Skip to content

Commit 1911750

Browse files
Only match within relative path
1 parent ae8ee58 commit 1911750

File tree

5 files changed

+61
-27
lines changed

5 files changed

+61
-27
lines changed

packages/jest-config/src/normalize.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,10 @@ const normalizeReporters = ({
391391
});
392392
};
393393

394-
const buildTestPathPatterns = (argv: Config.Argv): TestPathPatterns => {
394+
const buildTestPathPatterns = (
395+
argv: Config.Argv,
396+
rootDir: string,
397+
): TestPathPatterns => {
395398
const patterns = [];
396399

397400
if (argv._) {
@@ -401,10 +404,11 @@ const buildTestPathPatterns = (argv: Config.Argv): TestPathPatterns => {
401404
patterns.push(...argv.testPathPattern);
402405
}
403406

404-
const testPathPatterns = new TestPathPatterns(patterns);
407+
const config = {rootDir};
408+
const testPathPatterns = new TestPathPatterns(patterns, config);
405409
if (!testPathPatterns.isValid()) {
406410
showTestPathPatternsError(testPathPatterns);
407-
return new TestPathPatterns([]);
411+
return new TestPathPatterns([], config);
408412
}
409413
return testPathPatterns;
410414
};
@@ -997,7 +1001,7 @@ export default async function normalize(
9971001
}
9981002

9991003
newOptions.nonFlagArgs = argv._?.map(arg => `${arg}`);
1000-
const testPathPatterns = buildTestPathPatterns(argv);
1004+
const testPathPatterns = buildTestPathPatterns(argv, options.rootDir);
10011005
newOptions.testPathPatterns = testPathPatterns.patterns;
10021006
newOptions.json = !!argv.json;
10031007

packages/jest-core/src/__tests__/SearchSource.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ describe('SearchSource', () => {
109109
const {searchSource, config} = await initSearchSource(initialOptions);
110110
const {tests: paths} = await searchSource.getTestPaths({
111111
...config,
112+
...initialOptions,
112113
testPathPatterns: [],
113114
});
114115
return paths.map(({path: p}) => path.relative(rootDir, p)).sort();

packages/jest-core/src/watch.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ export default async function watch(
228228

229229
const emitFileChange = () => {
230230
if (hooks.isUsed('onFileChange')) {
231-
const testPathPatterns = new TestPathPatterns([]);
231+
const testPathPatterns = new TestPathPatterns([], globalConfig);
232232
const projects = searchSources.map(({context, searchSource}) => ({
233233
config: context.config,
234234
testPaths: searchSource

packages/jest-util/src/TestPathPatterns.ts

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,35 +6,57 @@
66
*/
77

88
import type {Config} from '@jest/types';
9-
import {replacePathSepForRegex} from 'jest-regex-util';
9+
import {escapePathForRegex, replacePathSepForRegex} from 'jest-regex-util';
1010

1111
type PatternsConfig = Pick<Config.GlobalConfig, 'rootDir'>;
1212
type PatternsFullConfig = PatternsConfig &
1313
Pick<Config.GlobalConfig, 'testPathPatterns'>;
1414

1515
export default class TestPathPatterns {
1616
readonly patterns: Array<string>;
17+
private readonly rootDir: string;
1718

1819
private _regexString: string | null = null;
1920

20-
constructor(patterns: Array<string>, config?: PatternsConfig);
21+
constructor(patterns: Array<string>, config: PatternsConfig);
2122
constructor(config: PatternsFullConfig);
22-
constructor(patternsOrConfig: Array<string> | PatternsFullConfig) {
23-
let patterns;
23+
constructor(
24+
patternsOrConfig: Array<string> | PatternsFullConfig,
25+
configArg?: PatternsConfig,
26+
) {
27+
let patterns, config;
2428
if (Array.isArray(patternsOrConfig)) {
2529
patterns = patternsOrConfig;
30+
config = configArg!;
2631
} else {
2732
patterns = patternsOrConfig.testPathPatterns;
33+
config = patternsOrConfig;
2834
}
2935

3036
this.patterns = patterns;
37+
this.rootDir = config.rootDir.replace(/\/*$/, '/');
3138
}
3239

3340
private get regexString(): string {
3441
if (this._regexString !== null) {
3542
return this._regexString;
3643
}
44+
const rootDirRegex = escapePathForRegex(this.rootDir);
3745
const regexString = this.patterns
46+
.map(p => {
47+
// absolute paths passed on command line should stay same
48+
if (p.match(/^\//)) {
49+
return p;
50+
}
51+
52+
// explicit relative paths should resolve against rootDir
53+
if (p.match(/^\.\//)) {
54+
return p.replace(/^\.\//, rootDirRegex);
55+
}
56+
57+
// all other patterns should only match the relative part of the test
58+
return `${rootDirRegex}(.*)?${p}`;
59+
})
3860
.map(replacePathSepForRegex)
3961
.join('|');
4062
this._regexString = regexString;

packages/jest-util/src/__tests__/TestPathPatterns.test.ts

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,81 +21,88 @@ beforeEach(() => {
2121
jest.resetAllMocks();
2222
});
2323

24+
const config = {rootDir: ''};
25+
2426
describe('TestPathPatterns', () => {
2527
describe('isSet', () => {
2628
it('returns false if no patterns specified', () => {
27-
const testPathPatterns = new TestPathPatterns([]);
29+
const testPathPatterns = new TestPathPatterns([], config);
2830
expect(testPathPatterns.isSet()).toBe(false);
2931
});
3032

3133
it('returns true if patterns specified', () => {
32-
const testPathPatterns = new TestPathPatterns(['a']);
34+
const testPathPatterns = new TestPathPatterns(['a'], config);
3335
expect(testPathPatterns.isSet()).toBe(true);
3436
});
3537
});
3638

3739
describe('isValid', () => {
3840
it('returns true for empty patterns', () => {
39-
const testPathPatterns = new TestPathPatterns([]);
41+
const testPathPatterns = new TestPathPatterns([], config);
4042
expect(testPathPatterns.isValid()).toBe(true);
4143
});
4244

4345
it('returns true for valid patterns', () => {
44-
const testPathPatterns = new TestPathPatterns(['abc+', 'z.*']);
46+
const testPathPatterns = new TestPathPatterns(['abc+', 'z.*'], config);
4547
expect(testPathPatterns.isValid()).toBe(true);
4648
});
4749

4850
it('returns false for at least one invalid pattern', () => {
49-
const testPathPatterns = new TestPathPatterns(['abc+', '(', 'z.*']);
51+
const testPathPatterns = new TestPathPatterns(
52+
['abc+', '(', 'z.*'],
53+
config,
54+
);
5055
expect(testPathPatterns.isValid()).toBe(false);
5156
});
5257
});
5358

5459
describe('isMatch', () => {
5560
it('returns true with no patterns', () => {
56-
const testPathPatterns = new TestPathPatterns([]);
61+
const testPathPatterns = new TestPathPatterns([], config);
5762
expect(testPathPatterns.isMatch('/a/b')).toBe(true);
5863
});
5964

6065
it('returns true for same path', () => {
61-
const testPathPatterns = new TestPathPatterns(['/a/b']);
66+
const testPathPatterns = new TestPathPatterns(['/a/b'], config);
6267
expect(testPathPatterns.isMatch('/a/b')).toBe(true);
6368
});
6469

6570
it('returns true for same path with case insensitive', () => {
66-
const testPathPatternsUpper = new TestPathPatterns(['/A/B']);
71+
const testPathPatternsUpper = new TestPathPatterns(['/A/B'], config);
6772
expect(testPathPatternsUpper.isMatch('/a/b')).toBe(true);
6873
expect(testPathPatternsUpper.isMatch('/A/B')).toBe(true);
6974

70-
const testPathPatternsLower = new TestPathPatterns(['/a/b']);
75+
const testPathPatternsLower = new TestPathPatterns(['/a/b'], config);
7176
expect(testPathPatternsLower.isMatch('/A/B')).toBe(true);
7277
expect(testPathPatternsLower.isMatch('/a/b')).toBe(true);
7378
});
7479

7580
it('returns true for contained path', () => {
76-
const testPathPatterns = new TestPathPatterns(['b/c']);
81+
const testPathPatterns = new TestPathPatterns(['b/c'], config);
7782
expect(testPathPatterns.isMatch('/a/b/c/d')).toBe(true);
7883
});
7984

8085
it('returns true for explicit relative path', () => {
81-
const testPathPatterns = new TestPathPatterns(['./b/c']);
86+
const testPathPatterns = new TestPathPatterns(['./b/c'], {
87+
rootDir: '/a',
88+
});
8289
expect(testPathPatterns.isMatch('/a/b/c')).toBe(true);
8390
});
8491

8592
it('returns true for partial file match', () => {
86-
const testPathPatterns = new TestPathPatterns(['aaa']);
93+
const testPathPatterns = new TestPathPatterns(['aaa'], config);
8794
expect(testPathPatterns.isMatch('/foo/..aaa..')).toBe(true);
8895
expect(testPathPatterns.isMatch('/foo/..aaa')).toBe(true);
8996
expect(testPathPatterns.isMatch('/foo/aaa..')).toBe(true);
9097
});
9198

9299
it('returns true for path suffix', () => {
93-
const testPathPatterns = new TestPathPatterns(['c/d']);
100+
const testPathPatterns = new TestPathPatterns(['c/d'], config);
94101
expect(testPathPatterns.isMatch('/a/b/c/d')).toBe(true);
95102
});
96103

97104
it('returns true if regex matches', () => {
98-
const testPathPatterns = new TestPathPatterns(['ab*c?']);
105+
const testPathPatterns = new TestPathPatterns(['ab*c?'], config);
99106

100107
expect(testPathPatterns.isMatch('/foo/a')).toBe(true);
101108
expect(testPathPatterns.isMatch('/foo/ab')).toBe(true);
@@ -123,7 +130,7 @@ describe('TestPathPatterns', () => {
123130
});
124131

125132
it('returns true if match any paths', () => {
126-
const testPathPatterns = new TestPathPatterns(['a/b', 'c/d']);
133+
const testPathPatterns = new TestPathPatterns(['a/b', 'c/d'], config);
127134

128135
expect(testPathPatterns.isMatch('/foo/a/b')).toBe(true);
129136
expect(testPathPatterns.isMatch('/foo/c/d')).toBe(true);
@@ -134,20 +141,20 @@ describe('TestPathPatterns', () => {
134141

135142
it('does not normalize Windows paths on POSIX', () => {
136143
mockSep.mockReturnValue('/');
137-
const testPathPatterns = new TestPathPatterns(['a\\z', 'a\\\\z']);
144+
const testPathPatterns = new TestPathPatterns(['a\\z', 'a\\\\z'], config);
138145
expect(testPathPatterns.isMatch('/foo/a/z')).toBe(false);
139146
});
140147

141148
it('normalizes paths for Windows', () => {
142149
mockSep.mockReturnValue('\\');
143-
const testPathPatterns = new TestPathPatterns(['a/b']);
150+
const testPathPatterns = new TestPathPatterns(['a/b'], config);
144151
expect(testPathPatterns.isMatch('\\foo\\a\\b')).toBe(true);
145152
});
146153
});
147154

148155
describe('toPretty', () => {
149156
it('renders a human-readable string', () => {
150-
const testPathPatterns = new TestPathPatterns(['a/b', 'c/d']);
157+
const testPathPatterns = new TestPathPatterns(['a/b', 'c/d'], config);
151158
expect(testPathPatterns.toPretty()).toMatchSnapshot();
152159
});
153160
});

0 commit comments

Comments
 (0)