Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

- `[jest-runtime]` Fix issue where user cannot utilize dynamic import despite specifying `--experimental-vm-modules` Node option ([#15842](https://github.com/jestjs/jest/pull/15842))
- `[jest-test-sequencer]` Fix issue where failed tests due to compilation errors not getting re-executed even with `--onlyFailures` CLI option ([#15851](https://github.com/jestjs/jest/pull/15851))
- `[jest-config]` Fix issue where Jest test deps `@jest/test-sequencer` and `jest-environment-node` cannot be resolved correctly when used in `pnpm`-based monorepo ([#15877](https://github.com/jestjs/jest/pull/15877))

### Chore & Maintenance

Expand Down
34 changes: 34 additions & 0 deletions packages/jest-config/src/__tests__/normalize.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Defaults from '../Defaults';
import {DEFAULT_JS_PATTERN} from '../constants';
import normalize, {type AllOptions} from '../normalize';

const env = {...process.env};
const DEFAULT_CSS_PATTERN = '\\.(css)$';

jest
Expand Down Expand Up @@ -85,6 +86,7 @@ beforeEach(() => {

afterEach(() => {
jest.mocked(console.warn).mockRestore();
process.env = env;
});

it('picks an id based on the rootDir', async () => {
Expand Down Expand Up @@ -814,6 +816,21 @@ describe('testEnvironment', () => {
);
});

it('resolves to node environment if given arg matches with default value', async () => {
process.env.npm_config_user_agent = 'pnpm';
const {options} = await normalize(
{
rootDir: '/root',
testEnvironment: 'node',
},
{} as Config.Argv,
);

expect(options.testEnvironment).toEqual(
require.resolve('jest-environment-node'),
);
});

it('throws on invalid environment names', async () => {
await expect(
normalize(
Expand Down Expand Up @@ -2204,3 +2221,20 @@ describe('runInBand', () => {
expect(options.runInBand).toBe(true);
});
});

describe('testSequencer', () => {
it('resolves to @jest/test-sequencer if given arg matches with default value and pnpm is used', async () => {
process.env.npm_config_user_agent = 'pnpm';
const {options} = await normalize(
{
rootDir: '/root/path/foo',
testSequencer: '@jest/test-sequencer',
},
{} as Config.Argv,
);

expect(options.testSequencer).toMatch(
require.resolve('@jest/test-sequencer'),
);
});
});
47 changes: 47 additions & 0 deletions packages/jest-config/src/__tests__/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

import {tmpdir} from 'os';
import {useSpecificPackageManager} from '../utils';
import path from 'path';
import {cleanup, writeFiles} from '../../../../e2e/Utils';

const DIR = path.resolve(tmpdir(), 'jest_config_utils_test');
const env = {...process.env};

beforeEach(() => {
cleanup(DIR);
});

afterEach(() => {
process.env = env;
cleanup(DIR);
});

describe('useSpecificPackageManager', () => {
it('returns true when package manager matches with arg is used', () => {
writeFiles(DIR, {
'pnpm-lock.yaml': "lockfileVersion: '9.0'",
});
process.env.npm_config_user_agent = 'pnpm';
expect(useSpecificPackageManager('pnpm', DIR)).toBe(true);
});

it('returns true when package manager is not used but signature lockfile can be found', () => {
writeFiles(DIR, {
'pnpm-lock.yaml': "lockfileVersion: '9.0'",
});
process.env.npm_config_user_agent = 'node';
expect(useSpecificPackageManager('pnpm', DIR)).toBe(true);
});

it('returns false when package manager different from arg is used', () => {
process.env.npm_config_user_agent = 'something_else';
expect(useSpecificPackageManager('npm', DIR)).toBe(false);
});
});
29 changes: 24 additions & 5 deletions packages/jest-config/src/normalize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import {
escapeGlobCharacters,
replaceRootDirInPath,
resolve,
useSpecificPackageManager,
} from './utils';

const ERROR = `${BULLET}Validation Error`;
Expand Down Expand Up @@ -169,7 +170,9 @@ const setupPreset = async (
);
}
throw createConfigError(
` Preset ${chalk.bold(presetPath)} not found relative to rootDir ${chalk.bold(options.rootDir)}.`,
` Preset ${chalk.bold(
presetPath,
)} not found relative to rootDir ${chalk.bold(options.rootDir)}.`,
);
}
throw createConfigError(
Expand Down Expand Up @@ -518,12 +521,20 @@ export default async function normalize(
options.setupFilesAfterEnv = [];
}

// For default Jest test env, let's use native resolution mechanism
// of JS runtime instead of resorting to third-party ones.
let testEnvironment = options.testEnvironment;
if (
`jest-environment-${testEnvironment}` === DEFAULT_CONFIG.testEnvironment &&
useSpecificPackageManager('pnpm', options.rootDir)
) {
testEnvironment = require.resolve(DEFAULT_CONFIG.testEnvironment);
}
options.testEnvironment = resolveTestEnvironment({
requireResolveFunction: requireResolve,
rootDir: options.rootDir,
testEnvironment:
options.testEnvironment ||
require.resolve(DEFAULT_CONFIG.testEnvironment),
testEnvironment || require.resolve(DEFAULT_CONFIG.testEnvironment),
});

if (!options.roots) {
Expand Down Expand Up @@ -997,9 +1008,17 @@ export default async function normalize(
// ignored
}

// For default Jest test sequencer, let's use native resolution mechanism
// of JS runtime instead of resorting to third-party ones.
let testSequencer = options.testSequencer;
if (
options.testSequencer === DEFAULT_CONFIG.testSequencer &&
useSpecificPackageManager('pnpm', options.rootDir)
) {
testSequencer = require.resolve(DEFAULT_CONFIG.testSequencer);
}
newOptions.testSequencer = resolveSequencer(newOptions.resolver, {
filePath:
options.testSequencer || require.resolve(DEFAULT_CONFIG.testSequencer),
filePath: testSequencer || require.resolve(DEFAULT_CONFIG.testSequencer),
requireResolveFunction: requireResolve,
rootDir: options.rootDir,
});
Expand Down
14 changes: 14 additions & 0 deletions packages/jest-config/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import * as path from 'path';
import chalk from 'chalk';
import {existsSync} from 'graceful-fs';
import Resolver from 'jest-resolve';
import {ValidationError} from 'jest-validate';

Expand Down Expand Up @@ -119,3 +120,16 @@ export const isJSONString = (text?: JSONString | string): text is JSONString =>
typeof text === 'string' &&
text.startsWith('{') &&
text.endsWith('}');

export const useSpecificPackageManager = (
identifier: string,
rootDir: string,
): boolean => {
let checkLockFile = false;
if (identifier === 'pnpm') {
checkLockFile = existsSync(path.join(rootDir, 'pnpm-lock.yaml'));
}
return (
checkLockFile || !!process.env.npm_config_user_agent?.includes(identifier)
);
};
Loading