1
0
Fork 0
mirror of https://github.com/dorny/test-reporter.git synced 2026-02-04 05:27:55 +01:00

feat: Add listTestCaseTime flag to print test times next to test names

- Add a new listTestCaseTime flag, that optionally prints test times
next to test names. This flag defaults to false, for backward
compatibility.
- Update get-report.ts to use this flag when generating a report.
- Update existing tests to set ReportOptions listTestCaseTime: true to
verify above feature.
- Update README with documentation about this new flag.

Note this feature was needed for individual test times under pytest,
since the xml is generated with all tests under one test suite.

https://github.com/dorny/test-reporter/issues/260
This commit is contained in:
Rick Shanor 2026-01-06 07:39:38 -08:00
parent a810f9bf83
commit fb2dd2ba55
5 changed files with 31 additions and 7 deletions

View file

@ -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'

View file

@ -11,9 +11,9 @@
### ❌ <a id="user-content-r0s0" href="#user-content-r0s0">__tests__\main.test.js</a>
```
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
```
### ❌ <a id="user-content-r0s1" href="#user-content-r0s1">__tests__\second.test.js</a>
```
❌ 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
```

View file

@ -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)
})

View file

@ -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,

View file

@ -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)