From 18d7127bf9db0b9300f5d6651f0e4adea1a53877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=B3=E4=B9=99=E5=B1=B1?= Date: Sun, 5 Apr 2020 14:27:55 +0800 Subject: [PATCH 1/9] Add findRelatdSourcesFromTestsInChangedFiles in SearchSource --- packages/jest-core/src/SearchSource.ts | 34 ++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/packages/jest-core/src/SearchSource.ts b/packages/jest-core/src/SearchSource.ts index ba70f4ce021d..9efa210e6a7d 100644 --- a/packages/jest-core/src/SearchSource.ts +++ b/packages/jest-core/src/SearchSource.ts @@ -51,6 +51,15 @@ const toTests = (context: Context, tests: Array) => path, })); +const hasSCM = (changedFilesInfo: ChangedFiles) => { + const {repos} = changedFilesInfo; + // no SCM (git/hg/...) is found in any of the roots. + const noSCM = (Object.keys(repos) as Array< + keyof ChangedFiles['repos'] + >).every(scm => repos[scm].size === 0); + return !noSCM; +}; + export default class SearchSource { private _context: Context; private _testPathCases: TestPathCases = []; @@ -328,4 +337,29 @@ export default class SearchSource { return searchResult; } + + findRelatedSourcesFromTestsInChangedFiles( + changedFilesInfo: ChangedFiles, + ): Array { + if (!hasSCM(changedFilesInfo)) { + return []; + } + const {changedFiles} = changedFilesInfo; + const dependencyResolver = new DependencyResolver( + this._context.resolver, + this._context.hasteFS, + buildSnapshotResolver(this._context.config), + ); + const relatedSourcesSet = new Set(); + changedFiles.forEach(filePath => { + const isTestFile = this.isTestFilePath.bind(this)(filePath); + if (isTestFile) { + const sourcePaths = dependencyResolver.resolve(filePath, { + skipNodeResolution: this._context.config.skipNodeResolution, + }); + sourcePaths.forEach(sourcePath => relatedSourcesSet.add(sourcePath)); + } + }); + return Array.from(relatedSourcesSet); + } } From 6cf2150144addac9fa7cd20280a6f748e474ced0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=B3=E4=B9=99=E5=B1=B1?= Date: Sun, 5 Apr 2020 15:44:10 +0800 Subject: [PATCH 2/9] check sourcesRelatedToTestsInChangedFiles in shouldInstrument --- e2e/__tests__/onlyChanged.test.ts | 33 +++++++++++++++++++ packages/jest-core/src/TestScheduler.ts | 7 ++++ packages/jest-core/src/runJest.ts | 19 +++++++++-- .../src/__tests__/coverage_worker.test.js | 1 + .../jest-reporters/src/coverage_reporter.ts | 3 ++ .../jest-reporters/src/coverage_worker.ts | 3 ++ .../src/generateEmptyCoverage.ts | 2 ++ packages/jest-reporters/src/types.ts | 2 ++ packages/jest-runner/src/runTest.ts | 2 ++ packages/jest-runner/src/types.ts | 1 + packages/jest-runtime/src/index.ts | 1 + .../jest-transform/src/shouldInstrument.ts | 11 +++++-- packages/jest-transform/src/types.ts | 1 + 13 files changed, 81 insertions(+), 5 deletions(-) diff --git a/e2e/__tests__/onlyChanged.test.ts b/e2e/__tests__/onlyChanged.test.ts index 52abdd6d0613..2e160e4a4bb1 100644 --- a/e2e/__tests__/onlyChanged.test.ts +++ b/e2e/__tests__/onlyChanged.test.ts @@ -137,6 +137,39 @@ test('report test coverage for only changed files', () => { expect(stdout).not.toMatch('b.js'); }); +test('report test coverage of source on test file change under only changed files', () => { + writeFiles(DIR, { + '__tests__/a.test.js': ` + require('../a'); + test('a1', () => expect(1).toBe(1)); + `, + 'a.js': 'module.exports = {}', + 'package.json': JSON.stringify({ + jest: { + collectCoverage: true, + coverageReporters: ['text'], + testEnvironment: 'node', + }, + }), + }); + + run(`${GIT} init`, DIR); + run(`${GIT} add .`, DIR); + run(`${GIT} commit --no-gpg-sign -m "first"`, DIR); + + writeFiles(DIR, { + '__tests__/a.test.js': ` + require('../a'); + test('a1', () => expect(1).toBe(1)); + test('a2', () => expect(2).toBe(2)); + `, + }); + + const {stdout} = runJest(DIR, ['-o']); + + expect(stdout).toMatch('a.js'); +}); + test('do not pickup non-tested files when reporting coverage on only changed files', () => { writeFiles(DIR, { 'a.js': 'module.exports = {}', diff --git a/packages/jest-core/src/TestScheduler.ts b/packages/jest-core/src/TestScheduler.ts index 41b40e18955f..6b6f7810528f 100644 --- a/packages/jest-core/src/TestScheduler.ts +++ b/packages/jest-core/src/TestScheduler.ts @@ -44,6 +44,7 @@ export type TestSchedulerContext = { firstRun: boolean; previousSuccess: boolean; changedFiles?: Set; + sourcesRelatedToTestsInChangedFiles?: Set; }; export default class TestScheduler { private _dispatcher: ReporterDispatcher; @@ -181,6 +182,8 @@ export default class TestScheduler { const Runner: typeof TestRunner = require(config.runner); testRunners[config.runner] = new Runner(this._globalConfig, { changedFiles: this._context && this._context.changedFiles, + sourcesRelatedToTestsInChangedFiles: + this._context && this._context.sourcesRelatedToTestsInChangedFiles, }); } }); @@ -273,6 +276,8 @@ export default class TestScheduler { this.addReporter( new CoverageReporter(this._globalConfig, { changedFiles: this._context && this._context.changedFiles, + sourcesRelatedToTestsInChangedFiles: + this._context && this._context.sourcesRelatedToTestsInChangedFiles, }), ); } @@ -303,6 +308,8 @@ export default class TestScheduler { this.addReporter( new CoverageReporter(this._globalConfig, { changedFiles: this._context && this._context.changedFiles, + sourcesRelatedToTestsInChangedFiles: + this._context && this._context.sourcesRelatedToTestsInChangedFiles, }), ); } diff --git a/packages/jest-core/src/runJest.ts b/packages/jest-core/src/runJest.ts index 38bcb8dc95be..1f0ef43b002b 100644 --- a/packages/jest-core/src/runJest.ts +++ b/packages/jest-core/src/runJest.ts @@ -242,9 +242,22 @@ export default async function runJest({ } if (changedFilesPromise) { - testSchedulerContext.changedFiles = ( - await changedFilesPromise - ).changedFiles; + const changedFilesInfo = await changedFilesPromise; + testSchedulerContext.changedFiles = changedFilesInfo.changedFiles; + if (testSchedulerContext.changedFiles) { + const sourcesRelatedToTestsInChangedFilesArray = contexts + .map(context => { + const searchSource = new SearchSource(context); + const relatedSourceFromTestsInChangedFiles = searchSource.findRelatedSourcesFromTestsInChangedFiles( + changedFilesInfo, + ); + return relatedSourceFromTestsInChangedFiles; + }) + .reduce((total, paths) => [...total, ...paths], []); + testSchedulerContext.sourcesRelatedToTestsInChangedFiles = new Set( + sourcesRelatedToTestsInChangedFilesArray, + ); + } } const results = await new TestScheduler( diff --git a/packages/jest-reporters/src/__tests__/coverage_worker.test.js b/packages/jest-reporters/src/__tests__/coverage_worker.test.js index b3351ba29006..86cfeecb1ab3 100644 --- a/packages/jest-reporters/src/__tests__/coverage_worker.test.js +++ b/packages/jest-reporters/src/__tests__/coverage_worker.test.js @@ -41,6 +41,7 @@ test('resolves to the result of generateEmptyCoverage upon success', async () => globalConfig, config, undefined, + undefined, ); expect(result).toEqual(42); diff --git a/packages/jest-reporters/src/coverage_reporter.ts b/packages/jest-reporters/src/coverage_reporter.ts index b769743e2ff6..1e1cbfdbaab6 100644 --- a/packages/jest-reporters/src/coverage_reporter.ts +++ b/packages/jest-reporters/src/coverage_reporter.ts @@ -204,6 +204,9 @@ export default class CoverageReporter extends BaseReporter { changedFiles: this._options.changedFiles && Array.from(this._options.changedFiles), + sourcesRelatedToTestsInChangedFiles: + this._options.sourcesRelatedToTestsInChangedFiles && + Array.from(this._options.sourcesRelatedToTestsInChangedFiles), }, path: filename, }); diff --git a/packages/jest-reporters/src/coverage_worker.ts b/packages/jest-reporters/src/coverage_worker.ts index 23109ffa16ee..567a8b98064e 100644 --- a/packages/jest-reporters/src/coverage_worker.ts +++ b/packages/jest-reporters/src/coverage_worker.ts @@ -41,5 +41,8 @@ export function worker({ globalConfig, config, options && options.changedFiles && new Set(options.changedFiles), + options && + options.sourcesRelatedToTestsInChangedFiles && + new Set(options.sourcesRelatedToTestsInChangedFiles), ); } diff --git a/packages/jest-reporters/src/generateEmptyCoverage.ts b/packages/jest-reporters/src/generateEmptyCoverage.ts index 62ab4c023f2c..fae80dc5e049 100644 --- a/packages/jest-reporters/src/generateEmptyCoverage.ts +++ b/packages/jest-reporters/src/generateEmptyCoverage.ts @@ -31,6 +31,7 @@ export default function ( globalConfig: Config.GlobalConfig, config: Config.ProjectConfig, changedFiles?: Set, + sourcesRelatedToTestsInChangedFiles?: Set, ): CoverageWorkerResult | null { const coverageOptions = { changedFiles, @@ -38,6 +39,7 @@ export default function ( collectCoverageFrom: globalConfig.collectCoverageFrom, collectCoverageOnlyFrom: globalConfig.collectCoverageOnlyFrom, coverageProvider: globalConfig.coverageProvider, + sourcesRelatedToTestsInChangedFiles, }; let coverageWorkerResult: CoverageWorkerResult | null = null; if (shouldInstrument(filename, coverageOptions, config)) { diff --git a/packages/jest-reporters/src/types.ts b/packages/jest-reporters/src/types.ts index ddfde5782362..d2725ead5917 100644 --- a/packages/jest-reporters/src/types.ts +++ b/packages/jest-reporters/src/types.ts @@ -37,10 +37,12 @@ export type CoverageWorker = {worker: typeof worker}; export type CoverageReporterOptions = { changedFiles?: Set; + sourcesRelatedToTestsInChangedFiles?: Set; }; export type CoverageReporterSerializedOptions = { changedFiles?: Array; + sourcesRelatedToTestsInChangedFiles?: Array; }; export type OnTestStart = (test: Test) => Promise; diff --git a/packages/jest-runner/src/runTest.ts b/packages/jest-runner/src/runTest.ts index 36754d3f086e..7c957493db51 100644 --- a/packages/jest-runner/src/runTest.ts +++ b/packages/jest-runner/src/runTest.ts @@ -152,6 +152,8 @@ async function runTestInternal( collectCoverageFrom: globalConfig.collectCoverageFrom, collectCoverageOnlyFrom: globalConfig.collectCoverageOnlyFrom, coverageProvider: globalConfig.coverageProvider, + sourcesRelatedToTestsInChangedFiles: + context && context.sourcesRelatedToTestsInChangedFiles, }); const start = Date.now(); diff --git a/packages/jest-runner/src/types.ts b/packages/jest-runner/src/types.ts index c45b44d32677..4862c886ce86 100644 --- a/packages/jest-runner/src/types.ts +++ b/packages/jest-runner/src/types.ts @@ -51,6 +51,7 @@ export type TestRunnerOptions = { export type TestRunnerContext = { changedFiles?: Set; + sourcesRelatedToTestsInChangedFiles?: Set; }; export type TestRunnerSerializedContext = { diff --git a/packages/jest-runtime/src/index.ts b/packages/jest-runtime/src/index.ts index 33df2ba5dbe6..550f75b3eeca 100644 --- a/packages/jest-runtime/src/index.ts +++ b/packages/jest-runtime/src/index.ts @@ -171,6 +171,7 @@ class Runtime { collectCoverageFrom: [], collectCoverageOnlyFrom: undefined, coverageProvider: 'babel', + sourcesRelatedToTestsInChangedFiles: undefined, }; this._currentlyExecutingModulePath = ''; this._environment = environment; diff --git a/packages/jest-transform/src/shouldInstrument.ts b/packages/jest-transform/src/shouldInstrument.ts index e9d75afdbc63..7f6ef058f7ad 100644 --- a/packages/jest-transform/src/shouldInstrument.ts +++ b/packages/jest-transform/src/shouldInstrument.ts @@ -93,8 +93,15 @@ export default function shouldInstrument( return false; } - if (options.changedFiles && !options.changedFiles.has(filename)) { - return false; + if (options.changedFiles) { + if (!options.changedFiles.has(filename)) { + if (!options.sourcesRelatedToTestsInChangedFiles) { + return false; + } + if (!options.sourcesRelatedToTestsInChangedFiles.has(filename)) { + return false; + } + } } return true; diff --git a/packages/jest-transform/src/types.ts b/packages/jest-transform/src/types.ts index 30075298bc26..64e1145eb3c0 100644 --- a/packages/jest-transform/src/types.ts +++ b/packages/jest-transform/src/types.ts @@ -16,6 +16,7 @@ export type ShouldInstrumentOptions = Pick< | 'coverageProvider' > & { changedFiles?: Set; + sourcesRelatedToTestsInChangedFiles?: Set; }; export type Options = ShouldInstrumentOptions & From 1c8040040f3b93dae38042aaee0d88be054c7bae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=B3=E4=B9=99=E5=B1=B1?= Date: Sun, 5 Apr 2020 17:14:36 +0800 Subject: [PATCH 3/9] Add tests for findRelatedSourcesFromTestsInChangedFiles --- .../src/__tests__/SearchSource.test.ts | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/packages/jest-core/src/__tests__/SearchSource.test.ts b/packages/jest-core/src/__tests__/SearchSource.test.ts index 292e5e4b986a..9bf4c5344ec9 100644 --- a/packages/jest-core/src/__tests__/SearchSource.test.ts +++ b/packages/jest-core/src/__tests__/SearchSource.test.ts @@ -531,4 +531,77 @@ describe('SearchSource', () => { } }); }); + + describe('findRelatedSourcesFromTestsInChangedFiles', () => { + const rootDir = path.join( + __dirname, + '..', + '..', + '..', + 'jest-runtime', + 'src', + '__tests__', + 'test_root', + ); + + beforeEach(done => { + const {options: config} = normalize( + { + haste: { + hasteImplModulePath: path.join( + __dirname, + '..', + '..', + '..', + 'jest-haste-map', + 'src', + '__tests__', + 'haste_impl.js', + ), + providesModuleNodeModules: [], + }, + name: 'SearchSource-findRelatedSourcesFromTestsInChangedFiles-tests', + rootDir, + }, + {} as Config.Argv, + ); + Runtime.createContext(config, {maxWorkers, watchman: false}).then( + context => { + searchSource = new SearchSource(context); + done(); + }, + ); + }); + + it('return empty set if no SCM', () => { + const requireRegularModule = path.join( + rootDir, + 'RequireRegularModule.js', + ); + const sources = searchSource.findRelatedSourcesFromTestsInChangedFiles({ + changedFiles: new Set([requireRegularModule]), + repos: { + git: new Set(), + hg: new Set(), + }, + }); + expect(sources).toEqual([]); + }); + + it('return sources required by tests', () => { + const regularModule = path.join(rootDir, 'RegularModule.js'); + const requireRegularModule = path.join( + rootDir, + 'RequireRegularModule.js', + ); + const sources = searchSource.findRelatedSourcesFromTestsInChangedFiles({ + changedFiles: new Set([requireRegularModule]), + repos: { + git: new Set('/path/to/git'), + hg: new Set(), + }, + }); + expect(sources).toEqual([regularModule]); + }); + }); }); From e2665ea620779944bfa65a81e36646ebed4deffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=B3=E4=B9=99=E5=B1=B1?= Date: Sun, 5 Apr 2020 17:37:52 +0800 Subject: [PATCH 4/9] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f1165f46273..35120243efba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### Features - `[@jest/globals]` New package so Jest's globals can be explicitly imported ([#9801](https://github.com/facebook/jest/pull/9801)) +- `[jest-core]` Show coverage of sources related to tests in changed files ([#9769](https://github.com/facebook/jest/pull/9769)) - `[jest-runtime]` Populate `require.cache` ([#9841](https://github.com/facebook/jest/pull/9841)) ### Fixes From 4abe272eeb475aa66d6186f183581713b4801f79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=B3=E4=B9=99=E5=B1=B1?= Date: Sun, 5 Apr 2020 20:25:19 +0800 Subject: [PATCH 5/9] Address code review suggestion --- e2e/__tests__/onlyChanged.test.ts | 2 +- packages/jest-core/src/SearchSource.ts | 6 ++---- packages/jest-core/src/TestScheduler.ts | 18 ++++++++--------- .../src/__tests__/SearchSource.test.ts | 20 ++++--------------- packages/jest-core/src/runJest.ts | 6 +++--- .../jest-reporters/src/coverage_worker.ts | 5 ++--- packages/jest-runner/src/runTest.ts | 4 ++-- 7 files changed, 23 insertions(+), 38 deletions(-) diff --git a/e2e/__tests__/onlyChanged.test.ts b/e2e/__tests__/onlyChanged.test.ts index 2e160e4a4bb1..947a11d50ddc 100644 --- a/e2e/__tests__/onlyChanged.test.ts +++ b/e2e/__tests__/onlyChanged.test.ts @@ -165,7 +165,7 @@ test('report test coverage of source on test file change under only changed file `, }); - const {stdout} = runJest(DIR, ['-o']); + const {stdout} = runJest(DIR, ['--only-changed']); expect(stdout).toMatch('a.js'); }); diff --git a/packages/jest-core/src/SearchSource.ts b/packages/jest-core/src/SearchSource.ts index 9efa210e6a7d..194664594c16 100644 --- a/packages/jest-core/src/SearchSource.ts +++ b/packages/jest-core/src/SearchSource.ts @@ -54,9 +54,7 @@ const toTests = (context: Context, tests: Array) => const hasSCM = (changedFilesInfo: ChangedFiles) => { const {repos} = changedFilesInfo; // no SCM (git/hg/...) is found in any of the roots. - const noSCM = (Object.keys(repos) as Array< - keyof ChangedFiles['repos'] - >).every(scm => repos[scm].size === 0); + const noSCM = Object.values(repos).every(scm => scm.size === 0); return !noSCM; }; @@ -352,7 +350,7 @@ export default class SearchSource { ); const relatedSourcesSet = new Set(); changedFiles.forEach(filePath => { - const isTestFile = this.isTestFilePath.bind(this)(filePath); + const isTestFile = this.isTestFilePath(filePath); if (isTestFile) { const sourcePaths = dependencyResolver.resolve(filePath, { skipNodeResolution: this._context.config.skipNodeResolution, diff --git a/packages/jest-core/src/TestScheduler.ts b/packages/jest-core/src/TestScheduler.ts index 6b6f7810528f..bf455a2e05c1 100644 --- a/packages/jest-core/src/TestScheduler.ts +++ b/packages/jest-core/src/TestScheduler.ts @@ -181,9 +181,9 @@ export default class TestScheduler { if (!testRunners[config.runner]) { const Runner: typeof TestRunner = require(config.runner); testRunners[config.runner] = new Runner(this._globalConfig, { - changedFiles: this._context && this._context.changedFiles, - sourcesRelatedToTestsInChangedFiles: - this._context && this._context.sourcesRelatedToTestsInChangedFiles, + changedFiles: this._context?.changedFiles, + sourcesRelatedToTestsInChangedFiles: this._context + ?.sourcesRelatedToTestsInChangedFiles, }); } }); @@ -275,9 +275,9 @@ export default class TestScheduler { if (!isDefault && collectCoverage) { this.addReporter( new CoverageReporter(this._globalConfig, { - changedFiles: this._context && this._context.changedFiles, - sourcesRelatedToTestsInChangedFiles: - this._context && this._context.sourcesRelatedToTestsInChangedFiles, + changedFiles: this._context?.changedFiles, + sourcesRelatedToTestsInChangedFiles: this._context + ?.sourcesRelatedToTestsInChangedFiles, }), ); } @@ -307,9 +307,9 @@ export default class TestScheduler { if (collectCoverage) { this.addReporter( new CoverageReporter(this._globalConfig, { - changedFiles: this._context && this._context.changedFiles, - sourcesRelatedToTestsInChangedFiles: - this._context && this._context.sourcesRelatedToTestsInChangedFiles, + changedFiles: this._context?.changedFiles, + sourcesRelatedToTestsInChangedFiles: this._context + ?.sourcesRelatedToTestsInChangedFiles, }), ); } diff --git a/packages/jest-core/src/__tests__/SearchSource.test.ts b/packages/jest-core/src/__tests__/SearchSource.test.ts index 9bf4c5344ec9..307e2c2f68b0 100644 --- a/packages/jest-core/src/__tests__/SearchSource.test.ts +++ b/packages/jest-core/src/__tests__/SearchSource.test.ts @@ -533,30 +533,18 @@ describe('SearchSource', () => { }); describe('findRelatedSourcesFromTestsInChangedFiles', () => { - const rootDir = path.join( + const rootDir = path.resolve( __dirname, - '..', - '..', - '..', - 'jest-runtime', - 'src', - '__tests__', - 'test_root', + '../../../jest-runtime/src/__tests__/test_root', ); beforeEach(done => { const {options: config} = normalize( { haste: { - hasteImplModulePath: path.join( + hasteImplModulePath: path.resolve( __dirname, - '..', - '..', - '..', - 'jest-haste-map', - 'src', - '__tests__', - 'haste_impl.js', + '../../../jest-haste-map/src/__tests__/haste_impl.js', ), providesModuleNodeModules: [], }, diff --git a/packages/jest-core/src/runJest.ts b/packages/jest-core/src/runJest.ts index 1f0ef43b002b..787762903f8e 100644 --- a/packages/jest-core/src/runJest.ts +++ b/packages/jest-core/src/runJest.ts @@ -243,8 +243,8 @@ export default async function runJest({ if (changedFilesPromise) { const changedFilesInfo = await changedFilesPromise; - testSchedulerContext.changedFiles = changedFilesInfo.changedFiles; - if (testSchedulerContext.changedFiles) { + if (changedFilesInfo.changedFiles) { + testSchedulerContext.changedFiles = changedFilesInfo.changedFiles; const sourcesRelatedToTestsInChangedFilesArray = contexts .map(context => { const searchSource = new SearchSource(context); @@ -253,7 +253,7 @@ export default async function runJest({ ); return relatedSourceFromTestsInChangedFiles; }) - .reduce((total, paths) => [...total, ...paths], []); + .reduce((total, paths) => total.concat(paths), []); testSchedulerContext.sourcesRelatedToTestsInChangedFiles = new Set( sourcesRelatedToTestsInChangedFilesArray, ); diff --git a/packages/jest-reporters/src/coverage_worker.ts b/packages/jest-reporters/src/coverage_worker.ts index 567a8b98064e..d1894b97574c 100644 --- a/packages/jest-reporters/src/coverage_worker.ts +++ b/packages/jest-reporters/src/coverage_worker.ts @@ -40,9 +40,8 @@ export function worker({ path, globalConfig, config, - options && options.changedFiles && new Set(options.changedFiles), - options && - options.sourcesRelatedToTestsInChangedFiles && + options?.changedFiles && new Set(options.changedFiles), + options?.sourcesRelatedToTestsInChangedFiles && new Set(options.sourcesRelatedToTestsInChangedFiles), ); } diff --git a/packages/jest-runner/src/runTest.ts b/packages/jest-runner/src/runTest.ts index 7c957493db51..d9a64a874155 100644 --- a/packages/jest-runner/src/runTest.ts +++ b/packages/jest-runner/src/runTest.ts @@ -147,13 +147,13 @@ async function runTestInternal( setGlobal(environment.global, 'console', testConsole); const runtime = new Runtime(config, environment, resolver, cacheFS, { - changedFiles: context && context.changedFiles, + changedFiles: context?.changedFiles, collectCoverage: globalConfig.collectCoverage, collectCoverageFrom: globalConfig.collectCoverageFrom, collectCoverageOnlyFrom: globalConfig.collectCoverageOnlyFrom, coverageProvider: globalConfig.coverageProvider, sourcesRelatedToTestsInChangedFiles: - context && context.sourcesRelatedToTestsInChangedFiles, + context?.sourcesRelatedToTestsInChangedFiles, }); const start = Date.now(); From e724874eaa245243b17a02862db5febf1fd17f42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=B3=E4=B9=99=E5=B1=B1?= Date: Sun, 5 Apr 2020 20:34:09 +0800 Subject: [PATCH 6/9] Use hasSCM utility in SearchSource.findTestRelatedToChangeFiles --- packages/jest-core/src/SearchSource.ts | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/jest-core/src/SearchSource.ts b/packages/jest-core/src/SearchSource.ts index 194664594c16..27b05889f675 100644 --- a/packages/jest-core/src/SearchSource.ts +++ b/packages/jest-core/src/SearchSource.ts @@ -247,14 +247,11 @@ export default class SearchSource { changedFilesInfo: ChangedFiles, collectCoverage: boolean, ): SearchResult { - const {repos, changedFiles} = changedFilesInfo; - // no SCM (git/hg/...) is found in any of the roots. - const noSCM = (Object.keys(repos) as Array< - keyof ChangedFiles['repos'] - >).every(scm => repos[scm].size === 0); - return noSCM - ? {noSCM: true, tests: []} - : this.findRelatedTests(changedFiles, collectCoverage); + if (!hasSCM(changedFilesInfo)) { + return {noSCM: true, tests: []}; + } + const {changedFiles} = changedFilesInfo; + return this.findRelatedTests(changedFiles, collectCoverage); } private _getTestPaths( From 73271f0bd24384525cc4026b9140f6cd00dfeb93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=B3=E4=B9=99=E5=B1=B1?= Date: Sun, 26 Apr 2020 15:20:20 +0800 Subject: [PATCH 7/9] Create searchSources at first for reuse in runJest --- packages/jest-core/src/runJest.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/jest-core/src/runJest.ts b/packages/jest-core/src/runJest.ts index 787762903f8e..bea930899c0d 100644 --- a/packages/jest-core/src/runJest.ts +++ b/packages/jest-core/src/runJest.ts @@ -34,13 +34,12 @@ import type {Filter, TestRunData} from './types'; const getTestPaths = async ( globalConfig: Config.GlobalConfig, - context: Context, + source: SearchSource, outputStream: NodeJS.WriteStream, changedFiles: ChangedFiles | undefined, jestHooks: JestHookEmitter, filter?: Filter, ) => { - const source = new SearchSource(context); const data = await source.getTestPaths(globalConfig, changedFiles, filter); if (!data.tests.length && globalConfig.onlyChanged && data.noSCM) { @@ -167,11 +166,14 @@ export default async function runJest({ } } + const searchSources = contexts.map(context => new SearchSource(context)); + const testRunData: TestRunData = await Promise.all( - contexts.map(async context => { + contexts.map(async (context, index) => { + const searchSource = searchSources[index]; const matches = await getTestPaths( globalConfig, - context, + searchSource, outputStream, changedFilesPromise && (await changedFilesPromise), jestHooks, @@ -246,8 +248,8 @@ export default async function runJest({ if (changedFilesInfo.changedFiles) { testSchedulerContext.changedFiles = changedFilesInfo.changedFiles; const sourcesRelatedToTestsInChangedFilesArray = contexts - .map(context => { - const searchSource = new SearchSource(context); + .map((_, index) => { + const searchSource = searchSources[index]; const relatedSourceFromTestsInChangedFiles = searchSource.findRelatedSourcesFromTestsInChangedFiles( changedFilesInfo, ); From 0d50802d9938bc83e9acd4772dbfd1b3c9aa0ad5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=B3=E4=B9=99=E5=B1=B1?= Date: Sun, 26 Apr 2020 15:21:21 +0800 Subject: [PATCH 8/9] Create and keep DependencyResolver in SearchSource for reuse --- packages/jest-core/src/SearchSource.ts | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/packages/jest-core/src/SearchSource.ts b/packages/jest-core/src/SearchSource.ts index 27b05889f675..56ecfaa48ace 100644 --- a/packages/jest-core/src/SearchSource.ts +++ b/packages/jest-core/src/SearchSource.ts @@ -60,11 +60,13 @@ const hasSCM = (changedFilesInfo: ChangedFiles) => { export default class SearchSource { private _context: Context; + private _dependencyResolver: DependencyResolver | null; private _testPathCases: TestPathCases = []; constructor(context: Context) { const {config} = context; this._context = context; + this._dependencyResolver = null; const rootPattern = new RegExp( config.roots.map(dir => escapePathForRegex(dir + path.sep)).join('|'), @@ -99,6 +101,17 @@ export default class SearchSource { } } + private _getOrBuildDependencyResolver(): DependencyResolver { + if (!this._dependencyResolver) { + this._dependencyResolver = new DependencyResolver( + this._context.resolver, + this._context.hasteFS, + buildSnapshotResolver(this._context.config), + ); + } + return this._dependencyResolver; + } + private _filterTestPathsWithStats( allPaths: Array, testPathPattern?: string, @@ -162,11 +175,7 @@ export default class SearchSource { allPaths: Set, collectCoverage: boolean, ): SearchResult { - const dependencyResolver = new DependencyResolver( - this._context.resolver, - this._context.hasteFS, - buildSnapshotResolver(this._context.config), - ); + const dependencyResolver = this._getOrBuildDependencyResolver(); if (!collectCoverage) { return { @@ -340,11 +349,7 @@ export default class SearchSource { return []; } const {changedFiles} = changedFilesInfo; - const dependencyResolver = new DependencyResolver( - this._context.resolver, - this._context.hasteFS, - buildSnapshotResolver(this._context.config), - ); + const dependencyResolver = this._getOrBuildDependencyResolver(); const relatedSourcesSet = new Set(); changedFiles.forEach(filePath => { const isTestFile = this.isTestFilePath(filePath); From 913617bcfa0d2b7ddf94015f21df129d1efc70be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=B3=E4=B9=99=E5=B1=B1?= Date: Sun, 26 Apr 2020 16:00:28 +0800 Subject: [PATCH 9/9] Address code review suggestion --- packages/jest-core/src/SearchSource.ts | 3 +-- .../jest-core/src/__tests__/SearchSource.test.ts | 13 ++++++------- packages/jest-transform/src/shouldInstrument.ts | 14 ++++++-------- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/packages/jest-core/src/SearchSource.ts b/packages/jest-core/src/SearchSource.ts index 56ecfaa48ace..48c630f2adb4 100644 --- a/packages/jest-core/src/SearchSource.ts +++ b/packages/jest-core/src/SearchSource.ts @@ -352,8 +352,7 @@ export default class SearchSource { const dependencyResolver = this._getOrBuildDependencyResolver(); const relatedSourcesSet = new Set(); changedFiles.forEach(filePath => { - const isTestFile = this.isTestFilePath(filePath); - if (isTestFile) { + if (this.isTestFilePath(filePath)) { const sourcePaths = dependencyResolver.resolve(filePath, { skipNodeResolution: this._context.config.skipNodeResolution, }); diff --git a/packages/jest-core/src/__tests__/SearchSource.test.ts b/packages/jest-core/src/__tests__/SearchSource.test.ts index 307e2c2f68b0..0a6815062c85 100644 --- a/packages/jest-core/src/__tests__/SearchSource.test.ts +++ b/packages/jest-core/src/__tests__/SearchSource.test.ts @@ -538,7 +538,7 @@ describe('SearchSource', () => { '../../../jest-runtime/src/__tests__/test_root', ); - beforeEach(done => { + beforeEach(async () => { const {options: config} = normalize( { haste: { @@ -553,12 +553,11 @@ describe('SearchSource', () => { }, {} as Config.Argv, ); - Runtime.createContext(config, {maxWorkers, watchman: false}).then( - context => { - searchSource = new SearchSource(context); - done(); - }, - ); + const context = await Runtime.createContext(config, { + maxWorkers, + watchman: false, + }); + searchSource = new SearchSource(context); }); it('return empty set if no SCM', () => { diff --git a/packages/jest-transform/src/shouldInstrument.ts b/packages/jest-transform/src/shouldInstrument.ts index 7f6ef058f7ad..d9fcdcd268c3 100644 --- a/packages/jest-transform/src/shouldInstrument.ts +++ b/packages/jest-transform/src/shouldInstrument.ts @@ -93,14 +93,12 @@ export default function shouldInstrument( return false; } - if (options.changedFiles) { - if (!options.changedFiles.has(filename)) { - if (!options.sourcesRelatedToTestsInChangedFiles) { - return false; - } - if (!options.sourcesRelatedToTestsInChangedFiles.has(filename)) { - return false; - } + if (options.changedFiles && !options.changedFiles.has(filename)) { + if (!options.sourcesRelatedToTestsInChangedFiles) { + return false; + } + if (!options.sourcesRelatedToTestsInChangedFiles.has(filename)) { + return false; } }