diff --git a/README.md b/README.md index bdced5c..7439921 100644 --- a/README.md +++ b/README.md @@ -184,6 +184,10 @@ jobs: # none list-tests: 'all' + # Show execution time for individual test cases + # When enabled, test case execution times will be displayed in parentheses next to test names + list-test-case-time: 'false' + # Limits number of created annotations with error message and stack trace captured during test execution. # Must be less or equal to 50. max-annotations: '10' diff --git a/__tests__/__outputs__/jest-junit.md b/__tests__/__outputs__/jest-junit.md index 951256f..40b701c 100644 --- a/__tests__/__outputs__/jest-junit.md +++ b/__tests__/__outputs__/jest-junit.md @@ -11,9 +11,9 @@ ### ❌ __tests__\main.test.js ``` Test 1 - ✅ Passing test + ✅ Passing test (1ms) Test 1 › Test 1.1 - ❌ Failing test + ❌ Failing test (2ms) Error: expect(received).toBeTruthy() ❌ Exception in target unit Error: Some error @@ -23,7 +23,7 @@ Test 2 ``` ### ❌ __tests__\second.test.js ``` -❌ Timeout test +❌ Timeout test (4ms) : Timeout - Async callback was not invoked within the 1 ms timeout specified by jest.setTimeout.Timeout - Async callback was not invoked within the 1 ms timeout specified by jest.setTimeout.Error: ⚪ Skipped test ``` \ No newline at end of file diff --git a/__tests__/jest-junit.test.ts b/__tests__/jest-junit.test.ts index 912ebde..194856b 100644 --- a/__tests__/jest-junit.test.ts +++ b/__tests__/jest-junit.test.ts @@ -3,7 +3,7 @@ import * as path from 'path' import {JestJunitParser} from '../src/parsers/jest-junit/jest-junit-parser' import {ParseOptions} from '../src/test-parser' -import {DEFAULT_OPTIONS, getReport} from '../src/report/get-report' +import {DEFAULT_OPTIONS, getReport, ReportOptions} from '../src/report/get-report' import {normalizeFilePath} from '../src/utils/path-utils' describe('jest-junit tests', () => { @@ -55,7 +55,12 @@ describe('jest-junit tests', () => { const result = await parser.parse(filePath, fileContent) expect(result).toMatchSnapshot() - const report = getReport([result]) + const reportOpts: ReportOptions = { + ...DEFAULT_OPTIONS, + listTestCaseTime: true + } + + const report = getReport([result], reportOpts) fs.mkdirSync(path.dirname(outputPath), {recursive: true}) fs.writeFileSync(outputPath, report) }) diff --git a/src/main.ts b/src/main.ts index 9b24d38..842205b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -43,6 +43,7 @@ class TestReporter { readonly reporter = core.getInput('reporter', {required: true}) readonly listSuites = core.getInput('list-suites', {required: true}) as 'all' | 'failed' | 'none' readonly listTests = core.getInput('list-tests', {required: true}) as 'all' | 'failed' | 'none' + readonly listTestCaseTime = core.getInput('list-test-case-time', {required: false}) === 'true' readonly maxAnnotations = parseInt(core.getInput('max-annotations', {required: true})) readonly failOnError = core.getInput('fail-on-error', {required: true}) === 'true' readonly failOnEmpty = core.getInput('fail-on-empty', {required: true}) === 'true' @@ -174,7 +175,16 @@ class TestReporter { } } - const {listSuites, listTests, onlySummary, useActionsSummary, badgeTitle, reportTitle, collapsed} = this + const { + listSuites, + listTests, + listTestCaseTime, + onlySummary, + useActionsSummary, + badgeTitle, + reportTitle, + collapsed + } = this const passed = results.reduce((sum, tr) => sum + tr.passed, 0) const failed = results.reduce((sum, tr) => sum + tr.failed, 0) @@ -188,6 +198,7 @@ class TestReporter { { listSuites, listTests, + listTestCaseTime, baseUrl, onlySummary, useActionsSummary, @@ -219,6 +230,7 @@ class TestReporter { const summary = getReport(results, { listSuites, listTests, + listTestCaseTime, baseUrl, onlySummary, useActionsSummary, diff --git a/src/report/get-report.ts b/src/report/get-report.ts index 02b9d49..2827bd5 100644 --- a/src/report/get-report.ts +++ b/src/report/get-report.ts @@ -11,6 +11,7 @@ const MAX_ACTIONS_SUMMARY_LENGTH = 1048576 export interface ReportOptions { listSuites: 'all' | 'failed' | 'none' listTests: 'all' | 'failed' | 'none' + listTestCaseTime: boolean baseUrl: string onlySummary: boolean useActionsSummary: boolean @@ -22,6 +23,7 @@ export interface ReportOptions { export const DEFAULT_OPTIONS: ReportOptions = { listSuites: 'all', listTests: 'all', + listTestCaseTime: false, baseUrl: '', onlySummary: false, useActionsSummary: true, @@ -281,7 +283,8 @@ function getTestsReport(ts: TestSuiteResult, runIndex: number, suiteIndex: numbe continue } const result = getResultIcon(tc.result) - sections.push(`${space}${result} ${tc.name}`) + const time = options.listTestCaseTime && tc.time ? ` (${formatTime(tc.time)})` : '' + sections.push(`${space}${result} ${tc.name}${time}`) if (tc.error) { const lines = (tc.error.message ?? getFirstNonEmptyLine(tc.error.details)?.trim()) ?.split(/\r?\n/g)