diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b53b8c1..63dc117 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,11 +19,13 @@ jobs: node-version: 20 - run: npm ci - run: npm run lint - - run: npm run build - run: npm run test:ci env: GIST_TOKEN: ${{ secrets.GIST_TOKEN }} - - run: rm -rf test/data + - run: npm run build + - run: | + sed -i '0,/index.js/s//dist\/index.js/' action.yml package.json + rm -rf test/data - uses: ./ with: gist-id: ${{ env.GIST_ID }} diff --git a/README.md b/README.md index 4e4202b..feff0a9 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ Only matched report formats will get a file uploaded to the Gist. Write the verbose test output (`>` or `tee`) with coverage enabled to a single `test*.{out,txt}` file next to the `go.mod` file: -- `RUN`, `PASS` and `FAIL` flags will be used to count tests +- `RUN`, `PASS`, `FAIL` and `SKIP` flags will be used to count tests - The last percentage will be used as the coverage value `go tool cover -func=cover.out` output may be appended to the above file to make @@ -118,8 +118,8 @@ support this format too, natively or using an additional reporter: - **Deno**: `deno test --junit-path=report.xml` - **PHPUnit**: `phpunit --log-junit report.xml` -The number of tests and failures will be extracted from top-level `` -tags, from all matching and valid report files. +The number of tests (total, failed and skipped) will be extracted from +top-level `` tags, from all matching and valid report files. ➡️ `{repo}-[{ref}-]junit-tests.json` diff --git a/src/badges/coverage.js b/src/badges/coverage.js index bac782c..6e7b5ba 100644 --- a/src/badges/coverage.js +++ b/src/badges/coverage.js @@ -1,6 +1,6 @@ /** * Build a coverage badge. - * @param {*} data Badge data + * @param {import('../reports/index.js').CoverageReportData} data Coverage report data * @returns {import('./index.js').Badge} Badge content */ export function buildBadge(data) { diff --git a/src/badges/tests.js b/src/badges/tests.js index 4fe6a8a..5d60caf 100644 --- a/src/badges/tests.js +++ b/src/badges/tests.js @@ -1,14 +1,18 @@ /** * Build a tests badge. - * @param {*} data Badge data + * @param {import('../reports/index.js').TestReportData} data Test report data * @returns {import('./index.js').Badge} Badge content */ export function buildBadge(data) { const content = {}; content.message = `${data.passed} passed`; + content.color = data.passed > 0 ? 'brightgreen' : 'lightgrey'; if (data.failed > 0) { content.message += `, ${data.failed} failed`; + content.color = 'red'; + } + if (data.skipped > 0) { + content.message += `, ${data.skipped} skipped`; } - content.color = data.failed === 0 ? 'brightgreen' : 'red'; return content; } diff --git a/src/badges/tests.test.js b/src/badges/tests.test.js index 7ef6471..b0a98e1 100644 --- a/src/badges/tests.test.js +++ b/src/badges/tests.test.js @@ -4,11 +4,15 @@ import { buildBadge } from './tests.js'; describe('badges/tests', () => { describe('#buildBadge()', () => { const tests = [ - { data: { passed: 5, failed: 0 }, expected: { message: '5 passed', color: 'brightgreen' } }, - { data: { passed: 4, failed: 1 }, expected: { message: '4 passed, 1 failed', color: 'red' } } + { data: { passed: 0, failed: 0, skipped: 0 }, expected: { message: '0 passed', color: 'lightgrey' } }, + { data: { passed: 0, failed: 0, skipped: 1 }, expected: { message: '0 passed, 1 skipped', color: 'lightgrey' } }, + { data: { passed: 5, failed: 0, skipped: 0 }, expected: { message: '5 passed', color: 'brightgreen' } }, + { data: { passed: 4, failed: 0, skipped: 1 }, expected: { message: '4 passed, 1 skipped', color: 'brightgreen' } }, + { data: { passed: 4, failed: 1, skipped: 0 }, expected: { message: '4 passed, 1 failed', color: 'red' } }, + { data: { passed: 3, failed: 1, skipped: 1 }, expected: { message: '3 passed, 1 failed, 1 skipped', color: 'red' } } ]; for (const { data, expected } of tests) { - it(`should return a ${expected.color} "${expected.message}" badge for ${data.passed}/${data.failed} tests`, () => { + it(`should return a ${expected.color} "${expected.message}" badge for ${data.passed}/${data.failed}/${data.skipped} tests`, () => { const actual = buildBadge(data); assert.deepEqual(actual, expected); }); diff --git a/src/reports/go.js b/src/reports/go.js index c1dbfcc..174ca30 100644 --- a/src/reports/go.js +++ b/src/reports/go.js @@ -29,7 +29,8 @@ export async function getReports(root) { } const passed = (report.match(/--- PASS/g) || []).length; const failed = (report.match(/--- FAIL/g) || []).length; - badges.push({ type: 'tests', data: { passed, failed, tests } }); + const skipped = (report.match(/--- SKIP/g) || []).length; + badges.push({ type: 'tests', data: { tests, passed, failed, skipped } }); const percentages = report.match(/(?<=\s)[0-9.]+(?=%)/g); if (percentages && percentages.length >= 1) { const coverage = parseFloat(percentages.slice(-1)[0]); diff --git a/src/reports/go.test.js b/src/reports/go.test.js index c36047f..349903b 100644 --- a/src/reports/go.test.js +++ b/src/reports/go.test.js @@ -1,16 +1,29 @@ import assert from 'assert/strict'; +import { mkdir, writeFile, copyFile, rm } from 'fs/promises'; import { join } from 'path'; import { getReports } from './go.js'; describe('reports/go', () => { describe('#getReports()', () => { - it('should return tests and coverage reports', async () => { - const reports = await getReports(join(process.cwd(), 'test/data/go')); - assert.equal(reports.length, 2); - assert.deepEqual(reports, [ - { type: 'tests', data: { passed: 3, failed: 0, tests: 3 } }, - { type: 'coverage', data: { coverage: 96.5 } } - ]); + before(async () => { + await mkdir('test/data/go/project'); + await writeFile('test/data/go/project/go.mod', ''); + }); + const coverage = { type: 'coverage', data: { coverage: 96.5 } }; + const tests = [ + { report: 'test.out', expected: [{ type: 'tests', data: { tests: 3, passed: 3, failed: 0, skipped: 0 } }, coverage] }, + { report: 'failed-test.out', expected: [{ type: 'tests', data: { tests: 6, passed: 3, failed: 2, skipped: 1 } }, coverage] } + ]; + for (const { report, expected } of tests) { + it(`should return tests and coverage reports for file ${report}`, async () => { + await copyFile(join('test/data/go', report), 'test/data/go/project/test.out'); + const reports = await getReports(join(process.cwd(), 'test/data/go/project')); + assert.equal(reports.length, 2); + assert.deepEqual(reports, expected); + }); + } + after(async () => { + await rm('test/data/go/project', { recursive: true }); }); }); }); diff --git a/src/reports/index.js b/src/reports/index.js index 0cf2aee..625aed0 100644 --- a/src/reports/index.js +++ b/src/reports/index.js @@ -5,13 +5,16 @@ import * as cobertura from './cobertura.js'; import * as jacoco from './jacoco.js'; /** - * @typedef {{ type: string, format?: string, data: any }} Report A loaded report + * @typedef {{ passed: number, failed: number, skipped: number }} TestReportData Test report data + * @typedef {{ coverage: number }} CoverageReportData Coverage report data + * @typedef {TestReportData|CoverageReportData} ReportData Report data + * @typedef {{ type: string, format?: string, data: ReportData }} Report A loaded report * @typedef {(root: string) => Promise} ReportsLoader A reports loader */ /** * Available report loaders - * @type {{[key: string]: {getReports: ReportsLoader}}} + * @type {{ [key: string]: { getReports: ReportsLoader } }} */ const loaders = { go, junit, cobertura, jacoco }; diff --git a/src/reports/junit.js b/src/reports/junit.js index a69acab..f7f4286 100644 --- a/src/reports/junit.js +++ b/src/reports/junit.js @@ -17,7 +17,7 @@ export async function getReports(root) { join(root, '**/*junit*.xml') ]; const reports = await globNearest(patterns); - const data = { passed: 0, failed: 0, tests: 0 }; + const data = { tests: 0, passed: 0, failed: 0, skipped: 0 }; let count = 0; for (const r of reports) { core.info(`Load JUnit report '${r}'`); @@ -27,13 +27,14 @@ export async function getReports(root) { continue; // Invalid report file, trying the next one } for (const ts of testSuites) { + data.tests += parseInt(ts.match(/tests="([0-9]+)"/)?.[1] ?? '0'); data.failed += parseInt(ts.match(/failures="([0-9]+)"/)?.[1] ?? '0'); data.failed += parseInt(ts.match(/errors="([0-9]+)"/)?.[1] ?? '0'); - data.tests += parseInt(ts.match(/tests="([0-9]+)"/)?.[1] ?? '0'); + data.skipped += parseInt(ts.match(/skipped="([0-9]+)"/)?.[1] ?? '0'); } count++; } - data.passed = data.tests - data.failed; + data.passed = data.tests - (data.failed + data.skipped); core.info(`Loaded ${count} JUnit report(s)`); return [{ type: 'tests', data }]; } diff --git a/src/reports/junit.test.js b/src/reports/junit.test.js index ec52101..84a0836 100644 --- a/src/reports/junit.test.js +++ b/src/reports/junit.test.js @@ -8,7 +8,7 @@ describe('reports/junit', () => { const reports = await getReports(join(process.cwd(), 'test/data/junit')); assert.equal(reports.length, 1); assert.deepEqual(reports, [ - { type: 'tests', data: { passed: 8, failed: 4, tests: 12 } } + { type: 'tests', data: { tests: 12, passed: 7, failed: 4, skipped: 1 } } ]); }); }); diff --git a/test/data/go/failed-test.out b/test/data/go/failed-test.out new file mode 100644 index 0000000..2cf4271 --- /dev/null +++ b/test/data/go/failed-test.out @@ -0,0 +1,15 @@ +=== RUN Test +=== RUN Test/example/1 +=== RUN Test/example/2 +=== RUN Test/example/3 +=== RUN Test/example/4 +=== RUN Test/example/5 +--- FAIL: Test (0.01s) + --- PASS: Test/example/1 (0.00s) + --- PASS: Test/example/2 (0.01s) + --- SKIP: Test/example/3 (0.00s) + --- FAIL: Test/example/4 (0.01s) + --- PASS: Test/example/5 (0.01s) +FAIL +coverage: 96.5% of statements in ./... +ok github.com/example/test 0.111s coverage: 96.5% of statements in ./... diff --git a/test/data/junit/test-results-1.xml b/test/data/junit/test-results-1.xml index 061b702..992106f 100644 --- a/test/data/junit/test-results-1.xml +++ b/test/data/junit/test-results-1.xml @@ -1,19 +1,19 @@ - - + + - + - + - + diff --git a/test/data/junit/test-results-2.xml b/test/data/junit/test-results-2.xml index 0d98714..eb43853 100644 --- a/test/data/junit/test-results-2.xml +++ b/test/data/junit/test-results-2.xml @@ -1,7 +1,7 @@ - - - + + +