Skip to content

Commit

Permalink
fix(jest-runtime, @jest/transform): allow V8 coverage provider to col…
Browse files Browse the repository at this point in the history
…lect coverage from files which were not loaded explicitly (#13974)

Co-authored-by: GP4cK <gautier.bayzelon@gmail.com>
  • Loading branch information
mrazauskas and GP4cK committed Mar 4, 2023
1 parent 679b5ad commit 0060728
Show file tree
Hide file tree
Showing 9 changed files with 155 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -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))

Expand Down
9 changes: 9 additions & 0 deletions e2e/__tests__/__snapshots__/coverageProviderV8.test.ts.snap
Expand Up @@ -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
-------------|---------|----------|---------|---------|-------------------"
`;
12 changes: 12 additions & 0 deletions e2e/__tests__/coverageProviderV8.test.ts
Expand Up @@ -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();
});
42 changes: 42 additions & 0 deletions 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);
});
9 changes: 9 additions & 0 deletions e2e/vmscript-coverage/package.json
@@ -0,0 +1,9 @@
{
"jest": {
"rootDir": "./",
"testEnvironment": "node",
"collectCoverageFrom": [
"package/**/*.js"
]
}
}
27 changes: 27 additions & 0 deletions 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));
}
8 changes: 6 additions & 2 deletions packages/jest-runtime/src/index.ts
Expand Up @@ -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);
Expand Down
40 changes: 40 additions & 0 deletions packages/jest-transform/src/__tests__/shouldInstrument.test.ts
Expand Up @@ -24,11 +24,13 @@ describe('shouldInstrument', () => {
filename = defaultFilename,
options: Partial<Options>,
config: Partial<Config.ProjectConfig>,
loadedFilenames?: Array<string>,
) => {
const result = shouldInstrument(
filename,
{...defaultOptions, ...options},
{...defaultConfig, ...config},
loadedFilenames,
);
expect(result).toBe(true);
};
Expand Down Expand Up @@ -99,18 +101,38 @@ 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', () => {
const testShouldInstrument = (
filename = defaultFilename,
options: Partial<Options>,
config: Partial<Config.ProjectConfig>,
loadedFilenames?: Array<string>,
) => {
const result = shouldInstrument(
filename,
{...defaultOptions, ...options},
{...defaultConfig, ...config},
loadedFilenames,
);
expect(result).toBe(false);
};
Expand Down Expand Up @@ -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'],
);
});
});
});
9 changes: 9 additions & 0 deletions packages/jest-transform/src/shouldInstrument.ts
Expand Up @@ -34,6 +34,7 @@ export default function shouldInstrument(
filename: string,
options: ShouldInstrumentOptions,
config: Config.ProjectConfig,
loadedFilenames?: Array<string>,
): boolean {
if (!options.collectCoverage) {
return false;
Expand All @@ -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 &&
Expand Down

0 comments on commit 0060728

Please sign in to comment.