Skip to content

Commit

Permalink
Support '.js', '.cjs', '.json' configs (#9291)
Browse files Browse the repository at this point in the history
  • Loading branch information
the-spyke authored and SimenB committed Dec 11, 2019
1 parent b2c8a69 commit 446d174
Show file tree
Hide file tree
Showing 21 changed files with 240 additions and 106 deletions.
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'
? 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';
};

0 comments on commit 446d174

Please sign in to comment.