diff --git a/CHANGELOG.md b/CHANGELOG.md index 564e7585c84f..2e55677c750c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - `[jest-runtime]` Fix issue where user cannot utilize dynamic import despite specifying `--experimental-vm-modules` Node option ([#15842](https://github.com/jestjs/jest/pull/15842)) - `[jest-test-sequencer]` Fix issue where failed tests due to compilation errors not getting re-executed even with `--onlyFailures` CLI option ([#15851](https://github.com/jestjs/jest/pull/15851)) +- `[jest-reporters]` Fix issue where console output not displayed for GHA reporter even with `silent: false` option ([#15864](https://github.com/jestjs/jest/pull/15864)) ### Chore & Maintenance diff --git a/packages/jest-console/src/getConsoleOutput.ts b/packages/jest-console/src/getConsoleOutput.ts index 8e75b84ad28f..29a0f78b6de7 100644 --- a/packages/jest-console/src/getConsoleOutput.ts +++ b/packages/jest-console/src/getConsoleOutput.ts @@ -20,7 +20,7 @@ export default function getConsoleOutput( globalConfig: Config.GlobalConfig, ): string { const TITLE_INDENT = - globalConfig.verbose === true ? ' '.repeat(2) : ' '.repeat(4); + globalConfig?.verbose === true ? ' '.repeat(2) : ' '.repeat(4); const CONSOLE_INDENT = TITLE_INDENT + ' '.repeat(2); const logEntries = buffer.reduce((output, {type, message, origin}) => { diff --git a/packages/jest-reporters/src/GitHubActionsReporter.ts b/packages/jest-reporters/src/GitHubActionsReporter.ts index c25cb5c189b0..d47c4e37b986 100644 --- a/packages/jest-reporters/src/GitHubActionsReporter.ts +++ b/packages/jest-reporters/src/GitHubActionsReporter.ts @@ -7,6 +7,7 @@ import {stripVTControlCharacters as stripAnsi} from 'util'; import chalk from 'chalk'; +import {type ConsoleBuffer, getConsoleOutput} from '@jest/console'; import type { AggregatedResult, AssertionResult, @@ -66,12 +67,14 @@ type ResultTree = { export default class GitHubActionsReporter extends BaseReporter { static readonly filename = __filename; private readonly options: {silent: boolean}; + protected globalConfig: Config.GlobalConfig; constructor( _globalConfig: Config.GlobalConfig, reporterOptions: {silent?: boolean} = {}, ) { super(); + this.globalConfig = _globalConfig; this.options = { silent: typeof reporterOptions.silent === 'boolean' @@ -90,7 +93,7 @@ export default class GitHubActionsReporter extends BaseReporter { this.printFullResult(test.context, testResult); } if (this.isLastTestSuite(aggregatedResults)) { - this.printFailedTestLogs(test, aggregatedResults); + this.printFailedTestLogs(test, testResult.console, aggregatedResults); } } @@ -179,7 +182,7 @@ export default class GitHubActionsReporter extends BaseReporter { testDir, results.perfStats, ); - this.printResultTree(resultTree); + this.printResultTree(resultTree, context.config, results.console); } private arrayEqual(a1: Array, a2: Array): boolean { @@ -311,7 +314,11 @@ export default class GitHubActionsReporter extends BaseReporter { return node; } - private printResultTree(resultTree: ResultTree): void { + private printResultTree( + resultTree: ResultTree, + config: Config.ProjectConfig, + consoleLog?: ConsoleBuffer, + ): void { let perfMs; if (resultTree.performanceInfo.slow) { perfMs = ` (${chalk.red.inverse( @@ -324,6 +331,9 @@ export default class GitHubActionsReporter extends BaseReporter { this.startGroup( `${chalk.bold.green.inverse('PASS')} ${resultTree.name}${perfMs}`, ); + if (consoleLog && !this.options.silent) { + this.log(getConsoleOutput(consoleLog, config, this.globalConfig)); + } for (const child of resultTree.children) { this.recursivePrintResultTree(child, true, 1); } @@ -401,6 +411,7 @@ export default class GitHubActionsReporter extends BaseReporter { private printFailedTestLogs( context: Test, + consoleLog: ConsoleBuffer | undefined, testResults: AggregatedResult, ): boolean { const rootDir = context.context.config.rootDir; @@ -416,6 +427,15 @@ export default class GitHubActionsReporter extends BaseReporter { written = true; } this.startGroup(`Errors thrown in ${testDir}`); + if (consoleLog && !this.options.silent) { + this.log( + getConsoleOutput( + consoleLog, + context.context.config, + this.globalConfig, + ), + ); + } this.log(result.failureMessage); this.endGroup(); } diff --git a/packages/jest-reporters/src/__tests__/GitHubActionsReporter.test.ts b/packages/jest-reporters/src/__tests__/GitHubActionsReporter.test.ts index 3587ed8dfbed..5f960b81c7a5 100644 --- a/packages/jest-reporters/src/__tests__/GitHubActionsReporter.test.ts +++ b/packages/jest-reporters/src/__tests__/GitHubActionsReporter.test.ts @@ -687,5 +687,108 @@ describe('logs', () => { expect(mockedStderrWrite.mock.calls).toMatchSnapshot(); }); + + test('onTestResult last with console output for failed test', () => { + const mockTest = { + context: { + config: { + rootDir: '/testDir', + }, + }, + }; + const mockTestResult = { + console: [ + { + message: 'bar', + origin: + ' at Object.log (/tmp/jest-test/a.test.js:2:13)\n at Promise.finally.completed (/github.com/jestjs/jest/packages/jest-circus/build/jestAdapterInit.js:1557:28)', + type: 'log', + }, + ], + failureMessage: 'Failure message', + perfStats: { + runtime: 20, + slow: false, + }, + testFilePath: '/testDir/test1.js', + testResults: [ + { + ancestorTitles: [], + duration: 10, + status: 'passed', + title: 'test1', + }, + ], + }; + const mockResults = { + numFailedTestSuites: 1, + numPassedTestSuites: 2, + numTotalTestSuites: 3, + testResults: [mockTestResult], + }; + const gha = new GitHubActionsReporter({} as Config.GlobalConfig, { + silent: false, + }); + gha.generateAnnotations = jest.fn(); + + gha.onTestResult( + mockTest as Test, + mockTestResult as unknown as TestResult, + mockResults as unknown as AggregatedResult, + ); + + expect(mockedStderrWrite.mock.calls).toMatchSnapshot(); + }); + + test('onTestResult last with console output for success test', () => { + const mockTest = { + context: { + config: { + rootDir: '/testDir', + }, + }, + }; + const mockTestResult = { + console: [ + { + message: 'bar', + origin: + ' at Object.log (/tmp/jest-test/a.test.js:2:13)\n at Promise.finally.completed (/github.com/jestjs/jest/packages/jest-circus/build/jestAdapterInit.js:1557:28)', + type: 'log', + }, + ], + perfStats: { + runtime: 20, + slow: false, + }, + testFilePath: '/testDir/test1.js', + testResults: [ + { + ancestorTitles: [], + duration: 10, + status: 'passed', + title: 'test1', + }, + ], + }; + const mockResults = { + numFailedTestSuites: 0, + numPassedTestSuites: 1, + numTotalTestSuites: 1, + testResults: [mockTestResult], + }; + const gha = new GitHubActionsReporter({} as Config.GlobalConfig, { + silent: false, + }); + gha.generateAnnotations = jest.fn(); + + gha.onTestResult( + mockTest as Test, + mockTestResult as unknown as TestResult, + mockResults as unknown as AggregatedResult, + ); + + expect(mockedStderrWrite.mock.calls).toMatchSnapshot(); + }); }); }); diff --git a/packages/jest-reporters/src/__tests__/__snapshots__/GitHubActionsReporter.test.ts.snap b/packages/jest-reporters/src/__tests__/__snapshots__/GitHubActionsReporter.test.ts.snap index eb022c9657f8..c2a7c34ae10c 100644 --- a/packages/jest-reporters/src/__tests__/__snapshots__/GitHubActionsReporter.test.ts.snap +++ b/packages/jest-reporters/src/__tests__/__snapshots__/GitHubActionsReporter.test.ts.snap @@ -72,6 +72,80 @@ Array [ ] `; +exports[`logs Reporter interface onTestResult last with console output for failed test 1`] = ` +Array [ + Array [ + "::group::PASS test1.js (20 ms) +", + ], + Array [ + " console.log + bar + + at Object.log (../tmp/jest-test/a.test.js:2:13) + +", + ], + Array [ + " ✓ test1 (10 ms) +", + ], + Array [ + "::endgroup:: +", + ], + Array [ + " +", + ], + Array [ + "::group::Errors thrown in test1.js +", + ], + Array [ + " console.log + bar + + at Object.log (../tmp/jest-test/a.test.js:2:13) + +", + ], + Array [ + "Failure message +", + ], + Array [ + "::endgroup:: +", + ], +] +`; + +exports[`logs Reporter interface onTestResult last with console output for success test 1`] = ` +Array [ + Array [ + "::group::PASS test1.js (20 ms) +", + ], + Array [ + " console.log + bar + + at Object.log (../tmp/jest-test/a.test.js:2:13) + +", + ], + Array [ + " ✓ test1 (10 ms) +", + ], + Array [ + "::endgroup:: +", + ], +] +`; + exports[`logs Reporter interface onTestResult not last 1`] = ` Array [ Array [