Skip to content

Commit 9afeb9c

Browse files
efegurkancpojer
authored andcommitted
Add forceCoverageMatch configuration option (#5081)
Add forceCoverageMatch config option to allow collecting coverage even if the file is ignored. This way you can collect coverage from the source files with tests or specific files you ignored manually.
1 parent cb98442 commit 9afeb9c

File tree

11 files changed

+205
-1
lines changed

11 files changed

+205
-1
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
## master
22

3-
None
3+
* `[jest-config]` Add `forceCoverageMatch` to allow collecting coverage from
4+
ignored files. ([#5081](https://github.com/facebook/jest/pull/5081))
45

56
## jest 22.0.0
67

docs/Configuration.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,41 @@ Jest will fail if:
237237
* The `./src/api/very-important-module.js` file has less than 100% coverage.
238238
* Every remaining file combined has less than 50% coverage (`global`).
239239

240+
### `forceCoverageMatch` [array<string>]
241+
242+
Default: `['']`
243+
244+
Test files are normally ignored from collecting code coverage. With this option,
245+
you can overwrite this behavior and include otherwise ignored files in code coverage.
246+
247+
For example, if you have tests in source files named with `.t.js` extension as
248+
following:
249+
250+
```javascript
251+
// sum.t.js
252+
253+
export function sum(a,b) {
254+
return a + b;
255+
}
256+
257+
if (process.env.NODE_ENV === 'test') {
258+
test('sum', () => {
259+
expect(sum(1, 2)).toBe(3);
260+
});
261+
}
262+
```
263+
264+
You can collect coverage from those files with setting `forceCoverageMatch`.
265+
```json
266+
{
267+
...
268+
"jest": {
269+
"forceCoverageMatch": ["**/*.t.js"]
270+
}
271+
}
272+
```
273+
274+
240275
### `globals` [object]
241276

242277
Default: `{}`

integration_tests/__tests__/__snapshots__/show_config.test.js.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ exports[`--showConfig outputs config info and exits 1`] = `
1313
\\"/node_modules/\\"
1414
],
1515
\\"detectLeaks\\": false,
16+
\\"forceCoverageMatch\\": [],
1617
\\"globals\\": {},
1718
\\"haste\\": {
1819
\\"providesModuleNodeModules\\": []

packages/jest-config/src/defaults.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export default ({
3838
coverageReporters: ['json', 'text', 'lcov', 'clover'],
3939
detectLeaks: false,
4040
expand: false,
41+
forceCoverageMatch: [],
4142
globalSetup: null,
4243
globalTeardown: null,
4344
globals: {},

packages/jest-config/src/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ const getConfigs = (
130130
cwd: options.cwd,
131131
detectLeaks: options.detectLeaks,
132132
displayName: options.displayName,
133+
forceCoverageMatch: options.forceCoverageMatch,
133134
globals: options.globals,
134135
haste: options.haste,
135136
moduleDirectories: options.moduleDirectories,

packages/jest-config/src/normalize.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,7 @@ export default function normalize(options: InitialOptions, argv: Argv) {
459459
case 'expand':
460460
case 'globals':
461461
case 'findRelatedTests':
462+
case 'forceCoverageMatch':
462463
case 'forceExit':
463464
case 'listTests':
464465
case 'logHeapUsage':

packages/jest-config/src/valid_config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export default ({
3737
},
3838
displayName: 'project-name',
3939
expand: false,
40+
forceCoverageMatch: ['**/*.t.js'],
4041
forceExit: false,
4142
globalSetup: 'setup.js',
4243
globalTeardown: 'teardown.js',
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
/**
2+
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
*/
8+
9+
import shouldInstrument from '../should_instrument';
10+
11+
describe('should_instrument', () => {
12+
const defaultFilename = 'source_file.test.js';
13+
const defaultOptions = {
14+
collectCoverage: true,
15+
};
16+
const defaultConfig = {
17+
rootDir: '/',
18+
};
19+
20+
describe('should return true', () => {
21+
const testShouldInstrument = (
22+
filename = defaultFilename,
23+
options = defaultOptions,
24+
config = defaultConfig,
25+
) => {
26+
const result = shouldInstrument(filename, options, config);
27+
expect(result).toBe(true);
28+
};
29+
30+
it('when testRegex provided and file is not a test file', () => {
31+
testShouldInstrument('source_file.js', defaultOptions, {
32+
testRegex: '.*\\.(test)\\.(js)$',
33+
});
34+
});
35+
36+
it('when testMatch is provided and file is not a test file', () => {
37+
testShouldInstrument('source_file.js', defaultOptions, {
38+
testMatch: ['**/?(*.)(test).js'],
39+
});
40+
});
41+
42+
it('should return true when file is in collectCoverageOnlyFrom when provided', () => {
43+
testShouldInstrument(
44+
'collect/only/from/here.js',
45+
46+
{
47+
collectCoverage: true,
48+
collectCoverageOnlyFrom: {'collect/only/from/here.js': true},
49+
},
50+
defaultConfig,
51+
);
52+
});
53+
54+
it('should return true when filename matches collectCoverageFrom', () => {
55+
testShouldInstrument(
56+
'do/collect/coverage.js',
57+
{
58+
collectCoverage: true,
59+
collectCoverageFrom: ['!**/dont/**/*.js', '**/do/**/*.js'],
60+
},
61+
defaultConfig,
62+
);
63+
});
64+
65+
it('should return true if the file is not in coveragePathIgnorePatterns', () => {
66+
testShouldInstrument('do/collect/coverage.js', defaultOptions, {
67+
coveragePathIgnorePatterns: ['dont'],
68+
rootDir: '/',
69+
});
70+
});
71+
72+
it('should return true if file is a testfile but forceCoverageMatch is set', () => {
73+
testShouldInstrument('do/collect/sum.coverage.test.js', defaultOptions, {
74+
forceCoverageMatch: ['**/*.(coverage).(test).js'],
75+
rootDir: '/',
76+
testRegex: '.*\\.(test)\\.(js)$',
77+
});
78+
});
79+
});
80+
81+
describe('should return false', () => {
82+
const testShouldInstrument = (
83+
filename = defaultFilename,
84+
options = defaultOptions,
85+
config = defaultConfig,
86+
) => {
87+
const result = shouldInstrument(filename, options, config);
88+
expect(result).toBe(false);
89+
};
90+
91+
it('if collectCoverage is falsy', () => {
92+
testShouldInstrument(
93+
'source_file.js',
94+
{
95+
collectCoverage: false,
96+
},
97+
defaultConfig,
98+
);
99+
});
100+
101+
it('when testRegex provided and filename is a test file', () => {
102+
testShouldInstrument(defaultFilename, defaultOptions, {
103+
testRegex: '.*\\.(test)\\.(js)$',
104+
});
105+
});
106+
107+
it('when testMatch is provided and file is a test file', () => {
108+
testShouldInstrument(defaultFilename, defaultOptions, {
109+
testMatch: ['**/?(*.)(test).js'],
110+
});
111+
});
112+
113+
it('when file is not in collectCoverageOnlyFrom when provided', () => {
114+
testShouldInstrument(
115+
'source_file.js',
116+
{
117+
collectCoverage: true,
118+
collectCoverageOnlyFrom: {'collect/only/from/here.js': true},
119+
},
120+
defaultConfig,
121+
);
122+
});
123+
124+
it('when filename does not match collectCoverageFrom', () => {
125+
testShouldInstrument(
126+
'dont/collect/coverage.js',
127+
{
128+
collectCoverage: true,
129+
collectCoverageFrom: ['!**/dont/**/*.js', '**/do/**/*.js'],
130+
},
131+
defaultConfig,
132+
);
133+
});
134+
135+
it('if the file is in coveragePathIgnorePatterns', () => {
136+
testShouldInstrument('dont/collect/coverage.js', defaultOptions, {
137+
coveragePathIgnorePatterns: ['dont'],
138+
rootDir: '/',
139+
});
140+
});
141+
142+
it('if file is in mock patterns', () => {
143+
const filename =
144+
process.platform === 'win32'
145+
? 'dont\\__mocks__\\collect\\coverage.js'
146+
: 'dont/__mocks__/collect/coverage.js';
147+
148+
testShouldInstrument(filename, defaultOptions, defaultConfig);
149+
});
150+
});
151+
});

packages/jest-runtime/src/should_instrument.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ export default function shouldInstrument(
2727
return false;
2828
}
2929

30+
if (
31+
config.forceCoverageMatch &&
32+
config.forceCoverageMatch.length &&
33+
micromatch.any(filename, config.forceCoverageMatch)
34+
) {
35+
return true;
36+
}
37+
3038
if (config.testRegex && filename.match(config.testRegex)) {
3139
return false;
3240
}

test_utils.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ const DEFAULT_PROJECT_CONFIG: ProjectConfig = {
7070
cwd: '/test_root_dir/',
7171
detectLeaks: false,
7272
displayName: undefined,
73+
forceCoverageMatch: [],
7374
globals: {},
7475
haste: {
7576
providesModuleNodeModules: [],

types/Config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export type DefaultOptions = {|
3131
coveragePathIgnorePatterns: Array<string>,
3232
coverageReporters: Array<string>,
3333
expand: boolean,
34+
forceCoverageMatch: Array<Glob>,
3435
globals: ConfigGlobals,
3536
globalSetup: ?string,
3637
globalTeardown: ?string,
@@ -86,6 +87,7 @@ export type InitialOptions = {
8687
displayName?: string,
8788
expand?: boolean,
8889
findRelatedTests?: boolean,
90+
forceCoverageMatch?: Array<Glob>,
8991
forceExit?: boolean,
9092
json?: boolean,
9193
globals?: ConfigGlobals,
@@ -212,6 +214,7 @@ export type ProjectConfig = {|
212214
cwd: Path,
213215
detectLeaks: boolean,
214216
displayName: ?string,
217+
forceCoverageMatch: Array<Glob>,
215218
globals: ConfigGlobals,
216219
haste: HasteConfig,
217220
moduleDirectories: Array<string>,

0 commit comments

Comments
 (0)