Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: warn when there are multiple configs #11922

Merged
merged 41 commits into from Oct 6, 2021
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
b85b26b
chore: throw when there are multiple configs
jankaifer Oct 2, 2021
4dff740
fix: allowed package.json without 'jest' as valid config
jankaifer Oct 2, 2021
227f7d4
test: unit test for multiple configs error in resolver
jankaifer Oct 2, 2021
a678d28
Apply suggestions from code review
jankaifer Oct 4, 2021
0f81fe4
test: fixed integration test
jankaifer Oct 4, 2021
b6ff8b8
tests: fixed config issues in old tests
jankaifer Oct 4, 2021
27fdaff
feat: multiple jest.config.ext files are not allowed
jankaifer Oct 4, 2021
0d15a1f
test: added e2e test for --config override
jankaifer Oct 4, 2021
eccf953
fix: more explicit expression
jankaifer Oct 5, 2021
3d71585
fix: added more real-life package.json example
jankaifer Oct 5, 2021
4cca511
Merge branch 'jankaifer/warn-multiple-configs-found' of github.com:Ja…
jankaifer Oct 5, 2021
752b1f9
test: added snapshot tests for multiple errors
jankaifer Oct 5, 2021
02b8ef2
test: moved snapshots from unit tests to e2e tests
jankaifer Oct 5, 2021
cd7c9c9
test: fixed rootDir replacements in snapshots
jankaifer Oct 5, 2021
9e13ff2
Apply suggestions from code review
jankaifer Oct 5, 2021
f30ab95
added missing import
jankaifer Oct 5, 2021
b931029
Change from CR
jankaifer Oct 5, 2021
f9c515e
improved error message
jankaifer Oct 5, 2021
3b1c5b8
added test for --config error surpresion
jankaifer Oct 5, 2021
02338fd
added more real life package.json
jankaifer Oct 5, 2021
2ce0401
added more assertions for multiple config errors
jankaifer Oct 5, 2021
ac00510
improved formatting of error message
jankaifer Oct 5, 2021
82d3e44
fixed sample jest configs in e2e tests
jankaifer Oct 5, 2021
db8c90c
wip: changed from error to warning
jankaifer Oct 5, 2021
ab05377
fixed unit tests for warning
jankaifer Oct 5, 2021
df0f3a5
updated snapshots
jankaifer Oct 5, 2021
1f17acc
Update CHANGELOG.md
SimenB Oct 6, 2021
2d6efff
Update packages/jest-config/src/resolveConfigPath.ts
jankaifer Oct 6, 2021
3682947
Merge branch 'main' into jankaifer/warn-multiple-configs-found
SimenB Oct 6, 2021
7727e74
add slash import
SimenB Oct 6, 2021
9926edf
no flat in node 10
SimenB Oct 6, 2021
91655ce
rename tests
SimenB Oct 6, 2021
d60356f
slash path in e2e test as well
SimenB Oct 6, 2021
6a52634
skip duplicate warning
SimenB Oct 6, 2021
3505a2c
add copyright header
SimenB Oct 6, 2021
80e52de
make warning yellow
SimenB Oct 6, 2021
8abb1c1
specify key in pkg.json
SimenB Oct 6, 2021
746f353
use wrap
SimenB Oct 6, 2021
cae826c
removed hardcoded filename
jankaifer Oct 6, 2021
1de582b
made skipMultipleConfigWarning optional
jankaifer Oct 6, 2021
b57cbf5
Update packages/jest-config/src/resolveConfigPath.ts
SimenB Oct 6, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 6 additions & 3 deletions e2e/Utils.ts
Expand Up @@ -176,20 +176,23 @@ interface JestPackageJson extends PackageJson {
}

const DEFAULT_PACKAGE_JSON: JestPackageJson = {
description: 'THIS IS AN AUTOGENERATED FILE AND SHOULD NOT BE ADDED TO GIT',
jest: {
testEnvironment: 'node',
},
};

export const createEmptyPackage = (
directory: Config.Path,
packageJson = DEFAULT_PACKAGE_JSON,
packageJson: PackageJson = DEFAULT_PACKAGE_JSON,
) => {
const packageJsonWithDefaults = {
...packageJson,
description: 'THIS IS AN AUTOGENERATED FILE AND SHOULD NOT BE ADDED TO GIT',
};
fs.mkdirSync(directory, {recursive: true});
fs.writeFileSync(
path.resolve(directory, 'package.json'),
JSON.stringify(packageJson, null, 2),
JSON.stringify(packageJsonWithDefaults, null, 2),
);
};

