Skip to content

Commit e7f21ab

Browse files
mrazauskasDmitryMakhnev
authored andcommitted
fix(jest-config): handle frozen config object (jestjs#14054)
* fix(jest-config): handle frozen config object * change log entry
1 parent c0553f4 commit e7f21ab

File tree

3 files changed

+178
-5
lines changed

3 files changed

+178
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
### Fixes
66

7+
- `[jest-config]` Handle frozen config object ([#14054](https://github.com/facebook/jest/pull/14054))
78
- `[jest-environment-jsdom, jest-environment-node]` Fix assignment of `customExportConditions` via `testEnvironmentOptions` when custom env subclass defines a default value ([#13989](https://github.com/facebook/jest/pull/13989))
89
- `[jest-matcher-utils]` Fix copying value of inherited getters ([#14007](https://github.com/facebook/jest/pull/14007))
910
- `[jest-snapshot]` Fix a potential bug when not using prettier and improve performance ([#14036](https://github.com/facebook/jest/pull/14036))
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
import path = require('path');
9+
import * as fs from 'graceful-fs';
10+
import {requireOrImportModule} from 'jest-util';
11+
import readConfigFileAndSetRootDir from '../readConfigFileAndSetRootDir';
12+
13+
jest.mock('graceful-fs').mock('jest-util');
14+
15+
describe('readConfigFileAndSetRootDir', () => {
16+
describe('JavaScript file', () => {
17+
test('reads config and sets `rootDir`', async () => {
18+
jest.mocked(requireOrImportModule).mockResolvedValueOnce({notify: true});
19+
20+
const rootDir = path.resolve('some', 'path', 'to');
21+
const config = await readConfigFileAndSetRootDir(
22+
path.join(rootDir, 'jest.config.js'),
23+
);
24+
25+
expect(config).toEqual({notify: true, rootDir});
26+
});
27+
28+
test('handles exported function', async () => {
29+
jest
30+
.mocked(requireOrImportModule)
31+
.mockResolvedValueOnce(() => ({bail: 1}));
32+
33+
const rootDir = path.resolve('some', 'path', 'to');
34+
const config = await readConfigFileAndSetRootDir(
35+
path.join(rootDir, 'jest.config.js'),
36+
);
37+
38+
expect(config).toEqual({bail: 1, rootDir});
39+
});
40+
41+
test('handles exported async function', async () => {
42+
jest
43+
.mocked(requireOrImportModule)
44+
.mockResolvedValueOnce(async () => ({testTimeout: 10000}));
45+
46+
const rootDir = path.resolve('some', 'path', 'to');
47+
const config = await readConfigFileAndSetRootDir(
48+
path.join(rootDir, 'jest.config.js'),
49+
);
50+
51+
expect(config).toEqual({rootDir, testTimeout: 10000});
52+
});
53+
});
54+
55+
describe('JSON file', () => {
56+
test('reads config and sets `rootDir`', async () => {
57+
jest.mocked(fs.readFileSync).mockReturnValueOnce('{ "verbose": true }');
58+
59+
const rootDir = path.resolve('some', 'path', 'to');
60+
const config = await readConfigFileAndSetRootDir(
61+
path.join(rootDir, 'jest.config.json'),
62+
);
63+
64+
expect(config).toEqual({rootDir, verbose: true});
65+
});
66+
67+
test('supports comments in JSON', async () => {
68+
jest
69+
.mocked(fs.readFileSync)
70+
.mockReturnValueOnce('{ // test comment\n "bail": true }');
71+
72+
const rootDir = path.resolve('some', 'path', 'to');
73+
const config = await readConfigFileAndSetRootDir(
74+
path.join(rootDir, 'jest.config.json'),
75+
);
76+
77+
expect(config).toEqual({bail: true, rootDir});
78+
});
79+
});
80+
81+
describe('package.json file', () => {
82+
test('reads config from "jest" key and sets `rootDir`', async () => {
83+
jest
84+
.mocked(fs.readFileSync)
85+
.mockReturnValueOnce('{ "jest": { "coverage": true } }');
86+
87+
const rootDir = path.resolve('some', 'path', 'to');
88+
const config = await readConfigFileAndSetRootDir(
89+
path.join(rootDir, 'package.json'),
90+
);
91+
92+
expect(config).toEqual({coverage: true, rootDir});
93+
});
94+
95+
test('sets rootDir if "jest" is absent', async () => {
96+
jest.mocked(fs.readFileSync).mockReturnValueOnce('{ "name": "test" }');
97+
98+
const rootDir = path.resolve('some', 'path', 'to');
99+
const config = await readConfigFileAndSetRootDir(
100+
path.join(rootDir, 'package.json'),
101+
);
102+
103+
expect(config).toEqual({rootDir});
104+
});
105+
});
106+
107+
describe('sets `rootDir`', () => {
108+
test('handles frozen config object', async () => {
109+
jest
110+
.mocked(requireOrImportModule)
111+
.mockResolvedValueOnce(Object.freeze({preset: 'some-preset'}));
112+
113+
const rootDir = path.resolve('some', 'path', 'to');
114+
const config = await readConfigFileAndSetRootDir(
115+
path.join(rootDir, 'jest.config.js'),
116+
);
117+
118+
expect(config).toEqual({preset: 'some-preset', rootDir});
119+
});
120+
121+
test('keeps the path if it is absolute', async () => {
122+
const rootDir = path.resolve('some', 'path', 'to');
123+
jest.mocked(requireOrImportModule).mockResolvedValueOnce({
124+
rootDir,
125+
testEnvironment: 'node',
126+
});
127+
128+
const config = await readConfigFileAndSetRootDir(
129+
path.join(path.resolve('other', 'path', 'to'), 'jest.config.js'),
130+
);
131+
132+
expect(config).toEqual({rootDir, testEnvironment: 'node'});
133+
});
134+
135+
test('resolves the path relative to dirname of the config file', async () => {
136+
jest.mocked(requireOrImportModule).mockResolvedValueOnce({
137+
restoreMocks: true,
138+
rootDir: path.join('path', 'to'),
139+
});
140+
141+
const config = await readConfigFileAndSetRootDir(
142+
path.join(path.resolve('some'), 'jest.config.js'),
143+
);
144+
145+
expect(config).toEqual({
146+
restoreMocks: true,
147+
rootDir: path.resolve('some', 'path', 'to'),
148+
});
149+
});
150+
151+
test('resolves relative path when the read config object if frozen', async () => {
152+
jest.mocked(requireOrImportModule).mockResolvedValueOnce(
153+
Object.freeze({
154+
resetModules: true,
155+
rootDir: path.join('path', 'to'),
156+
}),
157+
);
158+
159+
const config = await readConfigFileAndSetRootDir(
160+
path.join(path.resolve('some'), 'jest.config.js'),
161+
);
162+
163+
expect(config).toEqual({
164+
resetModules: true,
165+
rootDir: path.resolve('some', 'path', 'to'),
166+
});
167+
});
168+
});
169+
});

packages/jest-config/src/readConfigFileAndSetRootDir.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,17 @@ export default async function readConfigFileAndSetRootDir(
6464
// We don't touch it if it has an absolute path specified
6565
if (!path.isAbsolute(configObject.rootDir)) {
6666
// otherwise, we'll resolve it relative to the file's __dirname
67-
configObject.rootDir = path.resolve(
68-
path.dirname(configPath),
69-
configObject.rootDir,
70-
);
67+
configObject = {
68+
...configObject,
69+
rootDir: path.resolve(path.dirname(configPath), configObject.rootDir),
70+
};
7171
}
7272
} else {
7373
// If rootDir is not there, we'll set it to this file's __dirname
74-
configObject.rootDir = path.dirname(configPath);
74+
configObject = {
75+
...configObject,
76+
rootDir: path.dirname(configPath),
77+
};
7578
}
7679

7780
return configObject;

0 commit comments

Comments
 (0)