diff --git a/CHANGELOG.md b/CHANGELOG.md index 69bbea1761ea..f98b97eb773b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - `[jest-message-util]` Add support for [AggregateError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AggregateError) ([#13946](https://github.com/facebook/jest/pull/13946) & [#13947](https://github.com/facebook/jest/pull/13947)) - `[jest-message-util]` Add support for [Error causes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause) in `test` and `it` ([#13935](https://github.com/facebook/jest/pull/13935) & [#13966](https://github.com/facebook/jest/pull/13966)) - `[jest-reporters]` Add `summaryThreshold` option to summary reporter to allow overriding the internal threshold that is used to print the summary of all failed tests when the number of test suites surpasses it ([#13895](https://github.com/facebook/jest/pull/13895)) +- `[jest-runtime, @jest/transform]` Allow V8 coverage provider to collect coverage from files which were not loaded explicitly ([#13974](https://github.com/facebook/jest/pull/13974)) - `[jest-snapshot]` Add support to `cts` and `mts` TypeScript files to inline snapshots ([#13975](https://github.com/facebook/jest/pull/13975)) - `[jest-worker]` Add `start` method to worker farms ([#13937](https://github.com/facebook/jest/pull/13937)) diff --git a/e2e/__tests__/__snapshots__/coverageProviderV8.test.ts.snap b/e2e/__tests__/__snapshots__/coverageProviderV8.test.ts.snap index f24e97dce582..102d755384bb 100644 --- a/e2e/__tests__/__snapshots__/coverageProviderV8.test.ts.snap +++ b/e2e/__tests__/__snapshots__/coverageProviderV8.test.ts.snap @@ -105,3 +105,12 @@ All files | 59.37 | 33.33 | 33.33 | 59.37 | uncovered.js | 0 | 0 | 0 | 0 | 1-8 --------------|---------|----------|---------|---------|-------------------" `; + +exports[`vm script coverage generator 1`] = ` +"-------------|---------|----------|---------|---------|------------------- +File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s +-------------|---------|----------|---------|---------|------------------- +All files | 88.88 | 100 | 66.66 | 88.88 | + vmscript.js | 88.88 | 100 | 66.66 | 88.88 | 20-22 +-------------|---------|----------|---------|---------|-------------------" +`; diff --git a/e2e/__tests__/coverageProviderV8.test.ts b/e2e/__tests__/coverageProviderV8.test.ts index b282b5182f9e..2928bf91c6a4 100644 --- a/e2e/__tests__/coverageProviderV8.test.ts +++ b/e2e/__tests__/coverageProviderV8.test.ts @@ -106,3 +106,15 @@ test('prints correct coverage report, if a TS module is transpiled by custom tra expect(exitCode).toBe(0); expect(stdout).toMatchSnapshot(); }); + +test('vm script coverage generator', () => { + const dir = path.resolve(__dirname, '../vmscript-coverage'); + const {stdout, exitCode} = runJest( + dir, + ['--coverage', '--coverage-provider', 'v8'], + {stripAnsi: true}, + ); + + expect(exitCode).toBe(0); + expect(stdout).toMatchSnapshot(); +}); diff --git a/e2e/vmscript-coverage/__tests__/extract-coverage.test.js b/e2e/vmscript-coverage/__tests__/extract-coverage.test.js new file mode 100644 index 000000000000..29fad304fa07 --- /dev/null +++ b/e2e/vmscript-coverage/__tests__/extract-coverage.test.js @@ -0,0 +1,42 @@ +/** + * 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. + */ + +const fs = require('fs'); +const path = require('path'); +const vm = require('vm'); +const filePath = path.resolve(__dirname, '../package/vmscript.js'); + +test('extract coverage', () => { + const content = fs.readFileSync(filePath, {encoding: 'utf8'}); + + const case1 = vm.runInNewContext( + content, + { + inputObject: { + number: 0, + }, + }, + { + filename: filePath, + }, + ); + + const case2 = vm.runInNewContext( + content, + { + inputObject: { + number: 7, + }, + }, + { + filename: filePath, + }, + ); + + expect(case1).toBe(false); + expect(case2).toBe(true); +}); diff --git a/e2e/vmscript-coverage/package.json b/e2e/vmscript-coverage/package.json new file mode 100644 index 000000000000..4a3ea998ce9d --- /dev/null +++ b/e2e/vmscript-coverage/package.json @@ -0,0 +1,9 @@ +{ + "jest": { + "rootDir": "./", + "testEnvironment": "node", + "collectCoverageFrom": [ + "package/**/*.js" + ] + } +} diff --git a/e2e/vmscript-coverage/package/vmscript.js b/e2e/vmscript-coverage/package/vmscript.js new file mode 100644 index 000000000000..57b3370ff98d --- /dev/null +++ b/e2e/vmscript-coverage/package/vmscript.js @@ -0,0 +1,27 @@ +/** + * 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. + */ + +function addOne(inputNumber) { + return ++inputNumber; +} + +function isEven(inputNumber) { + if (inputNumber % 2 === 0) { + return true; + } else { + return false; + } +} + +function notCovered() { + return 'not covered'; +} + +/* global inputObject */ +if (inputObject.number / 1 === inputObject.number) { + isEven(addOne(inputObject.number)); +} diff --git a/packages/jest-runtime/src/index.ts b/packages/jest-runtime/src/index.ts index b638e2927577..910004ca1769 100644 --- a/packages/jest-runtime/src/index.ts +++ b/packages/jest-runtime/src/index.ts @@ -1267,8 +1267,12 @@ export default class Runtime { res => // TODO: will this work on windows? It might be better if `shouldInstrument` deals with it anyways res.url.startsWith(this._config.rootDir) && - this._v8CoverageSources!.has(res.url) && - shouldInstrument(res.url, this._coverageOptions, this._config), + shouldInstrument( + res.url, + this._coverageOptions, + this._config, + /* loadedFilenames */ Array.from(this._v8CoverageSources!.keys()), + ), ) .map(result => { const transformedFile = this._v8CoverageSources!.get(result.url); diff --git a/packages/jest-transform/src/__tests__/shouldInstrument.test.ts b/packages/jest-transform/src/__tests__/shouldInstrument.test.ts index c570fa053bd3..cb1e66a38a2f 100644 --- a/packages/jest-transform/src/__tests__/shouldInstrument.test.ts +++ b/packages/jest-transform/src/__tests__/shouldInstrument.test.ts @@ -24,11 +24,13 @@ describe('shouldInstrument', () => { filename = defaultFilename, options: Partial, config: Partial, + loadedFilenames?: Array, ) => { const result = shouldInstrument( filename, {...defaultOptions, ...options}, {...defaultConfig, ...config}, + loadedFilenames, ); expect(result).toBe(true); }; @@ -99,6 +101,24 @@ describe('shouldInstrument', () => { testRegex: ['.*\\.(test)\\.(js)$'], }); }); + + it('when file is in loadedFilenames list', () => { + testShouldInstrument( + 'do/collect/coverage.js', + defaultOptions, + defaultConfig, + ['do/collect/coverage.js'], + ); + }); + + it('when file is in not loadedFilenames list, but matches collectCoverageFrom', () => { + testShouldInstrument( + 'do/collect/coverage.js', + {collectCoverageFrom: ['!**/dont/**/*.js', '**/do/**/*.js']}, + defaultConfig, + ['dont/collect/coverage.js'], + ); + }); }); describe('should return false', () => { @@ -106,11 +126,13 @@ describe('shouldInstrument', () => { filename = defaultFilename, options: Partial, config: Partial, + loadedFilenames?: Array, ) => { const result = shouldInstrument( filename, {...defaultOptions, ...options}, {...defaultConfig, ...config}, + loadedFilenames, ); expect(result).toBe(false); }; @@ -205,5 +227,23 @@ describe('shouldInstrument', () => { setupFilesAfterEnv: ['setupTest.js'], }); }); + + it('when file is not in loadedFilenames list', () => { + testShouldInstrument( + 'dont/collect/coverage.js', + defaultOptions, + defaultConfig, + ['do/collect/coverage.js'], + ); + }); + + it('when file is in not loadedFilenames list and does not match collectCoverageFrom', () => { + testShouldInstrument( + 'dont/collect/coverage.js', + {collectCoverageFrom: ['!**/dont/**/*.js', '**/do/**/*.js']}, + defaultConfig, + ['do/collect/coverage.js'], + ); + }); }); }); diff --git a/packages/jest-transform/src/shouldInstrument.ts b/packages/jest-transform/src/shouldInstrument.ts index 0850d103b6ad..837a8417d0c5 100644 --- a/packages/jest-transform/src/shouldInstrument.ts +++ b/packages/jest-transform/src/shouldInstrument.ts @@ -34,6 +34,7 @@ export default function shouldInstrument( filename: string, options: ShouldInstrumentOptions, config: Config.ProjectConfig, + loadedFilenames?: Array, ): boolean { if (!options.collectCoverage) { return false; @@ -60,6 +61,14 @@ export default function shouldInstrument( } } + if ( + options.collectCoverageFrom.length === 0 && + loadedFilenames != null && + !loadedFilenames.includes(filename) + ) { + return false; + } + if ( // still cover if `only` is specified options.collectCoverageFrom.length &&