Expand Down
34 changes: 34 additions & 0 deletions e2e/__tests__/__snapshots__/multipleConfigs.ts.snap
@@ -0,0 +1,34 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`multiple configs will throw matching error 1`] = `
"● Multiple configurations found:
* <rootDir>/e2e/multiple-configs/jest.config.js
* <rootDir>/e2e/multiple-configs/jest.config.json
* <rootDir>/e2e/multiple-configs/package.json

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
● Multiple configurations found:
* <rootDir>/e2e/multiple-configs/jest.config.js
* <rootDir>/e2e/multiple-configs/jest.config.json
* <rootDir>/e2e/multiple-configs/package.json

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
PASS Config from js file __tests__/test.js
✓ dummy test"
`;

exports[`multiple configs will throw matching error 2`] = `
"Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: <<REPLACED>>
Ran all test suites."
`;
24 changes: 24 additions & 0 deletions e2e/__tests__/configOverride.test.ts
@@ -0,0 +1,24 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import {getConfig} from '../runJest';

test('reads config from cjs file', () => {
SimenB marked this conversation as resolved.
Show resolved Hide resolved
const {configs} = getConfig(
'config-override',
['--config', 'different-config.json'],
{
skipPkgJsonCheck: true,
},
);

expect(configs).toHaveLength(1);
expect(configs[0].displayName).toEqual({
color: 'white',
name: 'Config from different-config.json file',
});
});
2 changes: 1 addition & 1 deletion e2e/__tests__/dependencyClash.test.ts
Expand Up @@ -18,7 +18,7 @@ const hasteImplModulePath = path

beforeEach(() => {
cleanup(tempDir);
createEmptyPackage(tempDir);
createEmptyPackage(tempDir, {});
SimenB marked this conversation as resolved.
Show resolved Hide resolved
});

// This test case is checking that when having both
Expand Down
41 changes: 41 additions & 0 deletions e2e/__tests__/multipleConfigs.ts
@@ -0,0 +1,41 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import * as path from 'path';
import {extractSummary} from '../Utils';
import runJest from '../runJest';

const MULTIPLE_CONFIGS_WARNING_TEXT = 'Multiple configurations found';

test('multiple configs will throw matching error', () => {
SimenB marked this conversation as resolved.
Show resolved Hide resolved
SimenB marked this conversation as resolved.
Show resolved Hide resolved
const rootDir = path.resolve(__dirname, '..', '..');
const {exitCode, stderr} = runJest('multiple-configs', [], {
skipPkgJsonCheck: true,
});

expect(exitCode).toBe(0);
expect(stderr).toContain(MULTIPLE_CONFIGS_WARNING_TEXT);

const cleanStdErr = stderr.replace(new RegExp(rootDir, 'g'), '<rootDir>');
const {rest, summary} = extractSummary(cleanStdErr);

expect(rest).toMatchSnapshot();
expect(summary).toMatchSnapshot();
});

test('multiple configs error can be remove by --config', () => {
const {exitCode, stderr} = runJest(
'multiple-configs',
['--config', 'jest.config.json'],
{
skipPkgJsonCheck: true,
},
);

expect(exitCode).toBe(0);
SimenB marked this conversation as resolved.
Show resolved Hide resolved
expect(stderr).not.toContain(MULTIPLE_CONFIGS_WARNING_TEXT);
});
10 changes: 10 additions & 0 deletions e2e/config-override/__tests__/test.js
@@ -0,0 +1,10 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

test('dummy test', () => {
expect(1).toBe(1);
});
3 changes: 3 additions & 0 deletions e2e/config-override/different-config.json
@@ -0,0 +1,3 @@
{
"displayName": "Config from different-config.json file"
}
3 changes: 3 additions & 0 deletions e2e/config-override/jest.config.json
@@ -0,0 +1,3 @@
{
"displayName": "Config from json file"
}
3 changes: 3 additions & 0 deletions e2e/config-override/package.json
@@ -0,0 +1,3 @@
{
"name": "config-override"
}
2 changes: 1 addition & 1 deletion e2e/esm-config/cjs/package.json
@@ -1,3 +1,3 @@
{
"jest": {}
SimenB marked this conversation as resolved.
Show resolved Hide resolved
"name": "cjs-config"
}
2 changes: 1 addition & 1 deletion e2e/esm-config/mjs/package.json
@@ -1,3 +1,3 @@
{
"jest": {}
"name": "mjs-config"
}
10 changes: 10 additions & 0 deletions e2e/multiple-configs/__tests__/test.js
@@ -0,0 +1,10 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

