UNPKG

11.9 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', {
4 value: true
5});
6exports.default = void 0;
7
8function os() {
9 const data = _interopRequireWildcard(require('os'));
10
11 os = function () {
12 return data;
13 };
14
15 return data;
16}
17
18function path() {
19 const data = _interopRequireWildcard(require('path'));
20
21 path = function () {
22 return data;
23 };
24
25 return data;
26}
27
28function _micromatch() {
29 const data = _interopRequireDefault(require('micromatch'));
30
31 _micromatch = function () {
32 return data;
33 };
34
35 return data;
36}
37
38function _jestConfig() {
39 const data = require('jest-config');
40
41 _jestConfig = function () {
42 return data;
43 };
44
45 return data;
46}
47
48function _jestRegexUtil() {
49 const data = require('jest-regex-util');
50
51 _jestRegexUtil = function () {
52 return data;
53 };
54
55 return data;
56}
57
58function _jestResolveDependencies() {
59 const data = require('jest-resolve-dependencies');
60
61 _jestResolveDependencies = function () {
62 return data;
63 };
64
65 return data;
66}
67
68function _jestSnapshot() {
69 const data = require('jest-snapshot');
70
71 _jestSnapshot = function () {
72 return data;
73 };
74
75 return data;
76}
77
78function _jestUtil() {
79 const data = require('jest-util');
80
81 _jestUtil = function () {
82 return data;
83 };
84
85 return data;
86}
87
88function _interopRequireDefault(obj) {
89 return obj && obj.__esModule ? obj : {default: obj};
90}
91
92function _getRequireWildcardCache(nodeInterop) {
93 if (typeof WeakMap !== 'function') return null;
94 var cacheBabelInterop = new WeakMap();
95 var cacheNodeInterop = new WeakMap();
96 return (_getRequireWildcardCache = function (nodeInterop) {
97 return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
98 })(nodeInterop);
99}
100
101function _interopRequireWildcard(obj, nodeInterop) {
102 if (!nodeInterop && obj && obj.__esModule) {
103 return obj;
104 }
105 if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
106 return {default: obj};
107 }
108 var cache = _getRequireWildcardCache(nodeInterop);
109 if (cache && cache.has(obj)) {
110 return cache.get(obj);
111 }
112 var newObj = {};
113 var hasPropertyDescriptor =
114 Object.defineProperty && Object.getOwnPropertyDescriptor;
115 for (var key in obj) {
116 if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) {
117 var desc = hasPropertyDescriptor
118 ? Object.getOwnPropertyDescriptor(obj, key)
119 : null;
120 if (desc && (desc.get || desc.set)) {
121 Object.defineProperty(newObj, key, desc);
122 } else {
123 newObj[key] = obj[key];
124 }
125 }
126 }
127 newObj.default = obj;
128 if (cache) {
129 cache.set(obj, newObj);
130 }
131 return newObj;
132}
133
134function _defineProperty(obj, key, value) {
135 if (key in obj) {
136 Object.defineProperty(obj, key, {
137 value: value,
138 enumerable: true,
139 configurable: true,
140 writable: true
141 });
142 } else {
143 obj[key] = value;
144 }
145 return obj;
146}
147
148const regexToMatcher = testRegex => {
149 const regexes = testRegex.map(testRegex => new RegExp(testRegex));
150 return path =>
151 regexes.some(regex => {
152 const result = regex.test(path); // prevent stateful regexes from breaking, just in case
153
154 regex.lastIndex = 0;
155 return result;
156 });
157};
158
159const toTests = (context, tests) =>
160 tests.map(path => ({
161 context,
162 duration: undefined,
163 path
164 }));
165
166const hasSCM = changedFilesInfo => {
167 const {repos} = changedFilesInfo; // no SCM (git/hg/...) is found in any of the roots.
168
169 const noSCM = Object.values(repos).every(scm => scm.size === 0);
170 return !noSCM;
171};
172
173class SearchSource {
174 constructor(context) {
175 _defineProperty(this, '_context', void 0);
176
177 _defineProperty(this, '_dependencyResolver', void 0);
178
179 _defineProperty(this, '_testPathCases', []);
180
181 const {config} = context;
182 this._context = context;
183 this._dependencyResolver = null;
184 const rootPattern = new RegExp(
185 config.roots
186 .map(dir => (0, _jestRegexUtil().escapePathForRegex)(dir + path().sep))
187 .join('|')
188 );
189
190 this._testPathCases.push({
191 isMatch: path => rootPattern.test(path),
192 stat: 'roots'
193 });
194
195 if (config.testMatch.length) {
196 this._testPathCases.push({
197 isMatch: (0, _jestUtil().globsToMatcher)(config.testMatch),
198 stat: 'testMatch'
199 });
200 }
201
202 if (config.testPathIgnorePatterns.length) {
203 const testIgnorePatternsRegex = new RegExp(
204 config.testPathIgnorePatterns.join('|')
205 );
206
207 this._testPathCases.push({
208 isMatch: path => !testIgnorePatternsRegex.test(path),
209 stat: 'testPathIgnorePatterns'
210 });
211 }
212
213 if (config.testRegex.length) {
214 this._testPathCases.push({
215 isMatch: regexToMatcher(config.testRegex),
216 stat: 'testRegex'
217 });
218 }
219 }
220
221 async _getOrBuildDependencyResolver() {
222 if (!this._dependencyResolver) {
223 this._dependencyResolver =
224 new (_jestResolveDependencies().DependencyResolver)(
225 this._context.resolver,
226 this._context.hasteFS,
227 await (0, _jestSnapshot().buildSnapshotResolver)(this._context.config)
228 );
229 }
230
231 return this._dependencyResolver;
232 }
233
234 _filterTestPathsWithStats(allPaths, testPathPattern) {
235 const data = {
236 stats: {
237 roots: 0,
238 testMatch: 0,
239 testPathIgnorePatterns: 0,
240 testRegex: 0
241 },
242 tests: [],
243 total: allPaths.length
244 };
245 const testCases = Array.from(this._testPathCases); // clone
246
247 if (testPathPattern) {
248 const regex = (0, _jestUtil().testPathPatternToRegExp)(testPathPattern);
249 testCases.push({
250 isMatch: path => regex.test(path),
251 stat: 'testPathPattern'
252 });
253 data.stats.testPathPattern = 0;
254 }
255
256 data.tests = allPaths.filter(test => {
257 let filterResult = true;
258
259 for (const {isMatch, stat} of testCases) {
260 if (isMatch(test.path)) {
261 data.stats[stat]++;
262 } else {
263 filterResult = false;
264 }
265 }
266
267 return filterResult;
268 });
269 return data;
270 }
271
272 _getAllTestPaths(testPathPattern) {
273 return this._filterTestPathsWithStats(
274 toTests(this._context, this._context.hasteFS.getAllFiles()),
275 testPathPattern
276 );
277 }
278
279 isTestFilePath(path) {
280 return this._testPathCases.every(testCase => testCase.isMatch(path));
281 }
282
283 findMatchingTests(testPathPattern) {
284 return this._getAllTestPaths(testPathPattern);
285 }
286
287 async findRelatedTests(allPaths, collectCoverage) {
288 const dependencyResolver = await this._getOrBuildDependencyResolver();
289
290 if (!collectCoverage) {
291 return {
292 tests: toTests(
293 this._context,
294 dependencyResolver.resolveInverse(
295 allPaths,
296 this.isTestFilePath.bind(this),
297 {
298 skipNodeResolution: this._context.config.skipNodeResolution
299 }
300 )
301 )
302 };
303 }
304
305 const testModulesMap = dependencyResolver.resolveInverseModuleMap(
306 allPaths,
307 this.isTestFilePath.bind(this),
308 {
309 skipNodeResolution: this._context.config.skipNodeResolution
310 }
311 );
312 const allPathsAbsolute = Array.from(allPaths).map(p => path().resolve(p));
313 const collectCoverageFrom = new Set();
314 testModulesMap.forEach(testModule => {
315 if (!testModule.dependencies) {
316 return;
317 }
318
319 testModule.dependencies.forEach(p => {
320 if (!allPathsAbsolute.includes(p)) {
321 return;
322 }
323
324 const filename = (0, _jestConfig().replaceRootDirInPath)(
325 this._context.config.rootDir,
326 p
327 );
328 collectCoverageFrom.add(
329 path().isAbsolute(filename)
330 ? path().relative(this._context.config.rootDir, filename)
331 : filename
332 );
333 });
334 });
335 return {
336 collectCoverageFrom,
337 tests: toTests(
338 this._context,
339 testModulesMap.map(testModule => testModule.file)
340 )
341 };
342 }
343
344 findTestsByPaths(paths) {
345 return {
346 tests: toTests(
347 this._context,
348 paths
349 .map(p => path().resolve(this._context.config.cwd, p))
350 .filter(this.isTestFilePath.bind(this))
351 )
352 };
353 }
354
355 async findRelatedTestsFromPattern(paths, collectCoverage) {
356 if (Array.isArray(paths) && paths.length) {
357 const resolvedPaths = paths.map(p =>
358 path().resolve(this._context.config.cwd, p)
359 );
360 return this.findRelatedTests(new Set(resolvedPaths), collectCoverage);
361 }
362
363 return {
364 tests: []
365 };
366 }
367
368 async findTestRelatedToChangedFiles(changedFilesInfo, collectCoverage) {
369 if (!hasSCM(changedFilesInfo)) {
370 return {
371 noSCM: true,
372 tests: []
373 };
374 }
375
376 const {changedFiles} = changedFilesInfo;
377 return this.findRelatedTests(changedFiles, collectCoverage);
378 }
379
380 async _getTestPaths(globalConfig, changedFiles) {
381 if (globalConfig.onlyChanged) {
382 if (!changedFiles) {
383 throw new Error('Changed files must be set when running with -o.');
384 }
385
386 return this.findTestRelatedToChangedFiles(
387 changedFiles,
388 globalConfig.collectCoverage
389 );
390 }
391
392 let paths = globalConfig.nonFlagArgs;
393
394 if (globalConfig.findRelatedTests && 'win32' === os().platform()) {
395 paths = this.filterPathsWin32(paths);
396 }
397
398 if (globalConfig.runTestsByPath && paths && paths.length) {
399 return this.findTestsByPaths(paths);
400 } else if (globalConfig.findRelatedTests && paths && paths.length) {
401 return this.findRelatedTestsFromPattern(
402 paths,
403 globalConfig.collectCoverage
404 );
405 } else if (globalConfig.testPathPattern != null) {
406 return this.findMatchingTests(globalConfig.testPathPattern);
407 } else {
408 return {
409 tests: []
410 };
411 }
412 }
413
414 filterPathsWin32(paths) {
415 const allFiles = this._context.hasteFS.getAllFiles();
416
417 const options = {
418 nocase: true,
419 windows: false
420 };
421
422 function normalizePosix(filePath) {
423 return filePath.replace(/\\/g, '/');
424 }
425
426 paths = paths
427 .map(p => {
428 // micromatch works with forward slashes: https://github.com/micromatch/micromatch#backslashes
429 const normalizedPath = normalizePosix(
430 path().resolve(this._context.config.cwd, p)
431 );
432 const match = (0, _micromatch().default)(
433 allFiles.map(normalizePosix),
434 normalizedPath,
435 options
436 );
437 return match[0];
438 })
439 .filter(Boolean)
440 .map(p => path().resolve(p));
441 return paths;
442 }
443
444 async getTestPaths(globalConfig, changedFiles, filter) {
445 const searchResult = await this._getTestPaths(globalConfig, changedFiles);
446 const filterPath = globalConfig.filter;
447
448 if (filter) {
449 const tests = searchResult.tests;
450 const filterResult = await filter(tests.map(test => test.path));
451
452 if (!Array.isArray(filterResult.filtered)) {
453 throw new Error(
454 `Filter ${filterPath} did not return a valid test list`
455 );
456 }
457
458 const filteredSet = new Set(
459 filterResult.filtered.map(result => result.test)
460 );
461 return {
462 ...searchResult,
463 tests: tests.filter(test => filteredSet.has(test.path))
464 };
465 }
466
467 return searchResult;
468 }
469
470 async findRelatedSourcesFromTestsInChangedFiles(changedFilesInfo) {
471 if (!hasSCM(changedFilesInfo)) {
472 return [];
473 }
474
475 const {changedFiles} = changedFilesInfo;
476 const dependencyResolver = await this._getOrBuildDependencyResolver();
477 const relatedSourcesSet = new Set();
478 changedFiles.forEach(filePath => {
479 if (this.isTestFilePath(filePath)) {
480 const sourcePaths = dependencyResolver.resolve(filePath, {
481 skipNodeResolution: this._context.config.skipNodeResolution
482 });
483 sourcePaths.forEach(sourcePath => relatedSourcesSet.add(sourcePath));
484 }
485 });
486 return Array.from(relatedSourcesSet);
487 }
488}
489
490exports.default = SearchSource;