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

Support '.js', '.cjs', '.json' configs #9291

Merged
merged 8 commits into from Dec 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -11,6 +11,7 @@
- `[jest-config]` Throw the full error message and stack when a Jest preset is missing a dependency ([#8924](https://github.com/facebook/jest/pull/8924))
- `[jest-config]` [**BREAKING**] Set default display name color based on runner ([#8689](https://github.com/facebook/jest/pull/8689))
- `[jest-config]` Merge preset globals with project globals ([#9027](https://github.com/facebook/jest/pull/9027))
- `[jest-config]` Support `.cjs` config files ([#9291](https://github.com/facebook/jest/pull/9291))
- `[jest-core]` Support reporters as default exports ([#9161](https://github.com/facebook/jest/pull/9161))
- `[jest-diff]` Add options for colors and symbols ([#8841](https://github.com/facebook/jest/pull/8841))
- `[jest-diff]` [**BREAKING**] Export as ECMAScript module ([#8873](https://github.com/facebook/jest/pull/8873))
Expand Down
2 changes: 1 addition & 1 deletion docs/Configuration.md
Expand Up @@ -3,7 +3,7 @@ id: configuration
title: Configuring Jest
---

Jest's configuration can be defined in the `package.json` file of your project, or through a `jest.config.js` file or through the `--config <path/to/js|json>` option. If you'd like to use your `package.json` to store Jest's config, the "jest" key should be used on the top level so Jest will know how to find your settings:
Jest's configuration can be defined in the `package.json` file of your project, or through a `jest.config.js` file or through the `--config <path/to/file.js|cjs|json>` option. If you'd like to use your `package.json` to store Jest's config, the "jest" key should be used on the top level so Jest will know how to find your settings:

```json
{
Expand Down
21 changes: 21 additions & 0 deletions e2e/__tests__/cjsConfigFile.test.ts
@@ -0,0 +1,21 @@
/**
* 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 {json as runWithJson} from '../runJest';

test('reads config from cjs file', () => {
const {json, exitCode} = runWithJson('cjs-config', ['--show-config'], {
skipPkgJsonCheck: true,
});

expect(exitCode).toBe(0);
expect(json.configs).toHaveLength(1);
expect(json.configs[0].displayName).toEqual({
color: 'white',
name: 'Config from cjs file',
});
});
10 changes: 10 additions & 0 deletions e2e/cjs-config/__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);
});
11 changes: 11 additions & 0 deletions e2e/cjs-config/jest.config.cjs
@@ -0,0 +1,11 @@
/**
* 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.
*/

module.exports = {
displayName: 'Config from cjs file',
testEnvironment: 'node',
};
3 changes: 3 additions & 0 deletions e2e/cjs-config/package.json
@@ -0,0 +1,3 @@
{
"jest": {}
}
Expand Up @@ -9,7 +9,25 @@ Object {
}
`;

exports[`init has-jest-config-file ask the user whether to override config or not user answered with "Yes" 1`] = `
exports[`init has-jest-config-file-cjs ask the user whether to override config or not user answered with "Yes" 1`] = `
Object {
"initial": true,
"message": "It seems that you already have a jest configuration, do you want to override it?",
"name": "continue",
"type": "confirm",
}
`;

exports[`init has-jest-config-file-js ask the user whether to override config or not user answered with "Yes" 1`] = `
Object {
"initial": true,
"message": "It seems that you already have a jest configuration, do you want to override it?",
"name": "continue",
"type": "confirm",
}
`;

exports[`init has-jest-config-file-json ask the user whether to override config or not user answered with "Yes" 1`] = `
Object {
"initial": true,
"message": "It seems that you already have a jest configuration, do you want to override it?",
Expand Down
@@ -0,0 +1,8 @@
/**
* 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.
*/

module.exports = {};
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
{}
36 changes: 20 additions & 16 deletions packages/jest-cli/src/init/__tests__/init.test.js
Expand Up @@ -10,6 +10,7 @@ import * as fs from 'fs';
import * as path from 'path';
import prompts from 'prompts';
import init from '../';
import {JEST_CONFIG_EXT_ORDER} from '../constants';

jest.mock('prompts');
jest.mock('../../../../jest-config/build/getCacheDirectory', () => () =>
Expand Down Expand Up @@ -125,29 +126,32 @@ describe('init', () => {
});
});

describe('has-jest-config-file', () => {
describe('ask the user whether to override config or not', () => {
it('user answered with "Yes"', async () => {
prompts.mockReturnValueOnce({continue: true}).mockReturnValueOnce({});
describe.each(JEST_CONFIG_EXT_ORDER.map(e => e.substring(1)))(
'has-jest-config-file-%s',
extension => {
describe('ask the user whether to override config or not', () => {
it('user answered with "Yes"', async () => {
prompts.mockReturnValueOnce({continue: true}).mockReturnValueOnce({});

await init(resolveFromFixture('has_jest_config_file'));
await init(resolveFromFixture(`has_jest_config_file_${extension}`));

expect(prompts.mock.calls[0][0]).toMatchSnapshot();
expect(prompts.mock.calls[0][0]).toMatchSnapshot();

const writtenJestConfig = fs.writeFileSync.mock.calls[0][1];
const writtenJestConfig = fs.writeFileSync.mock.calls[0][1];

expect(writtenJestConfig).toBeDefined();
});
expect(writtenJestConfig).toBeDefined();
});

it('user answered with "No"', async () => {
prompts.mockReturnValueOnce({continue: false});
it('user answered with "No"', async () => {
prompts.mockReturnValueOnce({continue: false});

await init(resolveFromFixture('has_jest_config_file'));
// return after first prompt
expect(prompts).toHaveBeenCalledTimes(1);
await init(resolveFromFixture(`has_jest_config_file_${extension}`));
// return after first prompt
expect(prompts).toHaveBeenCalledTimes(1);
});
});
});
});
},
);

describe('has jest config in package.json', () => {
it('should ask the user whether to override config or not', async () => {
Expand Down
10 changes: 9 additions & 1 deletion packages/jest-cli/src/init/constants.ts
Expand Up @@ -6,4 +6,12 @@
*/

export const PACKAGE_JSON = 'package.json';
export const JEST_CONFIG = 'jest.config.js';
export const JEST_CONFIG_BASE_NAME = 'jest.config';
export const JEST_CONFIG_EXT_CJS = '.cjs';
export const JEST_CONFIG_EXT_JS = '.js';
export const JEST_CONFIG_EXT_JSON = '.json';
export const JEST_CONFIG_EXT_ORDER = Object.freeze([
JEST_CONFIG_EXT_JS,
JEST_CONFIG_EXT_CJS,
JEST_CONFIG_EXT_JSON,
]);
30 changes: 23 additions & 7 deletions packages/jest-cli/src/init/index.ts
Expand Up @@ -12,7 +12,13 @@ import prompts = require('prompts');
import {sync as realpath} from 'realpath-native';
import defaultQuestions, {testScriptQuestion} from './questions';
import {MalformedPackageJsonError, NotFoundPackageJsonError} from './errors';
import {JEST_CONFIG, PACKAGE_JSON} from './constants';
import {
JEST_CONFIG_BASE_NAME,
JEST_CONFIG_EXT_CJS,
JEST_CONFIG_EXT_JS,
JEST_CONFIG_EXT_ORDER,
PACKAGE_JSON,
} from './constants';
import generateConfigFile from './generate_config_file';
import modifyPackageJson from './modify_package_json';
import {ProjectPackageJson} from './types';
Expand All @@ -24,18 +30,18 @@ type PromptsResults = {
scripts: boolean;
};

const getConfigFilename = (ext: string) => JEST_CONFIG_BASE_NAME + ext;

export default async (rootDir: string = realpath(process.cwd())) => {
// prerequisite checks
const projectPackageJsonPath: string = path.join(rootDir, PACKAGE_JSON);
const jestConfigPath: string = path.join(rootDir, JEST_CONFIG);

if (!fs.existsSync(projectPackageJsonPath)) {
throw new NotFoundPackageJsonError(rootDir);
}

const questions = defaultQuestions.slice(0);
let hasJestProperty: boolean = false;
let hasJestConfig: boolean = false;
let projectPackageJson: ProjectPackageJson;

try {
Expand All @@ -50,11 +56,21 @@ export default async (rootDir: string = realpath(process.cwd())) => {
hasJestProperty = true;
}

if (fs.existsSync(jestConfigPath)) {
hasJestConfig = true;
}
const existingJestConfigPath = JEST_CONFIG_EXT_ORDER.find(ext =>
fs.existsSync(path.join(rootDir, getConfigFilename(ext))),
);
const jestConfigPath =
existingJestConfigPath ||
path.join(
rootDir,
getConfigFilename(
projectPackageJson.type === 'module'
thymikee marked this conversation as resolved.
Show resolved Hide resolved
? JEST_CONFIG_EXT_CJS
: JEST_CONFIG_EXT_JS,
),
);

if (hasJestProperty || hasJestConfig) {
if (hasJestProperty || existingJestConfigPath) {
const result: {continue: boolean} = await prompts({
initial: true,
message:
Expand Down
1 change: 1 addition & 0 deletions packages/jest-cli/src/init/types.ts
Expand Up @@ -10,4 +10,5 @@ import {Config} from '@jest/types';
export type ProjectPackageJson = {
jest?: Partial<Config.InitialOptions>;
scripts?: Record<string, string>;
type?: 'commonjs' | 'module';
};