mirror of https://github.com/facebook/jest.git
Fix testPathPatterns when config is in subdirectory (#14934)
This commit is contained in:
parent
cb15c34c04
commit
68dca2a321
|
@ -64,11 +64,11 @@
|
|||
- `[jest-leak-detector]` Make leak-detector more aggressive when running GC ([#14526](https://github.com/jestjs/jest/pull/14526))
|
||||
- `[jest-runtime]` Properly handle re-exported native modules in ESM via CJS ([#14589](https://github.com/jestjs/jest/pull/14589))
|
||||
- `[jest-util]` Make sure `isInteractive` works in a browser ([#14552](https://github.com/jestjs/jest/pull/14552))
|
||||
- `[jest-util]` Add missing dependency on `jest-regex-util` ([#15030](https://github.com/jestjs/jest/pull/15030))
|
||||
- `[pretty-format]` [**BREAKING**] Print `ArrayBuffer` and `DataView` correctly ([#14290](https://github.com/jestjs/jest/pull/14290))
|
||||
- `[jest-cli]` When specifying paths on the command line, only match against the relative paths of the test files ([#12519](https://github.com/jestjs/jest/pull/12519))
|
||||
- [**BREAKING**] Changes `testPathPattern` configuration option to `testPathPatterns`, which now takes a list of patterns instead of the regex.
|
||||
- [**BREAKING**] `--testPathPattern` is now `--testPathPatterns`
|
||||
- [**BREAKING**] Specifying `testPathPatterns` when programmatically calling `watch` must be specified as `new TestPathPatterns(patterns)`, where `TestPathPatterns` can be imported from `@jest/pattern`
|
||||
- `[jest-reporters, jest-runner]` Unhandled errors without stack get correctly logged to console ([#14619](https://github.com/jestjs/jest/pull/14619))
|
||||
|
||||
### Performance
|
||||
|
|
|
@ -46,7 +46,7 @@ test('Tests are executed only once even in an MPR', () => {
|
|||
});
|
||||
/* eslint-enable sort-keys */
|
||||
|
||||
const {stderr, exitCode} = runJest(DIR, ['foo/folder/my-test-bar.js']);
|
||||
const {stderr, exitCode} = runJest(DIR, ['my-test-bar.js']);
|
||||
|
||||
expect(exitCode).toBe(0);
|
||||
|
||||
|
|
|
@ -109,7 +109,7 @@ test('should not call a globalSetup of a project if there are no tests to run fr
|
|||
|
||||
const result = runWithJson(e2eDir, [
|
||||
`--config=${configPath}`,
|
||||
'--testPathPatterns=project-1',
|
||||
'--testPathPatterns=setup1',
|
||||
]);
|
||||
|
||||
expect(result.exitCode).toBe(0);
|
||||
|
|
|
@ -93,7 +93,7 @@ test('should not call a globalTeardown of a project if there are no tests to run
|
|||
|
||||
const result = runWithJson('global-teardown', [
|
||||
`--config=${configPath}`,
|
||||
'--testPathPatterns=project-1',
|
||||
'--testPathPatterns=teardown1',
|
||||
]);
|
||||
|
||||
expect(result.exitCode).toBe(0);
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
/**
|
||||
* 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 {json} from '../runJest';
|
||||
|
||||
it('works when specifying --testPathPatterns when config is in subdir', () => {
|
||||
const {
|
||||
json: {numTotalTests},
|
||||
} = json('test-path-patterns-subprojects', [
|
||||
'--config=config/jest.config.js',
|
||||
'--testPathPatterns=testA',
|
||||
]);
|
||||
expect(numTotalTests).toBe(1);
|
||||
});
|
|
@ -6,6 +6,6 @@
|
|||
*/
|
||||
|
||||
module.exports = function (globalConfig, projectConfig) {
|
||||
console.log(globalConfig.testPathPatterns);
|
||||
console.log(globalConfig.testPathPatterns.patterns);
|
||||
console.log(projectConfig.cache);
|
||||
};
|
||||
|
|
|
@ -6,6 +6,6 @@
|
|||
*/
|
||||
|
||||
export default function (globalConfig, projectConfig): void {
|
||||
console.log(globalConfig.testPathPatterns);
|
||||
console.log(globalConfig.testPathPatterns.patterns);
|
||||
console.log(projectConfig.cache);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,6 @@
|
|||
*/
|
||||
|
||||
module.exports = function (globalConfig, projectConfig) {
|
||||
console.log(globalConfig.testPathPatterns);
|
||||
console.log(globalConfig.testPathPatterns.patterns);
|
||||
console.log(projectConfig.cache);
|
||||
};
|
||||
|
|
|
@ -6,6 +6,6 @@
|
|||
*/
|
||||
|
||||
export default function (globalConfig, projectConfig): void {
|
||||
console.log(globalConfig.testPathPatterns);
|
||||
console.log(globalConfig.testPathPatterns.patterns);
|
||||
console.log(projectConfig.cache);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import dedent from 'dedent';
|
|||
import execa = require('execa');
|
||||
import * as fs from 'graceful-fs';
|
||||
import stripAnsi = require('strip-ansi');
|
||||
import {TestPathPatterns} from '@jest/pattern';
|
||||
import type {FormattedTestResults} from '@jest/test-result';
|
||||
import {normalizeIcons} from '@jest/test-utils';
|
||||
import type {Config} from '@jest/types';
|
||||
|
@ -285,5 +286,10 @@ export function getConfig(
|
|||
throw error;
|
||||
}
|
||||
|
||||
return JSON.parse(stdout);
|
||||
const {testPathPatterns, ...globalConfig} = JSON.parse(stdout);
|
||||
|
||||
return {
|
||||
...globalConfig,
|
||||
testPathPatterns: new TestPathPatterns(testPathPatterns),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
projects: [{rootDir: 'src'}],
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
{}
|
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
it('test', () => {});
|
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
it('test', () => {});
|
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
it('test', () => {});
|
|
@ -655,7 +655,7 @@ export const options: {[key: string]: Options} = {
|
|||
},
|
||||
testPathPatterns: {
|
||||
description:
|
||||
'A regexp pattern string that is matched against all tests ' +
|
||||
'An array of regexp pattern strings that are matched against all tests ' +
|
||||
'paths before executing the test.',
|
||||
requiresArg: true,
|
||||
string: true,
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.11.6",
|
||||
"@jest/pattern": "workspace:*",
|
||||
"@jest/test-sequencer": "workspace:*",
|
||||
"@jest/types": "workspace:*",
|
||||
"babel-jest": "workspace:*",
|
||||
|
|
|
@ -1601,7 +1601,7 @@ describe('testPathPatterns', () => {
|
|||
it('defaults to empty', async () => {
|
||||
const {options} = await normalize(initialOptions, {} as Config.Argv);
|
||||
|
||||
expect(options.testPathPatterns).toEqual([]);
|
||||
expect(options.testPathPatterns.patterns).toEqual([]);
|
||||
});
|
||||
|
||||
const cliOptions = [
|
||||
|
@ -1614,14 +1614,14 @@ describe('testPathPatterns', () => {
|
|||
const argv = {[opt.property]: ['a/b']} as Config.Argv;
|
||||
const {options} = await normalize(initialOptions, argv);
|
||||
|
||||
expect(options.testPathPatterns).toEqual(['a/b']);
|
||||
expect(options.testPathPatterns.patterns).toEqual(['a/b']);
|
||||
});
|
||||
|
||||
it('ignores invalid regular expressions and logs a warning', async () => {
|
||||
const argv = {[opt.property]: ['a(']} as Config.Argv;
|
||||
const {options} = await normalize(initialOptions, argv);
|
||||
|
||||
expect(options.testPathPatterns).toEqual([]);
|
||||
expect(options.testPathPatterns.patterns).toEqual([]);
|
||||
expect(jest.mocked(console.log).mock.calls[0][0]).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
@ -1629,7 +1629,7 @@ describe('testPathPatterns', () => {
|
|||
const argv = {[opt.property]: ['a/b', 'c/d']} as Config.Argv;
|
||||
const {options} = await normalize(initialOptions, argv);
|
||||
|
||||
expect(options.testPathPatterns).toEqual(['a/b', 'c/d']);
|
||||
expect(options.testPathPatterns.patterns).toEqual(['a/b', 'c/d']);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -1638,7 +1638,7 @@ describe('testPathPatterns', () => {
|
|||
const argv = {_: [1]} as Config.Argv;
|
||||
const {options} = await normalize(initialOptions, argv);
|
||||
|
||||
expect(options.testPathPatterns).toEqual(['1']);
|
||||
expect(options.testPathPatterns.patterns).toEqual(['1']);
|
||||
});
|
||||
|
||||
it('joins multiple --testPathPatterns and <regexForTestFiles>', async () => {
|
||||
|
@ -1646,7 +1646,7 @@ describe('testPathPatterns', () => {
|
|||
_: ['a', 'b'],
|
||||
testPathPatterns: ['c', 'd'],
|
||||
} as Config.Argv);
|
||||
expect(options.testPathPatterns).toEqual(['a', 'b', 'c', 'd']);
|
||||
expect(options.testPathPatterns.patterns).toEqual(['a', 'b', 'c', 'd']);
|
||||
});
|
||||
|
||||
it('gives precedence to --all', async () => {
|
||||
|
|
|
@ -13,6 +13,7 @@ import merge = require('deepmerge');
|
|||
import {glob} from 'glob';
|
||||
import {statSync} from 'graceful-fs';
|
||||
import micromatch = require('micromatch');
|
||||
import {TestPathPatterns} from '@jest/pattern';
|
||||
import type {Config} from '@jest/types';
|
||||
import {replacePathSepForRegex} from 'jest-regex-util';
|
||||
import Resolver, {
|
||||
|
@ -22,7 +23,6 @@ import Resolver, {
|
|||
resolveWatchPlugin,
|
||||
} from 'jest-resolve';
|
||||
import {
|
||||
TestPathPatterns,
|
||||
clearLine,
|
||||
replacePathSepForGlob,
|
||||
requireOrImportModule,
|
||||
|
@ -393,10 +393,7 @@ const normalizeReporters = ({
|
|||
});
|
||||
};
|
||||
|
||||
const buildTestPathPatterns = (
|
||||
argv: Config.Argv,
|
||||
rootDir: string,
|
||||
): TestPathPatterns => {
|
||||
const buildTestPathPatterns = (argv: Config.Argv): TestPathPatterns => {
|
||||
const patterns = [];
|
||||
|
||||
if (argv._) {
|
||||
|
@ -406,12 +403,9 @@ const buildTestPathPatterns = (
|
|||
patterns.push(...argv.testPathPatterns);
|
||||
}
|
||||
|
||||
const config = {rootDir};
|
||||
const testPathPatterns = new TestPathPatterns(patterns, config);
|
||||
const testPathPatterns = new TestPathPatterns(patterns);
|
||||
|
||||
try {
|
||||
testPathPatterns.validate();
|
||||
} catch {
|
||||
if (!testPathPatterns.isValid()) {
|
||||
clearLine(process.stdout);
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
|
@ -422,7 +416,7 @@ const buildTestPathPatterns = (
|
|||
),
|
||||
);
|
||||
|
||||
return new TestPathPatterns([], config);
|
||||
return new TestPathPatterns([]);
|
||||
}
|
||||
|
||||
return testPathPatterns;
|
||||
|
@ -1012,8 +1006,8 @@ export default async function normalize(
|
|||
}
|
||||
|
||||
newOptions.nonFlagArgs = argv._?.map(arg => `${arg}`);
|
||||
const testPathPatterns = buildTestPathPatterns(argv, options.rootDir);
|
||||
newOptions.testPathPatterns = testPathPatterns.patterns;
|
||||
const testPathPatterns = buildTestPathPatterns(argv);
|
||||
newOptions.testPathPatterns = testPathPatterns;
|
||||
newOptions.json = !!argv.json;
|
||||
|
||||
newOptions.testFailureExitCode = Number.parseInt(
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
"references": [
|
||||
{"path": "../jest-environment-node"},
|
||||
{"path": "../jest-get-type"},
|
||||
{"path": "../jest-pattern"},
|
||||
{"path": "../jest-regex-util"},
|
||||
{"path": "../jest-resolve"},
|
||||
{"path": "../jest-runner"},
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@jest/console": "workspace:*",
|
||||
"@jest/pattern": "workspace:*",
|
||||
"@jest/reporters": "workspace:*",
|
||||
"@jest/test-result": "workspace:*",
|
||||
"@jest/transform": "workspace:*",
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import micromatch = require('micromatch');
|
||||
import type {TestPathPatternsExecutor} from '@jest/pattern';
|
||||
import type {Test, TestContext} from '@jest/test-result';
|
||||
import type {Config} from '@jest/types';
|
||||
import type {ChangedFiles} from 'jest-changed-files';
|
||||
|
@ -15,7 +16,7 @@ import {replaceRootDirInPath} from 'jest-config';
|
|||
import {escapePathForRegex} from 'jest-regex-util';
|
||||
import {DependencyResolver} from 'jest-resolve-dependencies';
|
||||
import {buildSnapshotResolver} from 'jest-snapshot';
|
||||
import {TestPathPatterns, globsToMatcher} from 'jest-util';
|
||||
import {globsToMatcher} from 'jest-util';
|
||||
import type {Filter, Stats, TestPathCases} from './types';
|
||||
|
||||
export type SearchResult = {
|
||||
|
@ -114,7 +115,7 @@ export default class SearchSource {
|
|||
|
||||
private _filterTestPathsWithStats(
|
||||
allPaths: Array<Test>,
|
||||
testPathPatterns: TestPathPatterns,
|
||||
testPathPatternsExecutor: TestPathPatternsExecutor,
|
||||
): SearchResult {
|
||||
const data: {
|
||||
stats: Stats;
|
||||
|
@ -132,9 +133,9 @@ export default class SearchSource {
|
|||
};
|
||||
|
||||
const testCases = [...this._testPathCases]; // clone
|
||||
if (testPathPatterns.isSet()) {
|
||||
if (testPathPatternsExecutor.isSet()) {
|
||||
testCases.push({
|
||||
isMatch: (path: string) => testPathPatterns.isMatch(path),
|
||||
isMatch: (path: string) => testPathPatternsExecutor.isMatch(path),
|
||||
stat: 'testPathPatterns',
|
||||
});
|
||||
data.stats.testPathPatterns = 0;
|
||||
|
@ -155,10 +156,12 @@ export default class SearchSource {
|
|||
return data;
|
||||
}
|
||||
|
||||
private _getAllTestPaths(testPathPatterns: TestPathPatterns): SearchResult {
|
||||
private _getAllTestPaths(
|
||||
testPathPatternsExecutor: TestPathPatternsExecutor,
|
||||
): SearchResult {
|
||||
return this._filterTestPathsWithStats(
|
||||
toTests(this._context, this._context.hasteFS.getAllFiles()),
|
||||
testPathPatterns,
|
||||
testPathPatternsExecutor,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -166,8 +169,10 @@ export default class SearchSource {
|
|||
return this._testPathCases.every(testCase => testCase.isMatch(path));
|
||||
}
|
||||
|
||||
findMatchingTests(testPathPatterns: TestPathPatterns): SearchResult {
|
||||
return this._getAllTestPaths(testPathPatterns);
|
||||
findMatchingTests(
|
||||
testPathPatternsExecutor: TestPathPatternsExecutor,
|
||||
): SearchResult {
|
||||
return this._getAllTestPaths(testPathPatternsExecutor);
|
||||
}
|
||||
|
||||
async findRelatedTests(
|
||||
|
@ -264,6 +269,7 @@ export default class SearchSource {
|
|||
|
||||
private async _getTestPaths(
|
||||
globalConfig: Config.GlobalConfig,
|
||||
projectConfig: Config.ProjectConfig,
|
||||
changedFiles?: ChangedFiles,
|
||||
): Promise<SearchResult> {
|
||||
if (globalConfig.onlyChanged) {
|
||||
|
@ -292,7 +298,9 @@ export default class SearchSource {
|
|||
);
|
||||
} else {
|
||||
return this.findMatchingTests(
|
||||
TestPathPatterns.fromGlobalConfig(globalConfig),
|
||||
globalConfig.testPathPatterns.toExecutor({
|
||||
rootDir: projectConfig.rootDir,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -321,10 +329,15 @@ export default class SearchSource {
|
|||
|
||||
async getTestPaths(
|
||||
globalConfig: Config.GlobalConfig,
|
||||
projectConfig: Config.ProjectConfig,
|
||||
changedFiles?: ChangedFiles,
|
||||
filter?: Filter,
|
||||
): Promise<SearchResult> {
|
||||
const searchResult = await this._getTestPaths(globalConfig, changedFiles);
|
||||
const searchResult = await this._getTestPaths(
|
||||
globalConfig,
|
||||
projectConfig,
|
||||
changedFiles,
|
||||
);
|
||||
|
||||
const filterPath = globalConfig.filter;
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
import * as path from 'path';
|
||||
import {TestPathPatterns} from '@jest/pattern';
|
||||
import type {Test} from '@jest/test-result';
|
||||
import type {Config} from '@jest/types';
|
||||
import {normalize} from 'jest-config';
|
||||
|
@ -111,12 +112,14 @@ describe('SearchSource', () => {
|
|||
filter?: Filter,
|
||||
) => {
|
||||
const {searchSource, config} = await initSearchSource(initialOptions);
|
||||
const allConfig = {
|
||||
...config,
|
||||
...initialOptions,
|
||||
testPathPatterns: new TestPathPatterns([]),
|
||||
};
|
||||
const {tests: paths} = await searchSource.getTestPaths(
|
||||
{
|
||||
...config,
|
||||
...initialOptions,
|
||||
testPathPatterns: [],
|
||||
},
|
||||
allConfig,
|
||||
allConfig,
|
||||
null,
|
||||
filter,
|
||||
);
|
||||
|
|
|
@ -93,9 +93,12 @@ Object {
|
|||
"onlyChanged": false,
|
||||
"passWithNoTests": true,
|
||||
"rootDir": "",
|
||||
"testPathPatterns": Array [
|
||||
"p.*3",
|
||||
],
|
||||
"testPathPatterns": Object {
|
||||
"patterns": Array [
|
||||
"p.*3",
|
||||
],
|
||||
"type": "TestPathPatterns",
|
||||
},
|
||||
"watch": true,
|
||||
"watchAll": false,
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {TestPathPatterns} from '@jest/pattern';
|
||||
import {makeGlobalConfig} from '@jest/test-utils';
|
||||
import type {Config} from '@jest/types';
|
||||
import getNoTestsFoundMessage from '../getNoTestsFoundMessage';
|
||||
|
@ -18,7 +19,7 @@ describe('getNoTestsFoundMessage', () => {
|
|||
function createGlobalConfig(options?: Partial<Config.GlobalConfig>) {
|
||||
return makeGlobalConfig({
|
||||
rootDir: '/root/dir',
|
||||
testPathPatterns: ['/path/pattern'],
|
||||
testPathPatterns: new TestPathPatterns(['/path/pattern']),
|
||||
...options,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {TestPathPatterns} from '@jest/pattern';
|
||||
import runJest from '../runJest';
|
||||
|
||||
jest.mock('@jest/console');
|
||||
|
@ -23,7 +24,7 @@ describe('runJest', () => {
|
|||
contexts: [],
|
||||
globalConfig: {
|
||||
rootDir: '',
|
||||
testPathPatterns: [],
|
||||
testPathPatterns: new TestPathPatterns([]),
|
||||
testSequencer: require.resolve('@jest/test-sequencer'),
|
||||
watch: true,
|
||||
},
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
import chalk from 'chalk';
|
||||
import {TestPathPatterns} from '@jest/pattern';
|
||||
// eslint-disable-next-line import/order
|
||||
import {JestHook, KEYS, TestWatcher} from 'jest-watcher';
|
||||
|
||||
|
@ -142,7 +143,7 @@ describe('Watch mode flows', () => {
|
|||
pipe = {write: jest.fn()};
|
||||
globalConfig = {
|
||||
rootDir: '',
|
||||
testPathPatterns: [],
|
||||
testPathPatterns: new TestPathPatterns([]),
|
||||
watch: true,
|
||||
};
|
||||
hasteMapInstances = [{on: () => {}}];
|
||||
|
@ -156,7 +157,7 @@ describe('Watch mode flows', () => {
|
|||
});
|
||||
|
||||
it('Correctly passing test path pattern', async () => {
|
||||
globalConfig.testPathPatterns = ['test-*'];
|
||||
globalConfig.testPathPatterns = new TestPathPatterns(['test-*']);
|
||||
|
||||
await watch(globalConfig, contexts, pipe, hasteMapInstances, stdin);
|
||||
|
||||
|
@ -690,6 +691,14 @@ describe('Watch mode flows', () => {
|
|||
ok = ok === '✔︎';
|
||||
const pluginPath = `${__dirname}/__fixtures__/plugin_path_config_updater_${option}`;
|
||||
|
||||
const newVal = (() => {
|
||||
if (option === 'testPathPatterns') {
|
||||
return new TestPathPatterns(['a/b', 'c']);
|
||||
}
|
||||
|
||||
return '__JUST_TRYING__';
|
||||
})();
|
||||
|
||||
jest.doMock(
|
||||
pluginPath,
|
||||
() =>
|
||||
|
@ -699,7 +708,7 @@ describe('Watch mode flows', () => {
|
|||
}
|
||||
|
||||
run(globalConfig, updateConfigAndRun) {
|
||||
updateConfigAndRun({[option]: '__JUST_TRYING__'});
|
||||
updateConfigAndRun({[option]: newVal});
|
||||
return Promise.resolve();
|
||||
}
|
||||
},
|
||||
|
@ -726,7 +735,7 @@ describe('Watch mode flows', () => {
|
|||
if (!ok) {
|
||||
expector = expector.not;
|
||||
}
|
||||
expector.toHaveProperty(option, '__JUST_TRYING__');
|
||||
expector.toHaveProperty(option, newVal);
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -904,7 +913,7 @@ describe('Watch mode flows', () => {
|
|||
await nextTick();
|
||||
|
||||
expect(runJestMock.mock.calls[0][0].globalConfig).toMatchObject({
|
||||
testPathPatterns: ['file'],
|
||||
testPathPatterns: {patterns: ['file']},
|
||||
watch: true,
|
||||
watchAll: false,
|
||||
});
|
||||
|
@ -928,7 +937,7 @@ describe('Watch mode flows', () => {
|
|||
|
||||
expect(runJestMock.mock.calls[1][0].globalConfig).toMatchObject({
|
||||
testNamePattern: 'test',
|
||||
testPathPatterns: ['file'],
|
||||
testPathPatterns: {patterns: ['file']},
|
||||
watch: true,
|
||||
watchAll: false,
|
||||
});
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
import chalk from 'chalk';
|
||||
import {TestPathPatterns} from '@jest/pattern';
|
||||
// eslint-disable-next-line import/order
|
||||
import {KEYS} from 'jest-watcher';
|
||||
|
||||
|
@ -72,7 +73,7 @@ const nextTick = () => new Promise(resolve => process.nextTick(resolve));
|
|||
|
||||
const globalConfig = {
|
||||
rootDir: '',
|
||||
testPathPatterns: [],
|
||||
testPathPatterns: new TestPathPatterns([]),
|
||||
watch: true,
|
||||
};
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
import chalk from 'chalk';
|
||||
import {TestPathPatterns} from '@jest/pattern';
|
||||
// eslint-disable-next-line import/order
|
||||
import {KEYS} from 'jest-watcher';
|
||||
|
||||
|
@ -84,7 +85,7 @@ const watch = require('../watch').default;
|
|||
|
||||
const globalConfig = {
|
||||
rootDir: '',
|
||||
testPathPatterns: [],
|
||||
testPathPatterns: new TestPathPatterns([]),
|
||||
watch: true,
|
||||
};
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import chalk = require('chalk');
|
||||
import type {Config} from '@jest/types';
|
||||
import {TestPathPatterns, pluralize} from 'jest-util';
|
||||
import {pluralize} from 'jest-util';
|
||||
import type {TestRunData} from './types';
|
||||
|
||||
export default function getNoTestFound(
|
||||
|
@ -26,9 +26,8 @@ export default function getNoTestFound(
|
|||
.map(p => `"${p}"`)
|
||||
.join(', ')}`;
|
||||
} else {
|
||||
const testPathPatterns = TestPathPatterns.fromGlobalConfig(globalConfig);
|
||||
dataMessage = `Pattern: ${chalk.yellow(
|
||||
testPathPatterns.toPretty(),
|
||||
globalConfig.testPathPatterns.toPretty(),
|
||||
)} - 0 matches`;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import chalk = require('chalk');
|
||||
import type {Config} from '@jest/types';
|
||||
import {TestPathPatterns, pluralize} from 'jest-util';
|
||||
import {pluralize} from 'jest-util';
|
||||
import type {Stats, TestRunData} from './types';
|
||||
|
||||
export default function getNoTestFoundVerbose(
|
||||
|
@ -56,9 +56,8 @@ export default function getNoTestFoundVerbose(
|
|||
.map(p => `"${p}"`)
|
||||
.join(', ')}`;
|
||||
} else {
|
||||
const testPathPatterns = TestPathPatterns.fromGlobalConfig(globalConfig);
|
||||
dataMessage = `Pattern: ${chalk.yellow(
|
||||
testPathPatterns.toPretty(),
|
||||
globalConfig.testPathPatterns.toPretty(),
|
||||
)} - 0 matches`;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
|
||||
import chalk = require('chalk');
|
||||
import type {Config} from '@jest/types';
|
||||
import {TestPathPatterns, isNonNullable} from 'jest-util';
|
||||
import {isNonNullable} from 'jest-util';
|
||||
|
||||
const activeFilters = (globalConfig: Config.GlobalConfig): string => {
|
||||
const {testNamePattern} = globalConfig;
|
||||
const testPathPatterns = TestPathPatterns.fromGlobalConfig(globalConfig);
|
||||
const testPathPatterns = globalConfig.testPathPatterns;
|
||||
if (testNamePattern || testPathPatterns.isSet()) {
|
||||
const filters = [
|
||||
testPathPatterns.isSet()
|
||||
|
|
|
@ -17,7 +17,10 @@ export default function logDebugMessages(
|
|||
): void {
|
||||
const output = {
|
||||
configs,
|
||||
globalConfig,
|
||||
globalConfig: {
|
||||
...globalConfig,
|
||||
testPathPatterns: globalConfig.testPathPatterns.patterns,
|
||||
},
|
||||
version: VERSION,
|
||||
};
|
||||
outputStream.write(`${JSON.stringify(output, null, ' ')}\n`);
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {TestPathPatterns} from '@jest/pattern';
|
||||
import type {Config} from '@jest/types';
|
||||
import {TestPathPatterns} from 'jest-util';
|
||||
import type {AllowedConfigOptions} from 'jest-watcher';
|
||||
|
||||
type ExtraConfigOptions = Partial<
|
||||
|
@ -32,13 +32,13 @@ export default function updateGlobalConfig(
|
|||
}
|
||||
|
||||
if (options.testPathPatterns !== undefined) {
|
||||
newConfig.testPathPatterns = options.testPathPatterns;
|
||||
newConfig.testPathPatterns = new TestPathPatterns(options.testPathPatterns);
|
||||
}
|
||||
|
||||
newConfig.onlyChanged =
|
||||
!newConfig.watchAll &&
|
||||
!newConfig.testNamePattern &&
|
||||
!TestPathPatterns.fromGlobalConfig(newConfig).isSet();
|
||||
!newConfig.testPathPatterns.isSet();
|
||||
|
||||
if (typeof options.bail === 'boolean') {
|
||||
newConfig.bail = options.bail ? 1 : 0;
|
||||
|
|
|
@ -49,7 +49,10 @@ class TestPathPatternPlugin extends BaseWatchPlugin {
|
|||
|
||||
testPathPatternPrompt.run(
|
||||
(value: string) => {
|
||||
updateConfigAndRun({mode: 'watch', testPathPatterns: [value]});
|
||||
updateConfigAndRun({
|
||||
mode: 'watch',
|
||||
testPathPatterns: [value],
|
||||
});
|
||||
resolve();
|
||||
},
|
||||
reject,
|
||||
|
|
|
@ -38,13 +38,19 @@ import type {Filter, TestRunData} from './types';
|
|||
|
||||
const getTestPaths = async (
|
||||
globalConfig: Config.GlobalConfig,
|
||||
projectConfig: Config.ProjectConfig,
|
||||
source: SearchSource,
|
||||
outputStream: WriteStream,
|
||||
changedFiles: ChangedFiles | undefined,
|
||||
jestHooks: JestHookEmitter,
|
||||
filter?: Filter,
|
||||
) => {
|
||||
const data = await source.getTestPaths(globalConfig, changedFiles, filter);
|
||||
const data = await source.getTestPaths(
|
||||
globalConfig,
|
||||
projectConfig,
|
||||
changedFiles,
|
||||
filter,
|
||||
);
|
||||
|
||||
if (data.tests.length === 0 && globalConfig.onlyChanged && data.noSCM) {
|
||||
new CustomConsole(outputStream, outputStream).log(
|
||||
|
@ -188,6 +194,7 @@ export default async function runJest({
|
|||
const searchSource = searchSources[index];
|
||||
const matches = await getTestPaths(
|
||||
globalConfig,
|
||||
context.config,
|
||||
searchSource,
|
||||
outputStream,
|
||||
changedFilesPromise && (await changedFilesPromise),
|
||||
|
|
|
@ -11,12 +11,12 @@ import ansiEscapes = require('ansi-escapes');
|
|||
import chalk = require('chalk');
|
||||
import exit = require('exit');
|
||||
import slash = require('slash');
|
||||
import {TestPathPatterns} from '@jest/pattern';
|
||||
import type {TestContext} from '@jest/test-result';
|
||||
import type {Config} from '@jest/types';
|
||||
import type {IHasteMap as HasteMap} from 'jest-haste-map';
|
||||
import {formatExecError} from 'jest-message-util';
|
||||
import {
|
||||
TestPathPatterns,
|
||||
isInteractive,
|
||||
preRunMessage,
|
||||
requireOrImportModule,
|
||||
|
@ -230,11 +230,14 @@ export default async function watch(
|
|||
|
||||
const emitFileChange = () => {
|
||||
if (hooks.isUsed('onFileChange')) {
|
||||
const testPathPatterns = new TestPathPatterns([], globalConfig);
|
||||
const projects = searchSources.map(({context, searchSource}) => ({
|
||||
config: context.config,
|
||||
testPaths: searchSource
|
||||
.findMatchingTests(testPathPatterns)
|
||||
.findMatchingTests(
|
||||
new TestPathPatterns([]).toExecutor({
|
||||
rootDir: context.config.rootDir,
|
||||
}),
|
||||
)
|
||||
.tests.map(t => t.path),
|
||||
}));
|
||||
hooks.getEmitter().onFileChange({projects});
|
||||
|
@ -533,7 +536,7 @@ const usage = (
|
|||
watchPlugins: Array<WatchPlugin>,
|
||||
delimiter = '\n',
|
||||
) => {
|
||||
const testPathPatterns = TestPathPatterns.fromGlobalConfig(globalConfig);
|
||||
const testPathPatterns = globalConfig.testPathPatterns;
|
||||
const messages = [
|
||||
activeFilters(globalConfig),
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
{"path": "../jest-console"},
|
||||
{"path": "../jest-haste-map"},
|
||||
{"path": "../jest-message-util"},
|
||||
{"path": "../jest-pattern"},
|
||||
{"path": "../jest-regex-util"},
|
||||
{"path": "../jest-reporters"},
|
||||
{"path": "../jest-resolve"},
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
# @jest/pattern
|
||||
|
||||
`@jest/pattern` is a helper library for the jest library that implements the logic for parsing and matching patterns.
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"name": "@jest/pattern",
|
||||
"version": "30.0.0-alpha.4",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/jestjs/jest.git",
|
||||
"directory": "packages/jest-pattern"
|
||||
},
|
||||
"license": "MIT",
|
||||
"main": "./build/index.js",
|
||||
"types": "./build/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./build/index.d.ts",
|
||||
"require": "./build/index.js",
|
||||
"import": "./build/index.mjs",
|
||||
"default": "./build/index.js"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"jest-regex-util": "workspace:*"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.10.0 || ^18.12.0 || >=20.0.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
|
@ -5,42 +5,83 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import type {Config} from '@jest/types';
|
||||
import {escapePathForRegex, replacePathSepForRegex} from 'jest-regex-util';
|
||||
|
||||
type PatternsConfig = {
|
||||
export class TestPathPatterns {
|
||||
constructor(readonly patterns: Array<string>) {}
|
||||
|
||||
/**
|
||||
* Return true if there are any patterns.
|
||||
*/
|
||||
isSet(): boolean {
|
||||
return this.patterns.length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the patterns are valid.
|
||||
*/
|
||||
isValid(): boolean {
|
||||
return this.toExecutor({
|
||||
// isValid() doesn't require rootDir to be accurate, so just
|
||||
// specify a dummy rootDir here
|
||||
rootDir: '/',
|
||||
}).isValid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a human-friendly version of the pattern regex.
|
||||
*/
|
||||
toPretty(): string {
|
||||
return this.patterns.join('|');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a TestPathPatternsExecutor that can execute the patterns.
|
||||
*/
|
||||
toExecutor(
|
||||
options: TestPathPatternsExecutorOptions,
|
||||
): TestPathPatternsExecutor {
|
||||
return new TestPathPatternsExecutor(this, options);
|
||||
}
|
||||
|
||||
/** For jest serializers */
|
||||
toJSON(): any {
|
||||
return {
|
||||
patterns: this.patterns,
|
||||
type: 'TestPathPatterns',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export type TestPathPatternsExecutorOptions = {
|
||||
rootDir: string;
|
||||
};
|
||||
|
||||
export default class TestPathPatterns {
|
||||
export class TestPathPatternsExecutor {
|
||||
private _regexString: string | null = null;
|
||||
|
||||
constructor(
|
||||
readonly patterns: Array<string>,
|
||||
private readonly config: PatternsConfig,
|
||||
readonly patterns: TestPathPatterns,
|
||||
private readonly options: TestPathPatternsExecutorOptions,
|
||||
) {}
|
||||
|
||||
static fromGlobalConfig(globalConfig: Config.GlobalConfig): TestPathPatterns {
|
||||
return new TestPathPatterns(globalConfig.testPathPatterns, globalConfig);
|
||||
}
|
||||
|
||||
private get regexString(): string {
|
||||
if (this._regexString !== null) {
|
||||
return this._regexString;
|
||||
}
|
||||
|
||||
const rootDir = this.config.rootDir.replace(/\/*$/, '/');
|
||||
const rootDir = this.options.rootDir.replace(/\/*$/, '/');
|
||||
const rootDirRegex = escapePathForRegex(rootDir);
|
||||
|
||||
const regexString = this.patterns
|
||||
const regexString = this.patterns.patterns
|
||||
.map(p => {
|
||||
// absolute paths passed on command line should stay same
|
||||
if (/^\//.test(p)) {
|
||||
if (p.startsWith('/')) {
|
||||
return p;
|
||||
}
|
||||
|
||||
// explicit relative paths should resolve against rootDir
|
||||
if (/^\.\//.test(p)) {
|
||||
if (p.startsWith('./')) {
|
||||
return p.replace(/^\.\//, rootDirRegex);
|
||||
}
|
||||
|
||||
|
@ -62,14 +103,19 @@ export default class TestPathPatterns {
|
|||
* Return true if there are any patterns.
|
||||
*/
|
||||
isSet(): boolean {
|
||||
return this.patterns.length > 0;
|
||||
return this.patterns.isSet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw an error if the patterns don't form a valid regex.
|
||||
* Return true if the patterns are valid.
|
||||
*/
|
||||
validate(): void {
|
||||
this.toRegex();
|
||||
isValid(): boolean {
|
||||
try {
|
||||
this.toRegex();
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -85,6 +131,6 @@ export default class TestPathPatterns {
|
|||
* Return a human-friendly version of the pattern regex.
|
||||
*/
|
||||
toPretty(): string {
|
||||
return this.patterns.join('|');
|
||||
return this.patterns.toPretty();
|
||||
}
|
||||
}
|
|
@ -6,16 +6,20 @@
|
|||
*/
|
||||
|
||||
import type * as path from 'path';
|
||||
import TestPathPatterns from '../TestPathPatterns';
|
||||
import {
|
||||
TestPathPatterns,
|
||||
TestPathPatternsExecutor,
|
||||
type TestPathPatternsExecutorOptions,
|
||||
} from '../TestPathPatterns';
|
||||
|
||||
const mockSep = jest.fn();
|
||||
const mockSep: jest.Mock<() => string> = jest.fn();
|
||||
jest.mock('path', () => {
|
||||
return {
|
||||
...(jest.requireActual('path') as typeof path),
|
||||
...jest.requireActual('path'),
|
||||
get sep() {
|
||||
return mockSep() || '/';
|
||||
},
|
||||
};
|
||||
} as typeof path;
|
||||
});
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
|
@ -23,88 +27,117 @@ beforeEach(() => {
|
|||
|
||||
const config = {rootDir: ''};
|
||||
|
||||
describe('TestPathPatterns', () => {
|
||||
interface TestPathPatternsLike {
|
||||
isSet(): boolean;
|
||||
isValid(): boolean;
|
||||
toPretty(): string;
|
||||
}
|
||||
|
||||
const testPathPatternsLikeTests = (
|
||||
makePatterns: (
|
||||
patterns: Array<string>,
|
||||
options: TestPathPatternsExecutorOptions,
|
||||
) => TestPathPatternsLike,
|
||||
) => {
|
||||
describe('isSet', () => {
|
||||
it('returns false if no patterns specified', () => {
|
||||
const testPathPatterns = new TestPathPatterns([], config);
|
||||
const testPathPatterns = makePatterns([], config);
|
||||
expect(testPathPatterns.isSet()).toBe(false);
|
||||
});
|
||||
|
||||
it('returns true if patterns specified', () => {
|
||||
const testPathPatterns = new TestPathPatterns(['a'], config);
|
||||
const testPathPatterns = makePatterns(['a'], config);
|
||||
expect(testPathPatterns.isSet()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('validate', () => {
|
||||
describe('isValid', () => {
|
||||
it('succeeds for empty patterns', () => {
|
||||
const testPathPatterns = new TestPathPatterns([], config);
|
||||
expect(() => testPathPatterns.validate()).not.toThrow();
|
||||
const testPathPatterns = makePatterns([], config);
|
||||
expect(testPathPatterns.isValid()).toBe(true);
|
||||
});
|
||||
|
||||
it('succeeds for valid patterns', () => {
|
||||
const testPathPatterns = new TestPathPatterns(['abc+', 'z.*'], config);
|
||||
expect(() => testPathPatterns.validate()).not.toThrow();
|
||||
const testPathPatterns = makePatterns(['abc+', 'z.*'], config);
|
||||
expect(testPathPatterns.isValid()).toBe(true);
|
||||
});
|
||||
|
||||
it('fails for at least one invalid pattern', () => {
|
||||
const testPathPatterns = new TestPathPatterns(
|
||||
['abc+', '(', 'z.*'],
|
||||
config,
|
||||
);
|
||||
expect(() => testPathPatterns.validate()).toThrow(
|
||||
'Invalid regular expression',
|
||||
);
|
||||
const testPathPatterns = makePatterns(['abc+', '(', 'z.*'], config);
|
||||
expect(testPathPatterns.isValid()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('toPretty', () => {
|
||||
it('renders a human-readable string', () => {
|
||||
const testPathPatterns = makePatterns(['a/b', 'c/d'], config);
|
||||
expect(testPathPatterns.toPretty()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
describe('TestPathPatterns', () => {
|
||||
testPathPatternsLikeTests(
|
||||
(patterns: Array<string>, _: TestPathPatternsExecutorOptions) =>
|
||||
new TestPathPatterns(patterns),
|
||||
);
|
||||
});
|
||||
|
||||
describe('TestPathPatternsExecutor', () => {
|
||||
const makeExecutor = (
|
||||
patterns: Array<string>,
|
||||
options: TestPathPatternsExecutorOptions,
|
||||
) => new TestPathPatternsExecutor(new TestPathPatterns(patterns), options);
|
||||
|
||||
testPathPatternsLikeTests(makeExecutor);
|
||||
|
||||
describe('isMatch', () => {
|
||||
it('returns true with no patterns', () => {
|
||||
const testPathPatterns = new TestPathPatterns([], config);
|
||||
const testPathPatterns = makeExecutor([], config);
|
||||
expect(testPathPatterns.isMatch('/a/b')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true for same path', () => {
|
||||
const testPathPatterns = new TestPathPatterns(['/a/b'], config);
|
||||
const testPathPatterns = makeExecutor(['/a/b'], config);
|
||||
expect(testPathPatterns.isMatch('/a/b')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true for same path with case insensitive', () => {
|
||||
const testPathPatternsUpper = new TestPathPatterns(['/A/B'], config);
|
||||
const testPathPatternsUpper = makeExecutor(['/A/B'], config);
|
||||
expect(testPathPatternsUpper.isMatch('/a/b')).toBe(true);
|
||||
expect(testPathPatternsUpper.isMatch('/A/B')).toBe(true);
|
||||
|
||||
const testPathPatternsLower = new TestPathPatterns(['/a/b'], config);
|
||||
const testPathPatternsLower = makeExecutor(['/a/b'], config);
|
||||
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'], config);
|
||||
const testPathPatterns = makeExecutor(['b/c'], config);
|
||||
expect(testPathPatterns.isMatch('/a/b/c/d')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true for explicit relative path', () => {
|
||||
const testPathPatterns = new TestPathPatterns(['./b/c'], {
|
||||
const testPathPatterns = makeExecutor(['./b/c'], {
|
||||
rootDir: '/a',
|
||||
});
|
||||
expect(testPathPatterns.isMatch('/a/b/c')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true for partial file match', () => {
|
||||
const testPathPatterns = new TestPathPatterns(['aaa'], config);
|
||||
const testPathPatterns = makeExecutor(['aaa'], config);
|
||||
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'], config);
|
||||
const testPathPatterns = makeExecutor(['c/d'], config);
|
||||
expect(testPathPatterns.isMatch('/a/b/c/d')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true if regex matches', () => {
|
||||
const testPathPatterns = new TestPathPatterns(['ab*c?'], config);
|
||||
const testPathPatterns = makeExecutor(['ab*c?'], config);
|
||||
|
||||
expect(testPathPatterns.isMatch('/foo/a')).toBe(true);
|
||||
expect(testPathPatterns.isMatch('/foo/ab')).toBe(true);
|
||||
|
@ -117,7 +150,7 @@ describe('TestPathPatterns', () => {
|
|||
});
|
||||
|
||||
it('returns true only if matches relative path', () => {
|
||||
const testPathPatterns = new TestPathPatterns(['home'], {
|
||||
const testPathPatterns = makeExecutor(['home'], {
|
||||
rootDir: '/home/myuser/',
|
||||
});
|
||||
expect(testPathPatterns.isMatch('/home/myuser/LoginPage.js')).toBe(false);
|
||||
|
@ -125,14 +158,14 @@ describe('TestPathPatterns', () => {
|
|||
});
|
||||
|
||||
it('matches absolute paths regardless of rootDir', () => {
|
||||
const testPathPatterns = new TestPathPatterns(['/a/b'], {
|
||||
const testPathPatterns = makeExecutor(['/a/b'], {
|
||||
rootDir: '/foo/bar',
|
||||
});
|
||||
expect(testPathPatterns.isMatch('/a/b')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true if match any paths', () => {
|
||||
const testPathPatterns = new TestPathPatterns(['a/b', 'c/d'], config);
|
||||
const testPathPatterns = makeExecutor(['a/b', 'c/d'], config);
|
||||
|
||||
expect(testPathPatterns.isMatch('/foo/a/b')).toBe(true);
|
||||
expect(testPathPatterns.isMatch('/foo/c/d')).toBe(true);
|
||||
|
@ -143,21 +176,14 @@ describe('TestPathPatterns', () => {
|
|||
|
||||
it('does not normalize Windows paths on POSIX', () => {
|
||||
mockSep.mockReturnValue('/');
|
||||
const testPathPatterns = new TestPathPatterns(['a\\z', 'a\\\\z'], config);
|
||||
const testPathPatterns = makeExecutor(['a\\z', 'a\\\\z'], config);
|
||||
expect(testPathPatterns.isMatch('/foo/a/z')).toBe(false);
|
||||
});
|
||||
|
||||
it('normalizes paths for Windows', () => {
|
||||
mockSep.mockReturnValue('\\');
|
||||
const testPathPatterns = new TestPathPatterns(['a/b'], config);
|
||||
const testPathPatterns = makeExecutor(['a/b'], config);
|
||||
expect(testPathPatterns.isMatch('\\foo\\a\\b')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('toPretty', () => {
|
||||
it('renders a human-readable string', () => {
|
||||
const testPathPatterns = new TestPathPatterns(['a/b', 'c/d'], config);
|
||||
expect(testPathPatterns.toPretty()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,3 +1,5 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`TestPathPatterns toPretty renders a human-readable string 1`] = `"a/b|c/d"`;
|
||||
|
||||
exports[`TestPathPatternsExecutor toPretty renders a human-readable string 1`] = `"a/b|c/d"`;
|
|
@ -0,0 +1,12 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export {
|
||||
TestPathPatterns,
|
||||
TestPathPatternsExecutor,
|
||||
type TestPathPatternsExecutorOptions,
|
||||
} from './TestPathPatterns';
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "build"
|
||||
},
|
||||
"include": ["./src/**/*"],
|
||||
"exclude": ["./**/__tests__/**/*"],
|
||||
"references": [{"path": "../jest-regex-util"}]
|
||||
}
|
|
@ -40,6 +40,7 @@
|
|||
"v8-to-istanbul": "^9.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@jest/pattern": "workspace:*",
|
||||
"@jest/test-utils": "workspace:*",
|
||||
"@types/exit": "^0.1.30",
|
||||
"@types/graceful-fs": "^4.1.3",
|
||||
|
|
|
@ -12,7 +12,6 @@ import type {
|
|||
TestContext,
|
||||
} from '@jest/test-result';
|
||||
import type {Config} from '@jest/types';
|
||||
import {TestPathPatterns} from 'jest-util';
|
||||
import BaseReporter from './BaseReporter';
|
||||
import getResultHeader from './getResultHeader';
|
||||
import getSnapshotSummary from './getSnapshotSummary';
|
||||
|
@ -212,7 +211,7 @@ export default class SummaryReporter extends BaseReporter {
|
|||
testContexts: Set<TestContext>,
|
||||
globalConfig: Config.GlobalConfig,
|
||||
) {
|
||||
const testPathPatterns = TestPathPatterns.fromGlobalConfig(globalConfig);
|
||||
const testPathPatterns = globalConfig.testPathPatterns;
|
||||
|
||||
const getMatchingTestsInfo = () => {
|
||||
const prefix = globalConfig.findRelatedTests
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
*/
|
||||
'use strict';
|
||||
|
||||
import {TestPathPatterns} from '@jest/pattern';
|
||||
|
||||
let SummaryReporter;
|
||||
|
||||
const env = {...process.env};
|
||||
|
@ -13,7 +15,7 @@ const now = Date.now;
|
|||
const write = process.stderr.write;
|
||||
const globalConfig = {
|
||||
rootDir: 'root',
|
||||
testPathPatterns: [],
|
||||
testPathPatterns: new TestPathPatterns([]),
|
||||
watch: false,
|
||||
};
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
"references": [
|
||||
{"path": "../jest-console"},
|
||||
{"path": "../jest-message-util"},
|
||||
{"path": "../jest-pattern"},
|
||||
{"path": "../jest-resolve"},
|
||||
{"path": "../jest-test-result"},
|
||||
{"path": "../jest-transform"},
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
"./package.json": "./package.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jest/pattern": "workspace:*",
|
||||
"@jest/schemas": "workspace:*",
|
||||
"@types/istanbul-lib-coverage": "^2.0.0",
|
||||
"@types/istanbul-reports": "^3.0.0",
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
import type {ForegroundColor} from 'chalk';
|
||||
import type {ReportOptions} from 'istanbul-reports';
|
||||
import type {Arguments} from 'yargs';
|
||||
import type {TestPathPatterns} from '@jest/pattern';
|
||||
import type {InitialOptions, SnapshotFormat} from '@jest/schemas';
|
||||
|
||||
export type {InitialOptions} from '@jest/schemas';
|
||||
|
@ -305,7 +306,7 @@ export type GlobalConfig = {
|
|||
errorOnDeprecated: boolean;
|
||||
testFailureExitCode: number;
|
||||
testNamePattern?: string;
|
||||
testPathPatterns: Array<string>;
|
||||
testPathPatterns: TestPathPatterns;
|
||||
testResultsProcessor?: string;
|
||||
testSequencer: string;
|
||||
testTimeout?: number;
|
||||
|
|
|
@ -5,5 +5,5 @@
|
|||
"outDir": "build"
|
||||
},
|
||||
"include": ["./src/**/*"],
|
||||
"references": [{"path": "../jest-schemas"}]
|
||||
"references": [{"path": "../jest-pattern"}, {"path": "../jest-schemas"}]
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
"chalk": "^4.0.0",
|
||||
"ci-info": "^4.0.0",
|
||||
"graceful-fs": "^4.2.9",
|
||||
"jest-regex-util": "workspace:*",
|
||||
"picomatch": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -21,7 +21,6 @@ export {default as deepCyclicCopy} from './deepCyclicCopy';
|
|||
export {default as convertDescriptorToString} from './convertDescriptorToString';
|
||||
export {specialChars};
|
||||
export {default as replacePathSepForGlob} from './replacePathSepForGlob';
|
||||
export {default as TestPathPatterns} from './TestPathPatterns';
|
||||
export {default as globsToMatcher} from './globsToMatcher';
|
||||
export {preRunMessage};
|
||||
export {default as pluralize} from './pluralize';
|
||||
|
|
|
@ -6,5 +6,5 @@
|
|||
},
|
||||
"include": ["./src/**/*"],
|
||||
"exclude": ["./**/__tests__/**/*"],
|
||||
"references": [{"path": "../jest-regex-util"}, {"path": "../jest-types"}]
|
||||
"references": [{"path": "../jest-types"}]
|
||||
}
|
||||
|
|
|
@ -63,10 +63,12 @@ export type AllowedConfigOptions = Partial<
|
|||
| 'onlyFailures'
|
||||
| 'reporters'
|
||||
| 'testNamePattern'
|
||||
| 'testPathPatterns'
|
||||
| 'updateSnapshot'
|
||||
| 'verbose'
|
||||
> & {mode: 'watch' | 'watchAll'}
|
||||
> & {
|
||||
mode: 'watch' | 'watchAll';
|
||||
testPathPatterns: Array<string>;
|
||||
}
|
||||
>;
|
||||
|
||||
export type UpdateConfigCallback = (config?: AllowedConfigOptions) => void;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@jest/globals": "workspace:*",
|
||||
"@jest/pattern": "workspace:*",
|
||||
"@jest/types": "workspace:*",
|
||||
"@types/node": "*",
|
||||
"ansi-regex": "^5.0.1",
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {TestPathPatterns} from '@jest/pattern';
|
||||
import type {Config} from '@jest/types';
|
||||
|
||||
const DEFAULT_GLOBAL_CONFIG: Config.GlobalConfig = {
|
||||
|
@ -55,7 +56,7 @@ const DEFAULT_GLOBAL_CONFIG: Config.GlobalConfig = {
|
|||
snapshotFormat: {},
|
||||
testFailureExitCode: 1,
|
||||
testNamePattern: '',
|
||||
testPathPatterns: [],
|
||||
testPathPatterns: new TestPathPatterns([]),
|
||||
testResultsProcessor: undefined,
|
||||
testSequencer: '@jest/test-sequencer',
|
||||
testTimeout: 5000,
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
"include": ["./src/**/*"],
|
||||
"references": [
|
||||
{"path": "../jest-globals"},
|
||||
{"path": "../jest-pattern"},
|
||||
{"path": "../jest-types"},
|
||||
{"path": "../pretty-format"}
|
||||
]
|
||||
|
|
|
@ -50,6 +50,7 @@ const packagesNotToTest = [
|
|||
'jest-matcher-utils',
|
||||
'jest-message-util',
|
||||
'jest-mock',
|
||||
'jest-pattern',
|
||||
'jest-phabricator',
|
||||
'jest-regex-util',
|
||||
'jest-repl',
|
||||
|
|
15
yarn.lock
15
yarn.lock
|
@ -2890,6 +2890,7 @@ __metadata:
|
|||
resolution: "@jest/core@workspace:packages/jest-core"
|
||||
dependencies:
|
||||
"@jest/console": "workspace:*"
|
||||
"@jest/pattern": "workspace:*"
|
||||
"@jest/reporters": "workspace:*"
|
||||
"@jest/test-result": "workspace:*"
|
||||
"@jest/test-sequencer": "workspace:*"
|
||||
|
@ -3113,12 +3114,22 @@ __metadata:
|
|||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@jest/pattern@workspace:*, @jest/pattern@workspace:packages/jest-pattern":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@jest/pattern@workspace:packages/jest-pattern"
|
||||
dependencies:
|
||||
"@types/node": "*"
|
||||
jest-regex-util: "workspace:*"
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@jest/reporters@workspace:*, @jest/reporters@workspace:packages/jest-reporters":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@jest/reporters@workspace:packages/jest-reporters"
|
||||
dependencies:
|
||||
"@bcoe/v8-coverage": ^0.2.3
|
||||
"@jest/console": "workspace:*"
|
||||
"@jest/pattern": "workspace:*"
|
||||
"@jest/test-result": "workspace:*"
|
||||
"@jest/test-utils": "workspace:*"
|
||||
"@jest/transform": "workspace:*"
|
||||
|
@ -3256,6 +3267,7 @@ __metadata:
|
|||
resolution: "@jest/test-utils@workspace:packages/test-utils"
|
||||
dependencies:
|
||||
"@jest/globals": "workspace:*"
|
||||
"@jest/pattern": "workspace:*"
|
||||
"@jest/types": "workspace:*"
|
||||
"@types/node": "*"
|
||||
"@types/semver": ^7.1.0
|
||||
|
@ -3326,6 +3338,7 @@ __metadata:
|
|||
version: 0.0.0-use.local
|
||||
resolution: "@jest/types@workspace:packages/jest-types"
|
||||
dependencies:
|
||||
"@jest/pattern": "workspace:*"
|
||||
"@jest/schemas": "workspace:*"
|
||||
"@types/istanbul-lib-coverage": ^2.0.0
|
||||
"@types/istanbul-reports": ^3.0.0
|
||||
|
@ -12755,6 +12768,7 @@ __metadata:
|
|||
resolution: "jest-config@workspace:packages/jest-config"
|
||||
dependencies:
|
||||
"@babel/core": ^7.11.6
|
||||
"@jest/pattern": "workspace:*"
|
||||
"@jest/test-sequencer": "workspace:*"
|
||||
"@jest/types": "workspace:*"
|
||||
"@types/graceful-fs": ^4.1.3
|
||||
|
@ -13257,7 +13271,6 @@ __metadata:
|
|||
chalk: ^4.0.0
|
||||
ci-info: ^4.0.0
|
||||
graceful-fs: ^4.2.9
|
||||
jest-regex-util: "workspace:*"
|
||||
picomatch: ^4.0.0
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
|
Loading…
Reference in New Issue