-
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
317d079
commit 86993d4
Showing
8 changed files
with
217 additions
and
116 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
35 changes: 0 additions & 35 deletions
35
packages/jest-config/src/__tests__/validatePattern.test.ts
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
/** | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
import {replacePathSepForRegex} from 'jest-regex-util'; | ||
|
||
export default class TestPathPatterns { | ||
readonly patterns: Array<string>; | ||
|
||
private _regexString: string | null = null; | ||
|
||
constructor(patterns: Array<string>) { | ||
this.patterns = patterns; | ||
} | ||
|
||
get regexString(): string { | ||
if (this._regexString !== null) { | ||
return this._regexString; | ||
} | ||
const regexString = this.patterns | ||
.map(replacePathSepForRegex) | ||
.join('|'); | ||
this._regexString = regexString; | ||
return regexString; | ||
} | ||
|
||
private get regex(): RegExp { | ||
return new RegExp(this.regexString, 'i'); | ||
} | ||
|
||
/** | ||
* Return true if there are any patterns. | ||
*/ | ||
isSet(): boolean { | ||
return this.patterns.length > 0; | ||
} | ||
|
||
/** | ||
* Return true if the patterns form a valid regex. | ||
*/ | ||
isValid(): boolean { | ||
try { | ||
// @ts-expect-error noUnusedLocals | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
const _ = this.regex; | ||
return true; | ||
} catch { | ||
return false; | ||
} | ||
} | ||
|
||
/** | ||
* Return true if the given ABSOLUTE path matches the patterns. | ||
* | ||
* Throws an error if the patterns form an invalid regex (see `isValid`). | ||
*/ | ||
isMatch(path: string): boolean { | ||
return this.regex.test(path); | ||
} | ||
|
||
/** | ||
* Return a human-friendly version of the pattern regex. | ||
* | ||
* Does no normalization or anything, just a naive joining of the regex, | ||
* for simplicity. | ||
*/ | ||
toPretty(): string { | ||
const regex = this.patterns.map(p => p.replace(/\//g, '\\/')).join('|'); | ||
return `/${regex}/i`; | ||
} | ||
} |
134 changes: 134 additions & 0 deletions
134
packages/jest-util/src/__tests__/TestPathPatterns.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
/** | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
import type * as path from 'path'; | ||
import TestPathPatterns from '../TestPathPatterns'; | ||
|
||
const mockSep = jest.fn(); | ||
jest.mock('path', () => { | ||
return { | ||
...(jest.requireActual('path') as typeof path), | ||
get sep() { | ||
return mockSep() || '/'; | ||
}, | ||
}; | ||
}); | ||
beforeEach(() => { | ||
jest.resetAllMocks(); | ||
}); | ||
|
||
describe('TestPathPatterns', () => { | ||
describe('isSet', () => { | ||
it('returns false if no patterns specified', () => { | ||
const testPathPatterns = new TestPathPatterns([]); | ||
expect(testPathPatterns.isSet()).toBe(false); | ||
}); | ||
|
||
it('returns true if patterns specified', () => { | ||
const testPathPatterns = new TestPathPatterns(['a']); | ||
expect(testPathPatterns.isSet()).toBe(true); | ||
}); | ||
}); | ||
|
||
describe('isValid', () => { | ||
it('returns true for empty patterns', () => { | ||
const testPathPatterns = new TestPathPatterns([]); | ||
expect(testPathPatterns.isValid()).toBe(true); | ||
}); | ||
|
||
it('returns true for valid patterns', () => { | ||
const testPathPatterns = new TestPathPatterns(['abc+', 'z.*']); | ||
expect(testPathPatterns.isValid()).toBe(true); | ||
}); | ||
|
||
it('returns false for at least one invalid pattern', () => { | ||
const testPathPatterns = new TestPathPatterns(['abc+', '(', 'z.*']); | ||
expect(testPathPatterns.isValid()).toBe(false); | ||
}); | ||
}); | ||
|
||
describe('isMatch', () => { | ||
it('returns true with no patterns', () => { | ||
const testPathPatterns = new TestPathPatterns([]); | ||
expect(testPathPatterns.isMatch('/a/b')).toBe(true); | ||
}); | ||
|
||
it('returns true for same path', () => { | ||
const testPathPatterns = new TestPathPatterns(['/a/b']); | ||
expect(testPathPatterns.isMatch('/a/b')).toBe(true); | ||
}); | ||
|
||
it('returns true for same path with case insensitive', () => { | ||
const testPathPatternsUpper = new TestPathPatterns(['/A/B']); | ||
expect(testPathPatternsUpper.isMatch('/a/b')).toBe(true); | ||
expect(testPathPatternsUpper.isMatch('/A/B')).toBe(true); | ||
|
||
const testPathPatternsLower = new TestPathPatterns(['/a/b']); | ||
expect(testPathPatternsLower.isMatch('/A/B')).toBe(true); | ||
expect(testPathPatternsLower.isMatch('/a/b')).toBe(true); | ||
}); | ||
|
||
it('returns true for contained path', () => { | ||
const testPathPatterns = new TestPathPatterns(['b/c']); | ||
expect(testPathPatterns.isMatch('/a/b/c/d')).toBe(true); | ||
}); | ||
|
||
it('returns true for partial file match', () => { | ||
const testPathPatterns = new TestPathPatterns(['aaa']); | ||
expect(testPathPatterns.isMatch('/foo/..aaa..')).toBe(true); | ||
expect(testPathPatterns.isMatch('/foo/..aaa')).toBe(true); | ||
expect(testPathPatterns.isMatch('/foo/aaa..')).toBe(true); | ||
}); | ||
|
||
it('returns true for path suffix', () => { | ||
const testPathPatterns = new TestPathPatterns(['c/d']); | ||
expect(testPathPatterns.isMatch('/a/b/c/d')).toBe(true); | ||
}); | ||
|
||
it('returns true if regex matches', () => { | ||
const testPathPatterns = new TestPathPatterns(['ab*c?']); | ||
|
||
expect(testPathPatterns.isMatch('/foo/a')).toBe(true); | ||
expect(testPathPatterns.isMatch('/foo/ab')).toBe(true); | ||
expect(testPathPatterns.isMatch('/foo/abb')).toBe(true); | ||
expect(testPathPatterns.isMatch('/foo/ac')).toBe(true); | ||
expect(testPathPatterns.isMatch('/foo/abc')).toBe(true); | ||
expect(testPathPatterns.isMatch('/foo/abbc')).toBe(true); | ||
|
||
expect(testPathPatterns.isMatch('/foo/bc')).toBe(false); | ||
}); | ||
|
||
it('returns true if match any paths', () => { | ||
const testPathPatterns = new TestPathPatterns(['a/b', 'c/d']); | ||
|
||
expect(testPathPatterns.isMatch('/foo/a/b')).toBe(true); | ||
expect(testPathPatterns.isMatch('/foo/c/d')).toBe(true); | ||
|
||
expect(testPathPatterns.isMatch('/foo/a')).toBe(false); | ||
expect(testPathPatterns.isMatch('/foo/b/c')).toBe(false); | ||
}); | ||
|
||
it('does not normalize Windows paths on POSIX', () => { | ||
mockSep.mockReturnValue('/'); | ||
const testPathPatterns = new TestPathPatterns(['a\\z', 'a\\\\z']); | ||
expect(testPathPatterns.isMatch('/foo/a/z')).toBe(false); | ||
}); | ||
|
||
it('normalizes paths for Windows', () => { | ||
mockSep.mockReturnValue('\\'); | ||
const testPathPatterns = new TestPathPatterns(['a/b']); | ||
expect(testPathPatterns.isMatch('\\foo\\a\\b')).toBe(true); | ||
}); | ||
}); | ||
|
||
describe('toPretty', () => { | ||
it('renders a human-readable string', () => { | ||
const testPathPatterns = new TestPathPatterns(['a/b', 'c/d']); | ||
expect(testPathPatterns.toPretty()).toMatchSnapshot(); | ||
}); | ||
}); | ||
}); |
3 changes: 3 additions & 0 deletions
3
packages/jest-util/src/__tests__/__snapshots__/TestPathPatterns.test.ts.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`TestPathPatterns toPretty renders a human-readable string 1`] = `"/a\\/b|c\\/d/i"`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters