From 7c5d42c653e74b4b934131a07f7366239441fd66 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Tue, 8 Jun 2021 22:20:40 +0200 Subject: [PATCH 1/6] fix(findRelatedTests): edge cases with --findRelatedTests on Windows Allow hidden directories and special characters with `--findRelatedTests` on windows. * `jest --findRelatedTests packages/@core/my-app.ts` * `jest --findRelatedTests packages/.hidden/my-hidden-app.ts` * `jest --findRelatedTests 'packages/programs (x86)/my-hidden-app.ts'` --- packages/jest-core/src/SearchSource.ts | 34 +++++---- .../src/__tests__/SearchSource.test.ts | 71 +++++++++++++++++++ 2 files changed, 93 insertions(+), 12 deletions(-) diff --git a/packages/jest-core/src/SearchSource.ts b/packages/jest-core/src/SearchSource.ts index 8b10cf5e0323..f3ea6c5212f1 100644 --- a/packages/jest-core/src/SearchSource.ts +++ b/packages/jest-core/src/SearchSource.ts @@ -288,18 +288,7 @@ export default class SearchSource { let paths = globalConfig.nonFlagArgs; if (globalConfig.findRelatedTests && 'win32' === os.platform()) { - const allFiles = this._context.hasteFS.getAllFiles(); - const options = {nocase: true, windows: false}; - - paths = paths - .map(p => { - const relativePath = path - .resolve(this._context.config.cwd, p) - .replace(/\\/g, '\\\\'); - const match = micromatch(allFiles, relativePath, options); - return match[0]; - }) - .filter(Boolean); + paths = this.filterPathsWin32(paths); } if (globalConfig.runTestsByPath && paths && paths.length) { @@ -316,6 +305,27 @@ export default class SearchSource { } } + public filterPathsWin32(paths: Array): Array { + const allFiles = this._context.hasteFS.getAllFiles(); + const options = {nocase: true, windows: false}; + + paths = paths + .map(p => { + const relativePath = path + .resolve(this._context.config.cwd, p) + .replace(/\\/g, '\\\\') + // Escape extended globs without a pattern: https://github.com/micromatch/micromatch#extended-globbing + // (* and ? are forbidden in file names) + .replace(/(@|\+|!)([^\(])/g, '\\$1$2') + // Allow search in hidden directories + .replace(/\\\./g, '\\\\.'); + const match = micromatch(allFiles, relativePath, options); + return match[0]; + }) + .filter(Boolean); + return paths; + } + async getTestPaths( globalConfig: Config.GlobalConfig, changedFiles: ChangedFiles | undefined, diff --git a/packages/jest-core/src/__tests__/SearchSource.test.ts b/packages/jest-core/src/__tests__/SearchSource.test.ts index 763d8c58018b..372aaedee5d0 100644 --- a/packages/jest-core/src/__tests__/SearchSource.test.ts +++ b/packages/jest-core/src/__tests__/SearchSource.test.ts @@ -406,6 +406,77 @@ describe('SearchSource', () => { }); }); + describe('filterPathsWin32', () => { + beforeEach(async () => { + const config = ( + await normalize( + { + name, + rootDir: '.', + roots: [], + }, + {} as Config.Argv, + ) + ).options; + const context = await Runtime.createContext(config, { + maxWorkers, + watchman: false, + }); + + searchSource = new SearchSource(context); + context.hasteFS.getAllFiles = () => [ + path.resolve('packages/lib/my-lib.ts'), + path.resolve('packages/@core/my-app.ts'), + path.resolve('packages/+cli/my-cli.ts'), + path.resolve('packages/.hidden/my-app-hidden.ts'), + path.resolve('packages/programs (x86)/my-program.ts'), + ]; + }); + + it('should allow a simple match', async () => { + const result = searchSource.filterPathsWin32(['packages/lib/my-lib.ts']); + expect(result).toEqual([path.resolve('packages/lib/my-lib.ts')]); + }); + it('should allow to match a file inside a hidden directory', async () => { + const result = searchSource.filterPathsWin32([ + 'packages/.hidden/my-app-hidden.ts', + ]); + expect(result).toEqual([ + path.resolve('packages/.hidden/my-app-hidden.ts'), + ]); + }); + it('should allow to match a file inside a directory prefixed with a "@"', async () => { + const result = searchSource.filterPathsWin32([ + 'packages/@core/my-app.ts', + ]); + expect(result).toEqual([path.resolve('packages/@core/my-app.ts')]); + }); + it('should allow to match a file inside a directory prefixed with a "+"', async () => { + const result = searchSource.filterPathsWin32(['packages/+cli/my-cli.ts']); + expect(result).toEqual([path.resolve('packages/+cli/my-cli.ts')]); + }); + it('should allow an @(pattern)', () => { + const result = searchSource.filterPathsWin32([ + 'packages/@(@core)/my-app.ts', + ]); + expect(result).toEqual([path.resolve('packages/@core/my-app.ts')]); + }); + it('should allow a +(pattern)', () => { + const result = searchSource.filterPathsWin32([ + 'packages/+(@core)/my-app.ts', + ]); + expect(result).toEqual([path.resolve('packages/@core/my-app.ts')]); + }); + it('should allow for (pattern) in file path', () => { + const result = searchSource.filterPathsWin32([ + 'packages/programs (x86)/my-program.ts', + ]); + expect(result).toEqual([ + path.resolve('packages/programs (x86)/my-program.ts'), + ]); + }); + }); + describe('findRelatedTests', () => { const rootDir = path.join( __dirname, From bdc37bb4473f232d5f9c58596dba0e2cded87cf7 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Tue, 8 Jun 2021 22:26:06 +0200 Subject: [PATCH 2/6] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 502e1cdd3274..8de7991c4b52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - `[jest-reporter]` Allow `node-notifier@10` as peer dependency ([#11523](https://github.com/facebook/jest/pull/11523)) - `[jest-reporter]` Update `v8-to-istanbul` ([#11523](https://github.com/facebook/jest/pull/11523)) +- `[jest-core]` Support special characters on windows with `--findRelatedTests` ([#11548](https://github.com/facebook/jest/pull/11548)) ### Chore & Maintenance From bd36b977f7187b7537d42c9dfd89780415e7ddef Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Tue, 8 Jun 2021 22:51:34 +0200 Subject: [PATCH 3/6] normalize before micro-matching --- packages/jest-core/src/SearchSource.ts | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/packages/jest-core/src/SearchSource.ts b/packages/jest-core/src/SearchSource.ts index f3ea6c5212f1..65fed9e71b2d 100644 --- a/packages/jest-core/src/SearchSource.ts +++ b/packages/jest-core/src/SearchSource.ts @@ -309,18 +309,22 @@ export default class SearchSource { const allFiles = this._context.hasteFS.getAllFiles(); const options = {nocase: true, windows: false}; + function normalizePosix(filePath: string) { + return filePath.replace(/\\/g, '/'); + } + paths = paths .map(p => { - const relativePath = path - .resolve(this._context.config.cwd, p) - .replace(/\\/g, '\\\\') - // Escape extended globs without a pattern: https://github.com/micromatch/micromatch#extended-globbing - // (* and ? are forbidden in file names) - .replace(/(@|\+|!)([^\(])/g, '\\$1$2') - // Allow search in hidden directories - .replace(/\\\./g, '\\\\.'); - const match = micromatch(allFiles, relativePath, options); - return match[0]; + // micromatch works with forward slashes: https://github.com/micromatch/micromatch#backslashes + const normalizedPath = normalizePosix( + path.resolve(this._context.config.cwd, p), + ); + const match = micromatch( + allFiles.map(normalizePosix), + normalizedPath, + options, + ); + return path.resolve(match[0]); }) .filter(Boolean); return paths; From e53bed894b16e3c38841b8f32e338e04772da210 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Tue, 8 Jun 2021 23:17:46 +0200 Subject: [PATCH 4/6] allow no match --- packages/jest-core/src/SearchSource.ts | 2 +- packages/jest-core/src/__tests__/SearchSource.test.ts | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/jest-core/src/SearchSource.ts b/packages/jest-core/src/SearchSource.ts index 65fed9e71b2d..9d7e31762856 100644 --- a/packages/jest-core/src/SearchSource.ts +++ b/packages/jest-core/src/SearchSource.ts @@ -324,7 +324,7 @@ export default class SearchSource { normalizedPath, options, ); - return path.resolve(match[0]); + return match.length && path.resolve(match[0]); }) .filter(Boolean); return paths; diff --git a/packages/jest-core/src/__tests__/SearchSource.test.ts b/packages/jest-core/src/__tests__/SearchSource.test.ts index 372aaedee5d0..76122f957363 100644 --- a/packages/jest-core/src/__tests__/SearchSource.test.ts +++ b/packages/jest-core/src/__tests__/SearchSource.test.ts @@ -475,6 +475,10 @@ describe('SearchSource', () => { path.resolve('packages/programs (x86)/my-program.ts'), ]); }); + it('should allow no results found', () => { + const result = searchSource.filterPathsWin32(['not/exists']); + expect(result).toHaveLength(0); + }); }); describe('findRelatedTests', () => { From 7f90de83822aed0a215d98624eeeed309e350004 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Tue, 8 Jun 2021 23:26:01 +0200 Subject: [PATCH 5/6] Fix type error --- packages/jest-core/src/SearchSource.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/jest-core/src/SearchSource.ts b/packages/jest-core/src/SearchSource.ts index 9d7e31762856..ad03652d18f4 100644 --- a/packages/jest-core/src/SearchSource.ts +++ b/packages/jest-core/src/SearchSource.ts @@ -324,9 +324,10 @@ export default class SearchSource { normalizedPath, options, ); - return match.length && path.resolve(match[0]); + return match[0]; }) - .filter(Boolean); + .filter(Boolean) + .map(p => path.resolve(p)); return paths; } From 325a98b12784cfcb4dec96156ed7927889a45145 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Wed, 9 Jun 2021 12:27:32 +0200 Subject: [PATCH 6/6] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8de7991c4b52..6b62f8d2922c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ - `[jest-reporter]` Allow `node-notifier@10` as peer dependency ([#11523](https://github.com/facebook/jest/pull/11523)) - `[jest-reporter]` Update `v8-to-istanbul` ([#11523](https://github.com/facebook/jest/pull/11523)) -- `[jest-core]` Support special characters on windows with `--findRelatedTests` ([#11548](https://github.com/facebook/jest/pull/11548)) +- `[jest-core]` Support special characters like `@`, `+` and `()` on windows with `--findRelatedTests` ([#11548](https://github.com/facebook/jest/pull/11548)) ### Chore & Maintenance