diff --git a/CHANGELOG.md b/CHANGELOG.md index 564e7585c84f..9208b8f6d70f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ ### Fixes - `[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-config]` Fix issue where user cannot toggle `collectCoverage` at project level ([#15588](https://github.com/jestjs/jest/issues/15588)) - `[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)) ### Chore & Maintenance diff --git a/e2e/__tests__/__snapshots__/coverageReportForMultiProjects.test.ts.snap b/e2e/__tests__/__snapshots__/coverageReportForMultiProjects.test.ts.snap new file mode 100644 index 000000000000..37c1f2f315b2 --- /dev/null +++ b/e2e/__tests__/__snapshots__/coverageReportForMultiProjects.test.ts.snap @@ -0,0 +1,13 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`exclude a project's code coverage if its collectCoverage is toggled off 1`] = ` +"-----------|---------|----------|---------|---------|------------------- +File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s +-----------|---------|----------|---------|---------|------------------- +All files | 100 | 100 | 100 | 100 | + package-1 | 100 | 100 | 100 | 100 | + index.js | 100 | 100 | 100 | 100 | + package-2 | 100 | 100 | 100 | 100 | + index.js | 100 | 100 | 100 | 100 | +-----------|---------|----------|---------|---------|-------------------" +`; diff --git a/e2e/__tests__/__snapshots__/showConfig.test.ts.snap b/e2e/__tests__/__snapshots__/showConfig.test.ts.snap index 6e3b84b759de..b86d7957163a 100644 --- a/e2e/__tests__/__snapshots__/showConfig.test.ts.snap +++ b/e2e/__tests__/__snapshots__/showConfig.test.ts.snap @@ -105,7 +105,6 @@ exports[`--showConfig outputs config info and exits 1`] = ` "bail": 0, "changedFilesWithAncestor": false, "ci": true, - "collectCoverage": false, "collectCoverageFrom": [], "coverageDirectory": "<>/coverage", "coverageProvider": "babel", diff --git a/e2e/__tests__/coverageReportForMultiProjects.test.ts b/e2e/__tests__/coverageReportForMultiProjects.test.ts new file mode 100644 index 000000000000..282e6e6485a3 --- /dev/null +++ b/e2e/__tests__/coverageReportForMultiProjects.test.ts @@ -0,0 +1,17 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import * as path from 'path'; +import runJest from '../runJest'; + +const DIR = path.resolve(__dirname, '../coverage-report-for-multi-projects'); + +test("exclude a project's code coverage if its collectCoverage is toggled off", () => { + const {stdout, exitCode} = runJest(DIR, ['--no-cache']); + expect(stdout).toMatchSnapshot(); + expect(exitCode).toBe(0); +}); diff --git a/e2e/coverage-report-for-multi-projects/jest.config.js b/e2e/coverage-report-for-multi-projects/jest.config.js new file mode 100644 index 000000000000..dade8ef68f77 --- /dev/null +++ b/e2e/coverage-report-for-multi-projects/jest.config.js @@ -0,0 +1,31 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +export default { + clearMocks: true, + collectCoverage: true, + collectCoverageFrom: ['./**/index.js', '!./__tests__/**/*.js'], + coverageProvider: 'v8', + projects: [ + { + displayName: 'Package 1', + rootDir: '/packages/package-1', + testMatch: ['/__tests__/**/*.e2e.js'], + }, + { + displayName: 'Package 2', + rootDir: '/packages/package-2', + testMatch: ['/__tests__/**/*.e2e.js'], + }, + { + collectCoverage: false, + displayName: 'Package 3', + rootDir: '/packages/package-3', + testMatch: ['/__tests__/**/*.e2e.js'], + }, + ], +}; diff --git a/e2e/coverage-report-for-multi-projects/package.json b/e2e/coverage-report-for-multi-projects/package.json new file mode 100644 index 000000000000..1befe01f8d0a --- /dev/null +++ b/e2e/coverage-report-for-multi-projects/package.json @@ -0,0 +1,6 @@ +{ + "type": "module", + "workspaces": [ + "packages/*" + ] +} diff --git a/e2e/coverage-report-for-multi-projects/packages/package-1/__tests__/example.e2e.js b/e2e/coverage-report-for-multi-projects/packages/package-1/__tests__/example.e2e.js new file mode 100644 index 000000000000..c343d29aa2ea --- /dev/null +++ b/e2e/coverage-report-for-multi-projects/packages/package-1/__tests__/example.e2e.js @@ -0,0 +1,15 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +'use strict'; + +const {package1} = require('../index.js'); + +describe('Example Package 1 Test', () => { + it('should run', () => { + expect(package1()).toBeTruthy(); + }); +}); diff --git a/e2e/coverage-report-for-multi-projects/packages/package-1/index.js b/e2e/coverage-report-for-multi-projects/packages/package-1/index.js new file mode 100644 index 000000000000..5d28ad35f6d6 --- /dev/null +++ b/e2e/coverage-report-for-multi-projects/packages/package-1/index.js @@ -0,0 +1,11 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +'use strict'; + +module.exports = { + package1: () => true, +}; diff --git a/e2e/coverage-report-for-multi-projects/packages/package-2/__tests__/example.e2e.js b/e2e/coverage-report-for-multi-projects/packages/package-2/__tests__/example.e2e.js new file mode 100644 index 000000000000..5e608e9b90ca --- /dev/null +++ b/e2e/coverage-report-for-multi-projects/packages/package-2/__tests__/example.e2e.js @@ -0,0 +1,15 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +'use strict'; + +const {package2} = require('../index'); + +describe('Example Package 2 Test', () => { + it('should run', () => { + expect(package2()).toBeTruthy(); + }); +}); diff --git a/e2e/coverage-report-for-multi-projects/packages/package-2/index.js b/e2e/coverage-report-for-multi-projects/packages/package-2/index.js new file mode 100644 index 000000000000..eb6a86c03e33 --- /dev/null +++ b/e2e/coverage-report-for-multi-projects/packages/package-2/index.js @@ -0,0 +1,11 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +'use strict'; + +module.exports = { + package2: () => true, +}; diff --git a/e2e/coverage-report-for-multi-projects/packages/package-3/__tests__/example.e2e.js b/e2e/coverage-report-for-multi-projects/packages/package-3/__tests__/example.e2e.js new file mode 100644 index 000000000000..593fbb3bfbcd --- /dev/null +++ b/e2e/coverage-report-for-multi-projects/packages/package-3/__tests__/example.e2e.js @@ -0,0 +1,13 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +'use strict'; + +describe('Example Package 3 Test', () => { + it('should run', () => { + expect(true).toBeTruthy(); + }); +}); diff --git a/e2e/coverage-report-for-multi-projects/packages/package-3/index.js b/e2e/coverage-report-for-multi-projects/packages/package-3/index.js new file mode 100644 index 000000000000..e371f36f4837 --- /dev/null +++ b/e2e/coverage-report-for-multi-projects/packages/package-3/index.js @@ -0,0 +1,11 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +'use strict'; + +module.exports = { + package3: () => true, +}; diff --git a/packages/jest-config/src/ValidConfig.ts b/packages/jest-config/src/ValidConfig.ts index f40c1c9247d1..ab91073adc61 100644 --- a/packages/jest-config/src/ValidConfig.ts +++ b/packages/jest-config/src/ValidConfig.ts @@ -208,6 +208,7 @@ export const initialProjectOptions: Config.InitialProjectOptions = { cache: true, cacheDirectory: '/tmp/user/jest', clearMocks: false, + collectCoverage: false, collectCoverageFrom: ['src', '!public'], coverageDirectory: 'coverage', coveragePathIgnorePatterns: [NODE_MODULES_REGEXP], diff --git a/packages/jest-config/src/index.ts b/packages/jest-config/src/index.ts index 2ee7078be474..bddc9ce07d33 100644 --- a/packages/jest-config/src/index.ts +++ b/packages/jest-config/src/index.ts @@ -197,6 +197,7 @@ const groupOptions = ( cache: options.cache, cacheDirectory: options.cacheDirectory, clearMocks: options.clearMocks, + collectCoverage: options.collectCoverage, collectCoverageFrom: options.collectCoverageFrom, coverageDirectory: options.coverageDirectory, coveragePathIgnorePatterns: options.coveragePathIgnorePatterns, diff --git a/packages/jest-config/src/normalize.ts b/packages/jest-config/src/normalize.ts index e2ed840cf020..656600e7d723 100644 --- a/packages/jest-config/src/normalize.ts +++ b/packages/jest-config/src/normalize.ts @@ -554,6 +554,9 @@ export default async function normalize( if (!options.coverageDirectory) { options.coverageDirectory = path.resolve(options.rootDir, 'coverage'); } + if (!Object.hasOwn(options, 'collectCoverage')) { + options.collectCoverage = undefined; + } setupBabelJest(options); // TODO: Type this properly diff --git a/packages/jest-transform/src/__tests__/ScriptTransformer.test.ts b/packages/jest-transform/src/__tests__/ScriptTransformer.test.ts index b1399872f51f..7671c76d2907 100644 --- a/packages/jest-transform/src/__tests__/ScriptTransformer.test.ts +++ b/packages/jest-transform/src/__tests__/ScriptTransformer.test.ts @@ -314,6 +314,7 @@ describe('ScriptTransformer', () => { config = makeProjectConfig({ cache: true, cacheDirectory: '/cache/', + collectCoverage: undefined, id: 'test', rootDir: '/', transformIgnorePatterns: ['/node_modules/'], diff --git a/packages/jest-transform/src/__tests__/__snapshots__/ScriptTransformer.test.ts.snap b/packages/jest-transform/src/__tests__/__snapshots__/ScriptTransformer.test.ts.snap index 17caaf4e17aa..bce5ae00e3a5 100644 --- a/packages/jest-transform/src/__tests__/__snapshots__/ScriptTransformer.test.ts.snap +++ b/packages/jest-transform/src/__tests__/__snapshots__/ScriptTransformer.test.ts.snap @@ -26,6 +26,7 @@ exports[`ScriptTransformer in async mode, passes expected transform options to g "cache": true, "cacheDirectory": "/cache/", "clearMocks": false, + "collectCoverage": undefined, "collectCoverageFrom": Array [ "src", "!public", @@ -177,6 +178,7 @@ exports[`ScriptTransformer passes expected transform options to getCacheKey 1`] "cache": true, "cacheDirectory": "/cache/", "clearMocks": false, + "collectCoverage": undefined, "collectCoverageFrom": Array [ "src", "!public", @@ -302,6 +304,7 @@ exports[`ScriptTransformer passes expected transform options to getCacheKeyAsync "cache": true, "cacheDirectory": "/cache/", "clearMocks": false, + "collectCoverage": undefined, "collectCoverageFrom": Array [ "src", "!public", diff --git a/packages/jest-transform/src/__tests__/shouldInstrument.test.ts b/packages/jest-transform/src/__tests__/shouldInstrument.test.ts index e48229f06a6f..c825a411816f 100644 --- a/packages/jest-transform/src/__tests__/shouldInstrument.test.ts +++ b/packages/jest-transform/src/__tests__/shouldInstrument.test.ts @@ -18,7 +18,10 @@ describe('shouldInstrument', () => { }), changedFiles: undefined, }; - const defaultConfig = makeProjectConfig({rootDir: '/'}); + const defaultConfig = makeProjectConfig({ + collectCoverage: undefined, + rootDir: '/', + }); describe('should return true', () => { const testShouldInstrument = ( filename = defaultFilename, diff --git a/packages/jest-transform/src/shouldInstrument.ts b/packages/jest-transform/src/shouldInstrument.ts index 511a7f5e1f3d..dc6fc22f9b73 100644 --- a/packages/jest-transform/src/shouldInstrument.ts +++ b/packages/jest-transform/src/shouldInstrument.ts @@ -36,7 +36,11 @@ export default function shouldInstrument( config: Config.ProjectConfig, loadedFilenames?: Array, ): boolean { - if (!options.collectCoverage) { + // Do not instrument when `collectCoverage` is toggled off global or project-wide + if ( + !options.collectCoverage || + (typeof config.collectCoverage === 'boolean' && !config.collectCoverage) + ) { return false; } diff --git a/packages/jest-types/src/Config.ts b/packages/jest-types/src/Config.ts index 1a0a9d0b64ff..976d5c2f0209 100644 --- a/packages/jest-types/src/Config.ts +++ b/packages/jest-types/src/Config.ts @@ -331,6 +331,7 @@ export type ProjectConfig = { cache: boolean; cacheDirectory: string; clearMocks: boolean; + collectCoverage?: boolean; collectCoverageFrom: Array; coverageDirectory: string; coveragePathIgnorePatterns: Array; diff --git a/packages/test-utils/src/config.ts b/packages/test-utils/src/config.ts index 3f5032e5c580..85a584e7a959 100644 --- a/packages/test-utils/src/config.ts +++ b/packages/test-utils/src/config.ts @@ -75,6 +75,7 @@ const DEFAULT_PROJECT_CONFIG: Config.ProjectConfig = { cache: false, cacheDirectory: '/test_cache_dir/', clearMocks: false, + collectCoverage: undefined, collectCoverageFrom: ['src', '!public'], coverageDirectory: 'coverage', coveragePathIgnorePatterns: [],