mirror of https://github.com/facebook/jest.git
fix(jest-runtime, @jest/transform): allow V8 coverage provider to collect coverage from files which were not loaded explicitly (#13974)
Co-authored-by: GP4cK <gautier.bayzelon@gmail.com>
This commit is contained in:
parent
679b5adc1f
commit
0060728fe5
|
@ -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 [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-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-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-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))
|
- `[jest-worker]` Add `start` method to worker farms ([#13937](https://github.com/facebook/jest/pull/13937))
|
||||||
|
|
||||||
|
|
|
@ -105,3 +105,12 @@ All files | 59.37 | 33.33 | 33.33 | 59.37 |
|
||||||
uncovered.js | 0 | 0 | 0 | 0 | 1-8
|
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
|
||||||
|
-------------|---------|----------|---------|---------|-------------------"
|
||||||
|
`;
|
||||||
|
|
|
@ -106,3 +106,15 @@ test('prints correct coverage report, if a TS module is transpiled by custom tra
|
||||||
expect(exitCode).toBe(0);
|
expect(exitCode).toBe(0);
|
||||||
expect(stdout).toMatchSnapshot();
|
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();
|
||||||
|
});
|
||||||
|
|
|
@ -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);
|
||||||
|
});
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"jest": {
|
||||||
|
"rootDir": "./",
|
||||||
|
"testEnvironment": "node",
|
||||||
|
"collectCoverageFrom": [
|
||||||
|
"package/**/*.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));
|
||||||
|
}
|
|
@ -1267,8 +1267,12 @@ export default class Runtime {
|
||||||
res =>
|
res =>
|
||||||
// TODO: will this work on windows? It might be better if `shouldInstrument` deals with it anyways
|
// TODO: will this work on windows? It might be better if `shouldInstrument` deals with it anyways
|
||||||
res.url.startsWith(this._config.rootDir) &&
|
res.url.startsWith(this._config.rootDir) &&
|
||||||
this._v8CoverageSources!.has(res.url) &&
|
shouldInstrument(
|
||||||
shouldInstrument(res.url, this._coverageOptions, this._config),
|
res.url,
|
||||||
|
this._coverageOptions,
|
||||||
|
this._config,
|
||||||
|
/* loadedFilenames */ Array.from(this._v8CoverageSources!.keys()),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.map(result => {
|
.map(result => {
|
||||||
const transformedFile = this._v8CoverageSources!.get(result.url);
|
const transformedFile = this._v8CoverageSources!.get(result.url);
|
||||||
|
|
|
@ -24,11 +24,13 @@ describe('shouldInstrument', () => {
|
||||||
filename = defaultFilename,
|
filename = defaultFilename,
|
||||||
options: Partial<Options>,
|
options: Partial<Options>,
|
||||||
config: Partial<Config.ProjectConfig>,
|
config: Partial<Config.ProjectConfig>,
|
||||||
|
loadedFilenames?: Array<string>,
|
||||||
) => {
|
) => {
|
||||||
const result = shouldInstrument(
|
const result = shouldInstrument(
|
||||||
filename,
|
filename,
|
||||||
{...defaultOptions, ...options},
|
{...defaultOptions, ...options},
|
||||||
{...defaultConfig, ...config},
|
{...defaultConfig, ...config},
|
||||||
|
loadedFilenames,
|
||||||
);
|
);
|
||||||
expect(result).toBe(true);
|
expect(result).toBe(true);
|
||||||
};
|
};
|
||||||
|
@ -99,6 +101,24 @@ describe('shouldInstrument', () => {
|
||||||
testRegex: ['.*\\.(test)\\.(js)$'],
|
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', () => {
|
describe('should return false', () => {
|
||||||
|
@ -106,11 +126,13 @@ describe('shouldInstrument', () => {
|
||||||
filename = defaultFilename,
|
filename = defaultFilename,
|
||||||
options: Partial<Options>,
|
options: Partial<Options>,
|
||||||
config: Partial<Config.ProjectConfig>,
|
config: Partial<Config.ProjectConfig>,
|
||||||
|
loadedFilenames?: Array<string>,
|
||||||
) => {
|
) => {
|
||||||
const result = shouldInstrument(
|
const result = shouldInstrument(
|
||||||
filename,
|
filename,
|
||||||
{...defaultOptions, ...options},
|
{...defaultOptions, ...options},
|
||||||
{...defaultConfig, ...config},
|
{...defaultConfig, ...config},
|
||||||
|
loadedFilenames,
|
||||||
);
|
);
|
||||||
expect(result).toBe(false);
|
expect(result).toBe(false);
|
||||||
};
|
};
|
||||||
|
@ -205,5 +227,23 @@ describe('shouldInstrument', () => {
|
||||||
setupFilesAfterEnv: ['setupTest.js'],
|
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'],
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -34,6 +34,7 @@ export default function shouldInstrument(
|
||||||
filename: string,
|
filename: string,
|
||||||
options: ShouldInstrumentOptions,
|
options: ShouldInstrumentOptions,
|
||||||
config: Config.ProjectConfig,
|
config: Config.ProjectConfig,
|
||||||
|
loadedFilenames?: Array<string>,
|
||||||
): boolean {
|
): boolean {
|
||||||
if (!options.collectCoverage) {
|
if (!options.collectCoverage) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -60,6 +61,14 @@ export default function shouldInstrument(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
options.collectCoverageFrom.length === 0 &&
|
||||||
|
loadedFilenames != null &&
|
||||||
|
!loadedFilenames.includes(filename)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
// still cover if `only` is specified
|
// still cover if `only` is specified
|
||||||
options.collectCoverageFrom.length &&
|
options.collectCoverageFrom.length &&
|
||||||
|
|
Loading…
Reference in New Issue