UNPKG

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