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(config): add read initial options helper #13356

Merged
merged 24 commits into from Oct 3, 2022
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
8d598dd
feat(config): add read initial options helper
nicojs Oct 2, 2022
aabb8de
Enable experimental-vm-modules to run jest.
nicojs Oct 2, 2022
e9b5c87
Update changelog
nicojs Oct 2, 2022
b6276fb
Add copyright headers
nicojs Oct 2, 2022
d93a12c
Update assert: also use forward slashes on windows.
nicojs Oct 2, 2022
eadd24e
Update packages/jest-config/src/index.ts
nicojs Oct 2, 2022
947bfaa
Update changelog sorting
nicojs Oct 2, 2022
7793ff2
Move integration tests to e2e
nicojs Oct 2, 2022
153af9b
Remove `--experimental-vm-modules`
nicojs Oct 2, 2022
4294610
Extract `ReadJestConfigOptions` interface
nicojs Oct 2, 2022
6d347a6
Finish rename `readFromCwdInstead` -> `readFromCwd`
nicojs Oct 2, 2022
c2dffe9
Import from `@jest/types` instead of `jest-runner`
nicojs Oct 2, 2022
b3a13cc
Update packages/jest-config/src/__tests__/readInitialOptions.test.ts
nicojs Oct 2, 2022
c41dbdf
Update packages/jest-config/src/__tests__/readInitialOptions.test.ts
nicojs Oct 2, 2022
8b479f5
Update packages/jest-config/src/__tests__/readInitialOptions.test.ts
nicojs Oct 2, 2022
9f01d80
Remove final `.name`
nicojs Oct 2, 2022
188b080
Read config by proxy for ts and mjs files
nicojs Oct 3, 2022
5c54a6a
Add copyright header
nicojs Oct 3, 2022
53b49ba
Read by proxy for every test
nicojs Oct 3, 2022
34e1a32
Update e2e/__tests__/readInitialOptions.test.ts
nicojs Oct 3, 2022
3cf1f21
Refactor if/else -> if
nicojs Oct 3, 2022
3d535ba
refactor: move some comments around
nicojs Oct 3, 2022
5ab7237
Update e2e/__tests__/readInitialOptions.test.ts
nicojs Oct 3, 2022
2dfe6ef
Require argv to be supplied
nicojs Oct 3, 2022
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 @@ -2,6 +2,7 @@

### Features

