From fc9bc4f1d172c72012ac44fcb46115f9999c5ff4 Mon Sep 17 00:00:00 2001 From: TrickyPi <530257315@qq.com> Date: Mon, 28 Feb 2022 13:10:01 +0800 Subject: [PATCH] feat(jest-config): Throw an error instead of showing a warning if multiple configs are used --- CHANGELOG.md | 1 + .../src/__tests__/resolveConfigPath.test.ts | 70 +++++++------------ packages/jest-config/src/index.ts | 6 +- packages/jest-config/src/resolveConfigPath.ts | 44 ++++++------ 4 files changed, 51 insertions(+), 70 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1f622dc41e6..1a4dcedbd1ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Features +- `[jest-config]` Throw an error instead of showing a warning if multiple configs are used ([#12506](https://github.com/facebook/jest/pull/12506)) - `[babel-jest]` Export `createTransformer` function ([#12399](https://github.com/facebook/jest/pull/12399)) - `[expect]` Expose `AsymmetricMatchers`, `MatcherFunction` and `MatcherFunctionWithState` interfaces ([#12363](https://github.com/facebook/jest/pull/12363), [#12376](https://github.com/facebook/jest/pull/12376)) - `[jest-circus, jest-jasmine2]` Allowed classes and functions as `describe` and `it`/`test` names ([#12484](https://github.com/facebook/jest/pull/12484)) diff --git a/packages/jest-config/src/__tests__/resolveConfigPath.test.ts b/packages/jest-config/src/__tests__/resolveConfigPath.test.ts index 96db06c9213b..e9b7f985b70d 100644 --- a/packages/jest-config/src/__tests__/resolveConfigPath.test.ts +++ b/packages/jest-config/src/__tests__/resolveConfigPath.test.ts @@ -16,16 +16,6 @@ const ERROR_PATTERN = /Could not find a config file based on provided values/; const NO_ROOT_DIR_ERROR_PATTERN = /Can't find a root directory/; const MULTIPLE_CONFIGS_ERROR_PATTERN = /Multiple configurations found/; -const mockConsoleWarn = () => { - jest.spyOn(console, 'warn'); - const mockedConsoleWarn = console.warn as jest.Mock>; - - // We will mock console.warn because it would produce a lot of noise in the tests - mockedConsoleWarn.mockImplementation(() => {}); - - return mockedConsoleWarn; -}; - beforeEach(() => cleanup(DIR)); afterEach(() => cleanup(DIR)); @@ -56,8 +46,6 @@ describe.each(JEST_CONFIG_EXT_ORDER.slice(0))( }); test(`directory path with "${extension}"`, () => { - const mockedConsoleWarn = mockConsoleWarn(); - const relativePackageJsonPath = 'a/b/c/package.json'; const absolutePackageJsonPath = path.resolve( DIR, @@ -81,7 +69,6 @@ describe.each(JEST_CONFIG_EXT_ORDER.slice(0))( writeFiles(DIR, {[relativePackageJsonPath]: ''}); - mockedConsoleWarn.mockClear(); // absolute expect( resolveConfigPath(path.dirname(absolutePackageJsonPath), DIR), @@ -91,12 +78,10 @@ describe.each(JEST_CONFIG_EXT_ORDER.slice(0))( expect( resolveConfigPath(path.dirname(relativePackageJsonPath), DIR), ).toBe(absolutePackageJsonPath); - expect(mockedConsoleWarn).not.toBeCalled(); // jest.config.js takes precedence writeFiles(DIR, {[relativeJestConfigPath]: ''}); - mockedConsoleWarn.mockClear(); // absolute expect( resolveConfigPath(path.dirname(absolutePackageJsonPath), DIR), @@ -106,30 +91,19 @@ describe.each(JEST_CONFIG_EXT_ORDER.slice(0))( expect( resolveConfigPath(path.dirname(relativePackageJsonPath), DIR), ).toBe(absoluteJestConfigPath); - expect(mockedConsoleWarn).not.toBeCalled(); // jest.config.js and package.json with 'jest' cannot be used together writeFiles(DIR, {[relativePackageJsonPath]: JSON.stringify({jest: {}})}); // absolute - mockedConsoleWarn.mockClear(); - expect( + expect(() => resolveConfigPath(path.dirname(absolutePackageJsonPath), DIR), - ).toBe(absoluteJestConfigPath); - expect(mockedConsoleWarn).toBeCalledTimes(1); - expect(mockedConsoleWarn.mock.calls[0].join()).toMatch( - MULTIPLE_CONFIGS_ERROR_PATTERN, - ); + ).toThrowError(MULTIPLE_CONFIGS_ERROR_PATTERN); // relative - mockedConsoleWarn.mockClear(); - expect( + expect(() => resolveConfigPath(path.dirname(relativePackageJsonPath), DIR), - ).toBe(absoluteJestConfigPath); - expect(mockedConsoleWarn).toBeCalledTimes(1); - expect(mockedConsoleWarn.mock.calls[0].join()).toMatch( - MULTIPLE_CONFIGS_ERROR_PATTERN, - ); + ).toThrowError(MULTIPLE_CONFIGS_ERROR_PATTERN); expect(() => { resolveConfigPath( @@ -146,8 +120,7 @@ const pickPairsWithSameOrder = (array: ReadonlyArray) => .map((value1, idx, arr) => arr.slice(idx + 1).map(value2 => [value1, value2]), ) - // TODO: use .flat() when we drop Node 10 - .reduce((acc, val) => acc.concat(val), []); + .flat(); test('pickPairsWithSameOrder', () => { expect(pickPairsWithSameOrder([1, 2, 3])).toStrictEqual([ @@ -158,11 +131,9 @@ test('pickPairsWithSameOrder', () => { }); describe.each(pickPairsWithSameOrder(JEST_CONFIG_EXT_ORDER))( - 'Using multiple configs shows warning', + 'Using multiple configs shows error', (extension1, extension2) => { - test(`Using jest.config${extension1} and jest.config${extension2} shows warning`, () => { - const mockedConsoleWarn = mockConsoleWarn(); - + test(`Using jest.config${extension1} and jest.config${extension2} shows error`, () => { const relativeJestConfigPaths = [ `a/b/c/jest.config${extension1}`, `a/b/c/jest.config${extension2}`, @@ -173,15 +144,26 @@ describe.each(pickPairsWithSameOrder(JEST_CONFIG_EXT_ORDER))( [relativeJestConfigPaths[1]]: '', }); - // multiple configs here, should print warning - mockedConsoleWarn.mockClear(); - expect( + expect(() => resolveConfigPath(path.dirname(relativeJestConfigPaths[0]), DIR), - ).toBe(path.resolve(DIR, relativeJestConfigPaths[0])); - expect(mockedConsoleWarn).toBeCalledTimes(1); - expect(mockedConsoleWarn.mock.calls[0].join()).toMatch( - MULTIPLE_CONFIGS_ERROR_PATTERN, - ); + ).toThrowError(MULTIPLE_CONFIGS_ERROR_PATTERN); }); }, ); + +test('skip multiple config error, if skipMultipleConfigError is true', () => { + const [extension1, extension2] = JEST_CONFIG_EXT_ORDER; + const relativeJestConfigPaths = [ + `a/b/c/jest.config${extension1}`, + `a/b/c/jest.config${extension2}`, + ]; + + writeFiles(DIR, { + [relativeJestConfigPaths[0]]: '', + [relativeJestConfigPaths[1]]: '', + }); + + expect( + resolveConfigPath(path.dirname(relativeJestConfigPaths[0]), DIR, true), + ).toBe(path.resolve(DIR, relativeJestConfigPaths[0])); +}); diff --git a/packages/jest-config/src/index.ts b/packages/jest-config/src/index.ts index 1146e84b11b5..1e1448bdf285 100644 --- a/packages/jest-config/src/index.ts +++ b/packages/jest-config/src/index.ts @@ -41,7 +41,7 @@ export async function readConfig( skipArgvConfigOption?: boolean, parentConfigDirname?: string | null, projectIndex = Infinity, - skipMultipleConfigWarning = false, + skipMultipleConfigError = false, ): Promise { let rawOptions: Config.InitialOptions; let configPath = null; @@ -78,7 +78,7 @@ export async function readConfig( configPath = resolveConfigPath( argv.config, process.cwd(), - skipMultipleConfigWarning, + skipMultipleConfigError, ); rawOptions = await readConfigFileAndSetRootDir(configPath); } else { @@ -86,7 +86,7 @@ export async function readConfig( configPath = resolveConfigPath( packageRootOrConfig, process.cwd(), - skipMultipleConfigWarning, + skipMultipleConfigError, ); rawOptions = await readConfigFileAndSetRootDir(configPath); } diff --git a/packages/jest-config/src/resolveConfigPath.ts b/packages/jest-config/src/resolveConfigPath.ts index e513340fb5dd..80e90d2f852e 100644 --- a/packages/jest-config/src/resolveConfigPath.ts +++ b/packages/jest-config/src/resolveConfigPath.ts @@ -23,7 +23,7 @@ const getConfigFilename = (ext: string) => JEST_CONFIG_BASE_NAME + ext; export default function resolveConfigPath( pathToResolve: string, cwd: string, - skipMultipleConfigWarning = false, + skipMultipleConfigError = false, ): string { if (!path.isAbsolute(cwd)) { throw new Error(`"cwd" must be an absolute path. cwd: ${cwd}`); @@ -58,7 +58,7 @@ export default function resolveConfigPath( absolutePath, pathToResolve, cwd, - skipMultipleConfigWarning, + skipMultipleConfigError, ); } @@ -66,7 +66,7 @@ const resolveConfigPathByTraversing = ( pathToResolve: string, initialPath: string, cwd: string, - skipMultipleConfigWarning: boolean, + skipMultipleConfigError: boolean, ): string => { const configFiles = JEST_CONFIG_EXT_ORDER.map(ext => path.resolve(pathToResolve, getConfigFilename(ext)), @@ -77,8 +77,8 @@ const resolveConfigPathByTraversing = ( configFiles.push(packageJson); } - if (!skipMultipleConfigWarning && configFiles.length > 1) { - console.warn(makeMultipleConfigsWarning(configFiles)); + if (!skipMultipleConfigError && configFiles.length > 1) { + throw new Error(makeMultipleConfigsErrorMessage(configFiles)); } if (configFiles.length > 0 || packageJson) { @@ -96,7 +96,7 @@ const resolveConfigPathByTraversing = ( path.dirname(pathToResolve), initialPath, cwd, - skipMultipleConfigWarning, + skipMultipleConfigError, ); }; @@ -137,20 +137,18 @@ function extraIfPackageJson(configPath: string) { return ''; } -const makeMultipleConfigsWarning = (configPaths: Array) => - chalk.yellow( - [ - chalk.bold('\u25cf Multiple configurations found:'), - ...configPaths.map( - configPath => - ` * ${extraIfPackageJson(configPath)}${slash(configPath)}`, - ), - '', - ' Implicit config resolution does not allow multiple configuration files.', - ' Either remove unused config files or select one explicitly with `--config`.', - '', - ' Configuration Documentation:', - ' https://jestjs.io/docs/configuration.html', - '', - ].join('\n'), - ); +const makeMultipleConfigsErrorMessage = (configPaths: Array) => + [ + chalk.bold('\u25cf Multiple configurations found:'), + ...configPaths.map( + configPath => + ` * ${extraIfPackageJson(configPath)}${slash(configPath)}`, + ), + '', + ' Implicit config resolution does not allow multiple configuration files.', + ' Either remove unused config files or select one explicitly with `--config`.', + '', + ' Configuration Documentation:', + ' https://jestjs.io/docs/configuration.html', + '', + ].join('\n');