test('dummy test', () => {
expect(1).toBe(1);
});
3 changes: 3 additions & 0 deletions e2e/multiple-configs/jest.config.js
@@ -0,0 +1,3 @@
module.exports = {
displayName: 'Config from js file',
};
3 changes: 3 additions & 0 deletions e2e/multiple-configs/jest.config.json
@@ -0,0 +1,3 @@
{
"displayName": "Config from json file"
}
5 changes: 5 additions & 0 deletions e2e/multiple-configs/package.json
@@ -0,0 +1,5 @@
{
"jest": {
"displayName": "Config from package.json file"
}
}
87 changes: 85 additions & 2 deletions packages/jest-config/src/__tests__/resolveConfigPath.test.ts
Expand Up @@ -14,6 +14,17 @@ import resolveConfigPath from '../resolveConfigPath';
const DIR = path.resolve(tmpdir(), 'resolve_config_path_test');
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<void, Array<any>>;

// 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));
Expand Down Expand Up @@ -45,6 +56,8 @@ 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,
Expand All @@ -53,9 +66,9 @@ describe.each(JEST_CONFIG_EXT_ORDER.slice(0))(
const relativeJestConfigPath = `a/b/c/jest.config${extension}`;
const absoluteJestConfigPath = path.resolve(DIR, relativeJestConfigPath);

// no configs yet. should throw
writeFiles(DIR, {[`a/b/c/some_random_file${extension}`]: ''});

// no configs yet. should throw
expect(() =>
// absolute
resolveConfigPath(path.dirname(absoluteJestConfigPath), DIR),
Expand All @@ -68,6 +81,7 @@ describe.each(JEST_CONFIG_EXT_ORDER.slice(0))(

writeFiles(DIR, {[relativePackageJsonPath]: ''});

mockedConsoleWarn.mockClear();
// absolute
expect(
resolveConfigPath(path.dirname(absolutePackageJsonPath), DIR),
Expand All @@ -77,20 +91,45 @@ 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]: ''});

// jest.config.js takes precedence
mockedConsoleWarn.mockClear();
// absolute
expect(
resolveConfigPath(path.dirname(absolutePackageJsonPath), DIR),
).toBe(absoluteJestConfigPath);

// relative
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(
resolveConfigPath(path.dirname(absolutePackageJsonPath), DIR),
).toBe(absoluteJestConfigPath);
expect(mockedConsoleWarn).toBeCalledTimes(1);
expect(mockedConsoleWarn.mock.calls[0].join()).toMatch(
MULTIPLE_CONFIGS_ERROR_PATTERN,
);

// relative
mockedConsoleWarn.mockClear();
expect(
resolveConfigPath(path.dirname(relativePackageJsonPath), DIR),
).toBe(absoluteJestConfigPath);
expect(mockedConsoleWarn).toBeCalledTimes(1);
expect(mockedConsoleWarn.mock.calls[0].join()).toMatch(
MULTIPLE_CONFIGS_ERROR_PATTERN,
);

expect(() => {
resolveConfigPath(
Expand All @@ -101,3 +140,47 @@ describe.each(JEST_CONFIG_EXT_ORDER.slice(0))(
});
},
);

const pickPairsWithSameOrder = <T>(array: ReadonlyArray<T>) =>
array
.map((value1, idx, arr) =>
arr.slice(idx + 1).map(value2 => [value1, value2]),
)
.flat();
SimenB marked this conversation as resolved.
Show resolved Hide resolved

test('pickPairsWithSameOrder', () => {
expect(pickPairsWithSameOrder([1, 2, 3])).toStrictEqual([
jankaifer marked this conversation as resolved.
Show resolved Hide resolved
[1, 2],
[1, 3],
[2, 3],
]);
});

describe.each(pickPairsWithSameOrder(JEST_CONFIG_EXT_ORDER))(
'Using multiple configs shows warning',
(extension1, extension2) => {
test(`Using jest.config${extension1} and jest.config${extension2} shows warning`, () => {
const mockedConsoleWarn = mockConsoleWarn();

const relativeJestConfigPaths = [
`a/b/c/jest.config${extension1}`,
`a/b/c/jest.config${extension2}`,
];

writeFiles(DIR, {
[relativeJestConfigPaths[0]]: '',
[relativeJestConfigPaths[1]]: '',
});

// multiple configs here, should print warning
mockedConsoleWarn.mockClear();
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,
);
});
},
);