Skip to content

Commit 605e199

Browse files
MarcoScabbioloSimenB
authored andcommitted
Refactor -o & --coverage implementation | Fixes #6859 (#7611)
1 parent e67c818 commit 605e199

File tree

22 files changed

+220
-221
lines changed

22 files changed

+220
-221
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
### Fixes
66

7+
- `[jest-cli]` Refactor `-o` and `--coverage` combined ([#7611](https://github.com/facebook/jest/pull/7611))
8+
79
### Chore & Maintenance
810

911
- `[*]`: Setup building, linting and testing of TypeScript ([#7808](https://github.com/facebook/jest/pull/7808))

e2e/__tests__/onlyChanged.test.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,30 @@ test('report test coverage for only changed files', () => {
139139
expect(stdout).not.toMatch('b.js');
140140
});
141141

142+
test('do not pickup non-tested files when reporting coverage on only changed files', () => {
143+
writeFiles(DIR, {
144+
'a.js': 'module.exports = {}',
145+
'b.test.js': 'module.exports = {}',
146+
'package.json': JSON.stringify({name: 'original name'}),
147+
});
148+
149+
run(`${GIT} init`, DIR);
150+
run(`${GIT} add .`, DIR);
151+
run(`${GIT} commit --no-gpg-sign -m "first"`, DIR);
152+
153+
writeFiles(DIR, {
154+
'b.test.js': 'require("./package.json"); it("passes", () => {})',
155+
'package.json': JSON.stringify({name: 'new name'}),
156+
});
157+
158+
const {stderr, stdout} = runJest(DIR, ['-o', '--coverage']);
159+
160+
expect(stderr).toEqual(
161+
expect.not.stringContaining('Failed to collect coverage from'),
162+
);
163+
expect(stdout).toEqual(expect.not.stringContaining('package.json'));
164+
});
165+
142166
test('onlyChanged in config is overwritten by --all or testPathPattern', () => {
143167
writeFiles(DIR, {
144168
'.watchmanconfig': '',

packages/jest-cli/src/SearchSource.js

Lines changed: 65 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import type {Context} from 'types/Context';
1111
import type {Glob, GlobalConfig, Path} from 'types/Config';
1212
import type {Test} from 'types/TestRunner';
13-
import type {ChangedFilesPromise} from 'types/ChangedFiles';
13+
import type {ChangedFilesInfo} from 'types/ChangedFiles';
1414

1515
import path from 'path';
1616
import micromatch from 'micromatch';
@@ -24,7 +24,7 @@ import {replacePathSepForGlob} from 'jest-util';
2424
type SearchResult = {|
2525
noSCM?: boolean,
2626
stats?: {[key: string]: number},
27-
collectCoverageFrom?: Array<string>,
27+
collectCoverageFrom?: Set<string>,
2828
tests: Array<Test>,
2929
total?: number,
3030
|};
@@ -158,29 +158,55 @@ export default class SearchSource {
158158
buildSnapshotResolver(this._context.config),
159159
);
160160

161-
const tests = toTests(
162-
this._context,
163-
dependencyResolver.resolveInverse(
164-
allPaths,
165-
this.isTestFilePath.bind(this),
166-
{
167-
skipNodeResolution: this._context.config.skipNodeResolution,
168-
},
169-
),
170-
);
171-
let collectCoverageFrom;
172-
173-
// If we are collecting coverage, also return collectCoverageFrom patterns
174-
if (collectCoverage) {
175-
collectCoverageFrom = Array.from(allPaths).map(filename => {
176-
filename = replaceRootDirInPath(this._context.config.rootDir, filename);
177-
return path.isAbsolute(filename)
178-
? path.relative(this._context.config.rootDir, filename)
179-
: filename;
180-
});
161+
if (!collectCoverage) {
162+
return {
163+
tests: toTests(
164+
this._context,
165+
dependencyResolver.resolveInverse(
166+
allPaths,
167+
this.isTestFilePath.bind(this),
168+
{skipNodeResolution: this._context.config.skipNodeResolution},
169+
),
170+
),
171+
};
181172
}
182173

183-
return {collectCoverageFrom, tests};
174+
const testModulesMap = dependencyResolver.resolveInverseModuleMap(
175+
allPaths,
176+
this.isTestFilePath.bind(this),
177+
{skipNodeResolution: this._context.config.skipNodeResolution},
178+
);
179+
180+
const allPathsAbsolute = Array.from(allPaths).map(p => path.resolve(p));
181+
182+
const collectCoverageFrom = new Set();
183+
184+
testModulesMap.forEach(testModule => {
185+
if (!testModule.dependencies) {
186+
return;
187+
}
188+
189+
testModule.dependencies
190+
.filter(p => allPathsAbsolute.includes(p))
191+
.map(filename => {
192+
filename = replaceRootDirInPath(
193+
this._context.config.rootDir,
194+
filename,
195+
);
196+
return path.isAbsolute(filename)
197+
? path.relative(this._context.config.rootDir, filename)
198+
: filename;
199+
})
200+
.forEach(filename => collectCoverageFrom.add(filename));
201+
});
202+
203+
return {
204+
collectCoverageFrom,
205+
tests: toTests(
206+
this._context,
207+
testModulesMap.map(testModule => testModule.file),
208+
),
209+
};
184210
}
185211

186212
findTestsByPaths(paths: Array<Path>): SearchResult {
@@ -207,11 +233,11 @@ export default class SearchSource {
207233
return {tests: []};
208234
}
209235

210-
async findTestRelatedToChangedFiles(
211-
changedFilesPromise: ChangedFilesPromise,
236+
findTestRelatedToChangedFiles(
237+
changedFilesInfo: ChangedFilesInfo,
212238
collectCoverage: boolean,
213239
) {
214-
const {repos, changedFiles} = await changedFilesPromise;
240+
const {repos, changedFiles} = changedFilesInfo;
215241
// no SCM (git/hg/...) is found in any of the roots.
216242
const noSCM = Object.keys(repos).every(scm => repos[scm].size === 0);
217243
return noSCM
@@ -221,42 +247,38 @@ export default class SearchSource {
221247

222248
_getTestPaths(
223249
globalConfig: GlobalConfig,
224-
changedFilesPromise: ?ChangedFilesPromise,
225-
): Promise<SearchResult> {
250+
changedFiles: ?ChangedFilesInfo,
251+
): SearchResult {
226252
const paths = globalConfig.nonFlagArgs;
227253

228254
if (globalConfig.onlyChanged) {
229-
if (!changedFilesPromise) {
230-
throw new Error('This promise must be present when running with -o.');
255+
if (!changedFiles) {
256+
throw new Error('Changed files must be set when running with -o.');
231257
}
232258

233259
return this.findTestRelatedToChangedFiles(
234-
changedFilesPromise,
260+
changedFiles,
235261
globalConfig.collectCoverage,
236262
);
237263
} else if (globalConfig.runTestsByPath && paths && paths.length) {
238-
return Promise.resolve(this.findTestsByPaths(paths));
264+
return this.findTestsByPaths(paths);
239265
} else if (globalConfig.findRelatedTests && paths && paths.length) {
240-
return Promise.resolve(
241-
this.findRelatedTestsFromPattern(paths, globalConfig.collectCoverage),
266+
return this.findRelatedTestsFromPattern(
267+
paths,
268+
globalConfig.collectCoverage,
242269
);
243270
} else if (globalConfig.testPathPattern != null) {
244-
return Promise.resolve(
245-
this.findMatchingTests(globalConfig.testPathPattern),
246-
);
271+
return this.findMatchingTests(globalConfig.testPathPattern);
247272
} else {
248-
return Promise.resolve({tests: []});
273+
return {tests: []};
249274
}
250275
}
251276

252277
async getTestPaths(
253278
globalConfig: GlobalConfig,
254-
changedFilesPromise: ?ChangedFilesPromise,
279+
changedFiles: ?ChangedFilesInfo,
255280
): Promise<SearchResult> {
256-
const searchResult = await this._getTestPaths(
257-
globalConfig,
258-
changedFilesPromise,
259-
);
281+
const searchResult = this._getTestPaths(globalConfig, changedFiles);
260282

261283
const filterPath = globalConfig.filter;
262284

packages/jest-cli/src/TestScheduler.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*/
99

1010
import type {AggregatedResult, TestResult} from 'types/TestResult';
11-
import type {GlobalConfig, ReporterConfig} from 'types/Config';
11+
import type {GlobalConfig, ReporterConfig, Path} from 'types/Config';
1212
import type {Context} from 'types/Context';
1313
import type {Reporter, Test} from 'types/TestRunner';
1414

@@ -41,6 +41,7 @@ export type TestSchedulerOptions = {|
4141
export type TestSchedulerContext = {|
4242
firstRun: boolean,
4343
previousSuccess: boolean,
44+
changedFiles?: Set<Path>,
4445
|};
4546
export default class TestScheduler {
4647
_dispatcher: ReporterDispatcher;
@@ -173,6 +174,7 @@ export default class TestScheduler {
173174
// $FlowFixMe
174175
testRunners[config.runner] = new (require(config.runner): TestRunner)(
175176
this._globalConfig,
177+
{changedFiles: this._context && this._context.changedFiles},
176178
);
177179
}
178180
});
@@ -262,7 +264,11 @@ export default class TestScheduler {
262264
}
263265

264266
if (!isDefault && collectCoverage) {
265-
this.addReporter(new CoverageReporter(this._globalConfig));
267+
this.addReporter(
268+
new CoverageReporter(this._globalConfig, {
269+
changedFiles: this._context && this._context.changedFiles,
270+
}),
271+
);
266272
}
267273

268274
if (notify) {
@@ -288,7 +294,11 @@ export default class TestScheduler {
288294
);
289295

290296
if (collectCoverage) {
291-
this.addReporter(new CoverageReporter(this._globalConfig));
297+
this.addReporter(
298+
new CoverageReporter(this._globalConfig, {
299+
changedFiles: this._context && this._context.changedFiles,
300+
}),
301+
);
292302
}
293303

294304
this.addReporter(new SummaryReporter(this._globalConfig));

packages/jest-cli/src/__tests__/SearchSource.test.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,20 @@ describe('SearchSource', () => {
419419
rootPath,
420420
]);
421421
});
422+
423+
it('excludes untested files from coverage', () => {
424+
const unrelatedFile = path.join(rootDir, 'JSONFile.json');
425+
const regular = path.join(rootDir, 'RegularModule.js');
426+
const requireRegular = path.join(rootDir, 'RequireRegularMode.js');
427+
428+
const data = searchSource.findRelatedTests(
429+
new Set([regular, requireRegular, unrelatedFile]),
430+
true,
431+
);
432+
expect(Array.from(data.collectCoverageFrom)).toEqual([
433+
'RegularModule.js',
434+
]);
435+
});
422436
});
423437

424438
describe('findRelatedTestsFromPattern', () => {

packages/jest-cli/src/__tests__/runJestWithCoverage.test.js

Lines changed: 0 additions & 117 deletions
This file was deleted.

0 commit comments

Comments
 (0)