- `[jest-config]` Add `readInitialConfig` utility function ([#13356](https://github.com/facebook/jest/pull/13356))
- `[jest-core]` Enable testResultsProcessor to be async ([#13343](https://github.com/facebook/jest/pull/13343))
- `[expect, @jest/expect-utils]` Allow `isA` utility to take a type argument ([#13355](https://github.com/facebook/jest/pull/13355))

Expand Down
150 changes: 150 additions & 0 deletions e2e/__tests__/readInitialOptions.test.ts
@@ -0,0 +1,150 @@
/**
* 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 path = require('path');
import execa = require('execa');
import type {ReadJestConfigOptions, readInitialOptions} from 'jest-config';

function resolveFixture(...pathSegments: Array<string>) {
return path.resolve(__dirname, '..', 'read-initial-options', ...pathSegments);
}

interface ProxyReadJestConfigOptions extends ReadJestConfigOptions {
cwd?: string;
}

/**
* These e2e tests are running via a child process, because we're running in a VM and are not allowed to `import` directly
* It also represents a more real-world example of how to run.
*/
async function proxyReadInitialOptions(
configFile?: string | undefined,
options?: ProxyReadJestConfigOptions,
nicojs marked this conversation as resolved.
Show resolved Hide resolved
): ReturnType<typeof readInitialOptions> {
const {stdout} = await execa(
'node',
[
require.resolve('../read-initial-options/readOptions.js'),
configFile ?? '',
JSON.stringify(options),
],
{
cwd: options?.cwd,
},
nicojs marked this conversation as resolved.
Show resolved Hide resolved
);
return JSON.parse(stdout);
}

describe('readInitialOptions', () => {
test('should read from the cwd by default', async () => {
const configFile = resolveFixture('js-config', 'jest.config.js');
const rootDir = resolveFixture('js-config');
const {config, configPath} = await proxyReadInitialOptions(undefined, {
cwd: rootDir,
});
expect(config).toEqual({jestConfig: 'jest.config.js', rootDir});
expect(configPath).toEqual(configFile);
});
test('should read a jest.config.js file', async () => {
const configFile = resolveFixture('js-config', 'jest.config.js');
const rootDir = resolveFixture('js-config');
const {config, configPath} = await proxyReadInitialOptions(undefined, {
cwd: rootDir,
});
expect(config).toEqual({jestConfig: 'jest.config.js', rootDir});
expect(configPath).toEqual(configFile);
});
test('should read a package.json file', async () => {
const configFile = resolveFixture('pkg-config', 'package.json');
const rootDir = resolveFixture('pkg-config');
const {config, configPath} = await proxyReadInitialOptions(undefined, {
cwd: rootDir,
});
expect(config).toEqual({jestConfig: 'package.json', rootDir});
expect(configPath).toEqual(configFile);
});
test('should read a jest.config.ts file', async () => {
const configFile = resolveFixture('ts-config', 'jest.config.ts');
const rootDir = resolveFixture('ts-config');
const {config, configPath} = await proxyReadInitialOptions(undefined, {
cwd: rootDir,
});
expect(config).toEqual({jestConfig: 'jest.config.ts', rootDir});
expect(configPath).toEqual(configFile);
});
test('should read a jest.config.mjs file', async () => {
const configFile = resolveFixture('mjs-config', 'jest.config.mjs');
const rootDir = resolveFixture('mjs-config');
const {config, configPath} = await proxyReadInitialOptions(undefined, {
cwd: rootDir,
});
expect(config).toEqual({jestConfig: 'jest.config.mjs', rootDir});
expect(configPath).toEqual(configFile);
});
test('should read a jest.config.json file', async () => {
const configFile = resolveFixture('json-config', 'jest.config.json');
const rootDir = resolveFixture('json-config');
const {config, configPath} = await proxyReadInitialOptions(undefined, {
cwd: rootDir,
});
expect(config).toEqual({jestConfig: 'jest.config.json', rootDir});
expect(configPath).toEqual(configFile);
});
test('should read a jest config exporting an async function', async () => {
const configFile = resolveFixture('async-config', 'jest.config.js');
const rootDir = resolveFixture('async-config');
const {config, configPath} = await proxyReadInitialOptions(undefined, {
cwd: rootDir,
});
expect(config).toEqual({jestConfig: 'async-config', rootDir});
expect(configPath).toEqual(configFile);
});

test('should be able to skip config reading, instead read from cwd', async () => {
const expectedConfigFile = resolveFixture(
'json-config',
'jest.config.json',
);
const {config, configPath} = await proxyReadInitialOptions(
resolveFixture('js-config', 'jest.config.js'),
{
cwd: resolveFixture('json-config'),
readFromCwd: true,
},
);

expect(config).toEqual({
jestConfig: 'jest.config.json',
rootDir: path.dirname(expectedConfigFile),
});
expect(configPath).toEqual(expectedConfigFile);
});

test('should give an error when there are multiple config files', async () => {
const cwd = resolveFixture('multiple-config-files');
const error: Error = await proxyReadInitialOptions(undefined, {cwd}).catch(
error => error,
);
expect(error.message).toContain('Multiple configurations found');
expect(error.message).toContain('multiple-config-files/jest.config.js');
expect(error.message).toContain('multiple-config-files/jest.config.json');
});

test('should be able to ignore multiple config files error', async () => {
const cwd = resolveFixture('multiple-config-files');
const {config, configPath} = await proxyReadInitialOptions(undefined, {
cwd,
skipMultipleConfigError: true,
});
expect(config).toEqual({
jestConfig: 'jest.config.js',
rootDir: resolveFixture('multiple-config-files'),
});
expect(configPath).toEqual(
resolveFixture('multiple-config-files', 'jest.config.js'),
);
});
});
11 changes: 11 additions & 0 deletions e2e/read-initial-options/async-config/jest.config.js
@@ -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 = async function () {
return {
jestConfig: 'async-config',
};
};
9 changes: 9 additions & 0 deletions e2e/read-initial-options/js-config/jest.config.js
@@ -0,0 +1,9 @@
/**
* 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 = {
jestConfig: 'jest.config.js',
};
3 changes: 3 additions & 0 deletions e2e/read-initial-options/json-config/jest.config.json
@@ -0,0 +1,3 @@
{
"jestConfig": "jest.config.json"
}
9 changes: 9 additions & 0 deletions e2e/read-initial-options/mjs-config/jest.config.mjs
@@ -0,0 +1,9 @@
/**
* 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.
*/
export default {
jestConfig: 'jest.config.mjs',
};
9 changes: 9 additions & 0 deletions e2e/read-initial-options/multiple-config-files/jest.config.js
@@ -0,0 +1,9 @@
/**
* 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 = {
jestConfig: 'jest.config.js',
};
@@ -0,0 +1,3 @@
{
"jestConfig": "jest.config.json"
}
5 changes: 5 additions & 0 deletions e2e/read-initial-options/pkg-config/package.json
@@ -0,0 +1,5 @@
{
"jest": {
"jestConfig": "package.json"
}
}
22 changes: 22 additions & 0 deletions e2e/read-initial-options/readOptions.js
@@ -0,0 +1,22 @@
/**
* 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.
*/
const {readInitialOptions} = require('jest-config');
async function readConfig() {
let config = process.argv[2];
let options = undefined;
if (config === '') {
config = undefined;
}
if (process.argv[3]) {
options = JSON.parse(process.argv[3]);
}
console.log(JSON.stringify(await readInitialOptions(config, options)));
}
readConfig().catch(err => {
console.error(err);
process.exitCode = 1;
});
9 changes: 9 additions & 0 deletions e2e/read-initial-options/ts-config/jest.config.ts
@@ -0,0 +1,9 @@
/**
* 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.
*/
export default {
jestConfig: 'jest.config.ts',
};
30 changes: 30 additions & 0 deletions packages/jest-config/src/__tests__/readInitialOptions.test.ts
@@ -0,0 +1,30 @@
/**
* 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 type {Config} from '@jest/types';
import {readInitialOptions} from '../index';

describe(readInitialOptions, () => {
test('should be able to use serialized jest config', async () => {
const inputConfig = {jestConfig: 'serialized'};
const {config, configPath} = await readInitialOptions(
JSON.stringify(inputConfig),
);
expect(config).toEqual({...inputConfig, rootDir: process.cwd()});
expect(configPath).toBeNull();
});

test('should allow deserialized options', async () => {
const inputConfig = {jestConfig: 'deserialized'};
const {config, configPath} = await readInitialOptions(undefined, {
packageRootOrConfig: inputConfig as Config.InitialOptions,
parentConfigDirname: process.cwd(),
});
expect(config).toEqual({...inputConfig, rootDir: process.cwd()});
expect(configPath).toBeNull();
});
// Note: actual file reading is tested in e2e test
});