Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add omit input, deprecate others #15

Merged
merged 5 commits into from
Apr 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
name: test

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

Expand All @@ -17,3 +15,14 @@ jobs:
node-version: 20
- run: npm ci
- run: npm test
- run: npm run build
- name: check dist
run: |
changed_files_count=$(git status --porcelain | wc -l)
if [ $changed_files_count -ne 0 ]; then
echo 'mismatched files from ncc generation! did you forget to run `npm run build`?' | tee -a $GITHUB_STEP_SUMMARY
echo '```diff' >> $GITHUB_STEP_SUMMARY
git diff >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
exit 1
fi
91 changes: 79 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,56 @@
# go-test-action

GitHub Action for running `go test ...` and getting rich summary and annotations as output.
- [go-test-action](#go-test-action)
- [Quick start](#quick-start)
- [Inputs](#inputs)
- [Screenshots](#screenshots)
- [Examples](#examples)
- [Basic](#basic)
- [Using existing test file](#using-existing-test-file)
- [Omitting elements](#omitting-elements)

GitHub Action for running `go test ./...` and getting rich summary and annotations as output.

Powered by [Job Summaries](https://github.blog/2022-05-09-supercharging-github-actions-with-job-summaries/), this Action will generate a convenient interactive viewer for tests based on Go's [test2json](https://pkg.go.dev/cmd/test2json) output. If there are any errors during `go test`, the Action will report back the same exit code, which will fail the job.

## Quick start

```yaml
- name: Test
uses: robherley/go-test-action@v0
```

## Inputs

| Input | Default | Description |
| - | - | - |
| moduleDirectory | `.` | relative path to the directory containing the `go.mod` of the module you wish to test |
| testArguments | `./...` | arguments to pass to `go test`, `-json` will be prepended automatically |
| fromJSONFile | null | parse an exisiting [test2json](https://pkg.go.dev/cmd/test2json) file, instead of executing go test |
| omitUntestedPackages | `false` | omit any go packages that don't have any tests from the summary output |
| omitSuccessfulPackages | `false` | omit any go packages that didn't contain failed tests |
| omitPie | `false` | omit the pie chart from the summary output
```yaml
- uses: robherley/go-test-action@v0
with:
# Relative path to the directory containing the go.mod of the module you wish to test.
# Optional. Default is '.'
moduleDirectory:

# Arguments to pass to go test, -json will be prepended automatically.
# Optional. Default is './...'
testArguments:

# Parse an exisiting [test2json](https://pkg.go.dev/cmd/test2json) file, instead of executing go test.
# Will always exit(0) on successful test file parse.
# Optional. No default
fromJSONFile:

# Whitespace separated list of renderable items to omit.
# Valid options to omit are:
# untested: packages that have no tests
# successful: packages that are successful
# pie: mermaid.js pie chart
# pkg-tests: per-package test list
# pkg-output: per-package test output
# stderr: standard error output of `go test` subprocess
# Optional. No default
omit:
```

## Demo
## Screenshots

Tests are organized per package, with a brief summary of individual test results:

Expand All @@ -25,7 +60,9 @@ Expand for per-test (with subtest) results and to view raw test output:

![summary expanded](docs/img/expanded.png)

## Example workflow
## Examples

### Basic

```yaml
name: Go
Expand All @@ -48,6 +85,36 @@ jobs:
run: go build -v ./...

- name: Test
uses: robherley/[email protected]
uses: robherley/go-test-action@v0
```

### Using existing test file

```yaml
- name: Test
uses: robherley/go-test-action@v0
with:
fromJSONFile: /path/to/test2json.json
```

### Omitting elements

See [Inputs](#inputs) above for valid options

```yaml
- name: Test
uses: robherley/go-test-action@v0
with:
omit: |
pie
stderr
```

or

```yaml
- name: Test
uses: robherley/go-test-action@v0
with:
omit: 'pie'
```
3 changes: 1 addition & 2 deletions __tests__/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ export const removeSummaryFile = async () => {
export const setupActionsInputs = () => {
process.env['INPUT_MODULEDIRECTORY'] = testModuleDirectory
process.env['INPUT_TESTARGUMENTS'] = testArguments
process.env['INPUT_OMITUNTESTEDPACKAGES'] = 'false'
process.env['INPUT_OMITPIE'] = 'false'
process.env['INPUT_OMIT'] = ''
}

export const createFakeGoModule = async () => {
Expand Down
83 changes: 83 additions & 0 deletions __tests__/inputs.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import * as core from '@actions/core'
import { OmitOption, getInputs } from '../src/inputs'

jest.mock('@actions/core')

const mockGetInput = core.getInput as jest.MockedFunction<typeof core.getInput>
const mockGetBooleanInput = core.getBooleanInput as jest.MockedFunction<
typeof core.getBooleanInput
>

const mockInput = (name: string, value: string) => {
mockGetInput.mockImplementation((n: string) => (n === name ? value : ''))
}

describe('renderer', () => {
beforeEach(() => {
jest.resetAllMocks()
})

it('uses default values', () => {
mockGetInput.mockReturnValue('')
const inputs = getInputs()

expect(inputs).toEqual({
moduleDirectory: '.',
testArguments: ['./...'],
fromJSONFile: null,
omit: new Set(),
})
})

it('parses moduleDirectory', () => {
mockInput('moduleDirectory', 'foo')
const inputs = getInputs()

expect(inputs.moduleDirectory).toEqual('foo')
})

it('parses testArguments', () => {
mockInput('testArguments', 'foo bar')
const inputs = getInputs()

expect(inputs.testArguments).toEqual(['foo', 'bar'])
})

it('parses fromJSONFile', () => {
mockInput('fromJSONFile', 'foo.json')
const inputs = getInputs()

expect(inputs.fromJSONFile).toEqual('foo.json')
})

it('parses omit', () => {
mockInput(
'omit',
[...Object.values(OmitOption), 'foo', 'bar', 'baz'].join('\n')
)
const inputs = getInputs()

expect(inputs.omit).toEqual(new Set(Object.values(OmitOption)))
})

it('supports deprecated inputs', () => {
mockGetInput.mockImplementation((name: string) => {
switch (name) {
case 'omitUntestedPackages':
case 'omitSuccessfulPackages':
case 'omitPie':
return 'true'
default:
return ''
}
})

mockGetBooleanInput.mockReturnValue(true)

const inputs = getInputs()
expect(inputs.omit).toEqual(
new Set([OmitOption.Untested, OmitOption.Successful, OmitOption.Pie])
)
expect(core.warning).toHaveBeenCalled()
})
})
60 changes: 47 additions & 13 deletions __tests__/renderer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
import { parseTestEvents } from '../src/events'
import Renderer from '../src/renderer'
import { SummaryTableCell } from '@actions/core/lib/summary'
import { OmitOption } from '../src/inputs'

const loadSummaryHTML = async (): Promise<cheerio.CheerioAPI> => {
const file = await fs.readFile(testSummaryFilePath, { encoding: 'utf8' })
Expand All @@ -26,9 +27,7 @@ const getRenderer = async (): Promise<Renderer> => {
'github.com/robherley/go-test-example',
testEvents,
'', // stderr
false, // omitUntestedPackages
false, // omitSuccessfulPackages
false // omitPie
new Set()
)
}

Expand Down Expand Up @@ -105,9 +104,7 @@ describe('renderer', () => {
'github.com/robherley/empty-module',
[],
'',
false,
false,
false
new Set()
)
await renderer.writeSummary()

Expand Down Expand Up @@ -169,9 +166,9 @@ describe('renderer', () => {
expect($.text()).toContain(pieData)
})

it('does not render pie when omitPie is true', async () => {
it('does not render pie when pie in omit', async () => {
const renderer = await getRenderer()
renderer.omitPie = true
renderer.omit.add(OmitOption.Pie)
await renderer.writeSummary()
const $ = await loadSummaryHTML()

Expand Down Expand Up @@ -201,22 +198,22 @@ describe('renderer', () => {
})
})

it('renders correct number of table rows when omitUntestedPackages is true', async () => {
it('renders correct number of table rows when untested is in omit', async () => {
const renderer = await getRenderer()
renderer.omitUntestedPackages = true
renderer.omit.add(OmitOption.Untested)
await renderer.writeSummary()
const $ = await loadSummaryHTML()

expect($('tr')).toHaveLength(7)
})

it('renders correct number of table rows when omitUntestedPackages is true', async () => {
it('renders correct number of table rows when successful is in omit', async () => {
const renderer = await getRenderer()
renderer.omitUntestedPackages = true
renderer.omit.add(OmitOption.Successful)
await renderer.writeSummary()
const $ = await loadSummaryHTML()

expect($('tr')).toHaveLength(7)
expect($('tr')).toHaveLength(5)
})

it('does not render stderr when empty', async () => {
Expand All @@ -237,4 +234,41 @@ describe('renderer', () => {
expect($('summary:contains(Standard Error Output)')).toHaveLength(1)
expect($('details:contains(hello world)')).toHaveLength(1)
})

it('does not render stderr when in omit', async () => {
const renderer = await getRenderer()
renderer.omit.add(OmitOption.Stderr)
renderer.stderr = 'i should not be rendered'
await renderer.writeSummary()
const $ = await loadSummaryHTML()

expect($('summary:contains(Standard Error Output)')).toHaveLength(0)
})

it('renders package test and output list', async () => {
const renderer = await getRenderer()
await renderer.writeSummary()
const $ = await loadSummaryHTML()

expect($('summary:contains(🧪 Tests)')).toHaveLength(4)
expect($('summary:contains(🖨️ Output)')).toHaveLength(4)
})

it('does not render package test list when in omit', async () => {
const renderer = await getRenderer()
renderer.omit.add(OmitOption.PackageTests)
await renderer.writeSummary()
const $ = await loadSummaryHTML()

expect($('summary:contains(🧪 Tests)')).toHaveLength(0)
})

it('does not render package output list when in omit', async () => {
const renderer = await getRenderer()
renderer.omit.add(OmitOption.PackageOutput)
await renderer.writeSummary()
const $ = await loadSummaryHTML()

expect($('summary:contains(🖨️ Output)')).toHaveLength(0)
})
})
26 changes: 0 additions & 26 deletions __tests__/runner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,32 +23,6 @@ describe('runner', () => {
setupActionsInputs()
})

it("sets defaults if inputs aren't set", async () => {
delete process.env['INPUT_MODULEDIRECTORY']
delete process.env['INPUT_TESTARGUMENTS']
delete process.env['INPUT_OMITUNTESTEDPACKAGES']
delete process.env['INPUT_OMITPIE']

const runner = new Runner()
expect(runner.moduleDirectory).toBe('.')
expect(runner.testArguments).toEqual(['./...'])
expect(runner.omitUntestedPackages).toEqual(false)
expect(runner.omitPie).toEqual(false)
})

it('uses inputs if they are set', async () => {
process.env['INPUT_MODULEDIRECTORY'] = '/some/random/directory'
process.env['INPUT_TESTARGUMENTS'] = '-foo -bar\t-baz'
process.env['INPUT_OMITUNTESTEDPACKAGES'] = 'true'
process.env['INPUT_OMITPIE'] = 'true'

const runner = new Runner()
expect(runner.moduleDirectory).toBe('/some/random/directory')
expect(runner.testArguments).toEqual(['-foo', '-bar', '-baz'])
expect(runner.omitUntestedPackages).toEqual(true)
expect(runner.omitPie).toEqual(true)
})

it('resolves module name from go.mod', async () => {
const runner = new Runner()
const modName = await runner.findModuleName()
Expand Down
Loading