diff --git a/CHANGELOG.md b/CHANGELOG.md index a743b652ca1a..0f48c8855293 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,7 +37,7 @@ - `[jest-mock]` [**BREAKING**] Improve the usage of `jest.fn` generic type argument ([#12489](https://github.com/facebook/jest/pull/12489)) - `[jest-mock]` Add support for auto-mocking async generator functions ([#11080](https://github.com/facebook/jest/pull/11080)) - `[jest-mock]` Add `contexts` member to mock functions ([#12601](https://github.com/facebook/jest/pull/12601)) -- `[jest-reporters]` Add GitHub Actions reporter ([#11320](https://github.com/facebook/jest/pull/11320)) +- `[jest-reporters]` Add GitHub Actions reporter ([#11320](https://github.com/facebook/jest/pull/11320), [#12658](https://github.com/facebook/jest/pull/12658) - `[jest-resolve]` [**BREAKING**] Add support for `package.json` `exports` ([#11961](https://github.com/facebook/jest/pull/11961), [#12373](https://github.com/facebook/jest/pull/12373)) - `[jest-resolve, jest-runtime]` Add support for `data:` URI import and mock ([#12392](https://github.com/facebook/jest/pull/12392)) - `[jest-resolve, jest-runtime]` Add support for async resolver ([#11540](https://github.com/facebook/jest/pull/11540)) diff --git a/jest.config.ci.js b/jest.config.ci.js index 68e16b4300ac..953f52e08310 100644 --- a/jest.config.ci.js +++ b/jest.config.ci.js @@ -11,6 +11,7 @@ module.exports = { ...require('./jest.config'), coverageReporters: ['json'], reporters: [ + 'github-actions', [ 'jest-junit', {outputDirectory: 'reports/junit', outputName: 'js-test-results.xml'}, diff --git a/packages/jest-config/src/constants.ts b/packages/jest-config/src/constants.ts index 35e13c6f0a46..c24a77233c00 100644 --- a/packages/jest-config/src/constants.ts +++ b/packages/jest-config/src/constants.ts @@ -9,7 +9,6 @@ import * as path from 'path'; export const NODE_MODULES = `${path.sep}node_modules${path.sep}`; export const DEFAULT_JS_PATTERN = '\\.[jt]sx?$'; -export const DEFAULT_REPORTER_LABEL = 'default'; export const PACKAGE_JSON = 'package.json'; export const JEST_CONFIG_BASE_NAME = 'jest.config'; export const JEST_CONFIG_EXT_CJS = '.cjs'; diff --git a/packages/jest-config/src/normalize.ts b/packages/jest-config/src/normalize.ts index 7f22cb5e72e7..b7fd07b904c9 100644 --- a/packages/jest-config/src/normalize.ts +++ b/packages/jest-config/src/normalize.ts @@ -32,7 +32,7 @@ import DEPRECATED_CONFIG from './Deprecated'; import {validateReporters} from './ReporterValidationErrors'; import VALID_CONFIG from './ValidConfig'; import {getDisplayNameColor} from './color'; -import {DEFAULT_JS_PATTERN, DEFAULT_REPORTER_LABEL} from './constants'; +import {DEFAULT_JS_PATTERN} from './constants'; import getMaxWorkers from './getMaxWorkers'; import {parseShardPair} from './parseShardPair'; import setFromArgv from './setFromArgv'; @@ -433,7 +433,7 @@ const normalizeReporters = (options: Config.InitialOptionsWithRootDir) => { normalizedReporterConfig[0], ); - if (reporterPath !== DEFAULT_REPORTER_LABEL) { + if (!['default', 'github-actions'].includes(reporterPath)) { const reporter = Resolver.findNodeModule(reporterPath, { basedir: options.rootDir, }); diff --git a/packages/jest-core/package.json b/packages/jest-core/package.json index ccf923767447..e260ce01689d 100644 --- a/packages/jest-core/package.json +++ b/packages/jest-core/package.json @@ -20,6 +20,7 @@ "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", + "ci-info": "^3.2.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", "jest-changed-files": "^28.0.0-alpha.3", diff --git a/packages/jest-core/src/TestScheduler.ts b/packages/jest-core/src/TestScheduler.ts index 9cceb5fb1bdd..9eb4465a77ca 100644 --- a/packages/jest-core/src/TestScheduler.ts +++ b/packages/jest-core/src/TestScheduler.ts @@ -8,10 +8,12 @@ /* eslint-disable local/ban-types-eventually */ import chalk = require('chalk'); +import {GITHUB_ACTIONS} from 'ci-info'; import exit = require('exit'); import { CoverageReporter, DefaultReporter, + GitHubActionsReporter, NotifyReporter, Reporter, SummaryReporter, @@ -330,25 +332,40 @@ class TestScheduler { } } - private _shouldAddDefaultReporters( - reporters?: Array, - ): boolean { - return ( - !reporters || - !!reporters.find( - reporter => this._getReporterProps(reporter).path === 'default', - ) - ); - } - async _setupReporters() { const {collectCoverage, notify, reporters} = this._globalConfig; - const isDefault = this._shouldAddDefaultReporters(reporters); + + if (notify) { + this.addReporter( + new NotifyReporter( + this._globalConfig, + this._options.startRun, + this._context, + ), + ); + } + + if (!reporters) { + this._setupDefaultReporters(collectCoverage); + return; + } + + const reporterNames = reporters.map( + reporter => this._getReporterProps(reporter).path, + ); + + const isDefault = reporterNames?.includes('default'); + const isGitHubActions = + GITHUB_ACTIONS && reporterNames?.includes('github-actions'); if (isDefault) { this._setupDefaultReporters(collectCoverage); } + if (isGitHubActions) { + this.addReporter(new GitHubActionsReporter()); + } + if (!isDefault && collectCoverage) { this.addReporter( new CoverageReporter(this._globalConfig, { @@ -359,19 +376,7 @@ class TestScheduler { ); } - if (notify) { - this.addReporter( - new NotifyReporter( - this._globalConfig, - this._options.startRun, - this._context, - ), - ); - } - - if (reporters && Array.isArray(reporters)) { - await this._addCustomReporters(reporters); - } + await this._addCustomReporters(reporters); } private _setupDefaultReporters(collectCoverage: boolean) { @@ -400,7 +405,7 @@ class TestScheduler { for (const reporter of reporters) { const {options, path} = this._getReporterProps(reporter); - if (path === 'default') continue; + if (['default', 'github-actions'].includes(path)) continue; try { const Reporter = await requireOrImportModule(path, true); diff --git a/packages/jest-core/src/__tests__/TestScheduler.test.js b/packages/jest-core/src/__tests__/TestScheduler.test.js index 98b0d705ad7e..24dd450ee9a1 100644 --- a/packages/jest-core/src/__tests__/TestScheduler.test.js +++ b/packages/jest-core/src/__tests__/TestScheduler.test.js @@ -6,12 +6,15 @@ * */ -import {SummaryReporter} from '@jest/reporters'; +import {GitHubActionsReporter, SummaryReporter} from '@jest/reporters'; import {makeGlobalConfig, makeProjectConfig} from '@jest/test-utils'; import {createTestScheduler} from '../TestScheduler'; import * as testSchedulerHelper from '../testSchedulerHelper'; +jest.mock('ci-info', () => ({GITHUB_ACTIONS: true})); + jest.mock('@jest/reporters'); + const mockSerialRunner = { isSerial: true, runTests: jest.fn(), @@ -78,6 +81,35 @@ test('config for reporters supports `default`', async () => { expect(emptyReportersScheduler._dispatcher._reporters.length).toBe(0); }); +test('config for reporters supports `github-actions`', async () => { + await createTestScheduler( + makeGlobalConfig({ + reporters: [], + }), + {}, + {}, + ); + expect(GitHubActionsReporter).toHaveBeenCalledTimes(0); + + await createTestScheduler( + makeGlobalConfig({ + reporters: ['github-actions'], + }), + {}, + {}, + ); + expect(GitHubActionsReporter).toHaveBeenCalledTimes(1); + + await createTestScheduler( + makeGlobalConfig({ + reporters: ['default', 'github-actions'], + }), + {}, + {}, + ); + expect(GitHubActionsReporter).toHaveBeenCalledTimes(2); +}); + test('.addReporter() .removeReporter()', async () => { const scheduler = await createTestScheduler(makeGlobalConfig(), {}, {}); const reporter = new SummaryReporter(); diff --git a/packages/jest-reporters/src/GitHubActionsReporter.ts b/packages/jest-reporters/src/GitHubActionsReporter.ts index b9188e701b7b..454eeb93705b 100644 --- a/packages/jest-reporters/src/GitHubActionsReporter.ts +++ b/packages/jest-reporters/src/GitHubActionsReporter.ts @@ -23,6 +23,8 @@ function replaceEntities(s: string): string { } export default class GitHubActionsReporter extends BaseReporter { + static readonly filename = __filename; + override onRunComplete( _contexts?: Set, aggregatedResults?: AggregatedResult, @@ -48,7 +50,7 @@ function getMessages(results: Array | undefined) { .filter((m): m is RegExpExecArray => m !== null) .map( ([message, line, col]) => - `::error file=${testFilePath},line=${line},col=${col}::${message}`, + `\n::error file=${testFilePath},line=${line},col=${col}::${message}`, ), ); } diff --git a/packages/jest-reporters/src/__tests__/__snapshots__/GitHubActionsReporter.test.js.snap b/packages/jest-reporters/src/__tests__/__snapshots__/GitHubActionsReporter.test.js.snap index c523c4dd3448..0deced8ea4cf 100644 --- a/packages/jest-reporters/src/__tests__/__snapshots__/GitHubActionsReporter.test.js.snap +++ b/packages/jest-reporters/src/__tests__/__snapshots__/GitHubActionsReporter.test.js.snap @@ -1,6 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`reporter extracts the correct filename, line, and column 1`] = ` -"::error file=/home/runner/work/jest/jest/some.test.js,line=4,col=17::%0A Error: expect(received).toBe(expected) // Object.is equality%0A%0A %0A%0A Expected: "b"%0A%0A Received: "a"%0A%0A at Object. (/home/runner/work/jest/jest/some.test.js:4:17)%0A%0A at Object.asyncJestTest (/home/runner/work/jest/jest/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:106:37)%0A%0A at /home/runner/work/jest/jest/node_modules/jest-jasmine2/build/queueRunner.js:45:12%0A%0A at new Promise ()%0A%0A at mapper (/home/runner/work/jest/jest/node_modules/jest-jasmine2/build/queueRunner.js:28:19)%0A%0A at /home/runner/work/jest/jest/node_modules/jest-jasmine2/build/queueRunner.js:75:41%0A%0A at processTicksAndRejections (internal/process/task_queues.js:93:5)%0A +" +::error file=/home/runner/work/jest/jest/some.test.js,line=4,col=17::%0A Error: expect(received).toBe(expected) // Object.is equality%0A%0A %0A%0A Expected: "b"%0A%0A Received: "a"%0A%0A at Object. (/home/runner/work/jest/jest/some.test.js:4:17)%0A%0A at Object.asyncJestTest (/home/runner/work/jest/jest/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:106:37)%0A%0A at /home/runner/work/jest/jest/node_modules/jest-jasmine2/build/queueRunner.js:45:12%0A%0A at new Promise ()%0A%0A at mapper (/home/runner/work/jest/jest/node_modules/jest-jasmine2/build/queueRunner.js:28:19)%0A%0A at /home/runner/work/jest/jest/node_modules/jest-jasmine2/build/queueRunner.js:75:41%0A%0A at processTicksAndRejections (internal/process/task_queues.js:93:5)%0A " `; diff --git a/yarn.lock b/yarn.lock index a9276f7a5f4a..f1389152dc7e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2557,6 +2557,7 @@ __metadata: "@types/rimraf": ^3.0.0 ansi-escapes: ^4.2.1 chalk: ^4.0.0 + ci-info: ^3.2.0 exit: ^0.1.2 graceful-fs: ^4.2.9 jest-changed-files: ^28.0.0-alpha.3