Skip to content
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
### Fixes

- `[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-config]` Fix issue where custom reporters not loaded from legacy global module folder, i.e. `$HOME/.node_libraries` ([#15852](https://github.com/jestjs/jest/pull/15852))
- `[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))

### Chore & Maintenance
Expand Down
32 changes: 32 additions & 0 deletions e2e/__tests__/customReporters.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,4 +179,36 @@ describe('Custom Reporters Integration', () => {
expect(stderr).toMatch(/ON_RUN_START_ERROR/);
expect(exitCode).toBe(1);
});

test('supports custom reporter stored in legacy module path, i.e. $HOME/.node_libraries', () => {
writeFiles(DIR, {
'__tests__/test.test.js': "test('test', () => {});",
'fakeHome/.node_libraries/@org/custom-reporter/index.js': `
'use strict';
module.exports = class Reporter {
onRunStart() {
throw new Error('ON_RUN_START_ERROR');
}
};
`,
'package.json': JSON.stringify({
jest: {
reporters: ['@org/custom-reporter'],
},
}),
});

const {stderr, exitCode} = runJest(DIR, undefined, {
env: {
HOME: path.resolve(DIR, 'fakeHome'),
// For Windows testing
USERPROFILE:
process.platform === 'win32'
? path.resolve(DIR, 'fakeHome')
: undefined,
},
});
expect(stderr).toMatch(/ON_RUN_START_ERROR/);
expect(exitCode).toBe(1);
});
});
39 changes: 38 additions & 1 deletion packages/jest-config/src/__tests__/normalize.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {escapeStrForRegex} from 'jest-regex-util';
import Defaults from '../Defaults';
import {DEFAULT_JS_PATTERN} from '../constants';
import normalize, {type AllOptions} from '../normalize';
import type {FindNodeModuleConfig} from 'jest-resolve';

const DEFAULT_CSS_PATTERN = '\\.(css)$';

Expand Down Expand Up @@ -83,7 +84,16 @@ beforeEach(() => {
jest.spyOn(console, 'warn');
});

const oldUserProfile = process.env.USERPROFILE;
const originalPlatform = process.platform;

afterEach(() => {
// Restore the original process.* value after each test.
process.env.USERPROFILE = oldUserProfile;
Object.defineProperty(process, 'platform', {
value: originalPlatform,
});

jest.mocked(console.warn).mockRestore();
});

Expand Down Expand Up @@ -293,10 +303,14 @@ describe('roots', () => {

describe('reporters', () => {
let Resolver: typeof import('jest-resolve').default;
const spiedFindNodeModuleFunction = jest.fn(
(name: string, _: FindNodeModuleConfig) => name,
);

beforeEach(() => {
Resolver = (require('jest-resolve') as typeof import('jest-resolve'))
.default;
Resolver.findNodeModule = jest.fn((name: string) => name);
Resolver.findNodeModule = spiedFindNodeModuleFunction;
});

it('allows empty list', async () => {
Expand Down Expand Up @@ -390,6 +404,29 @@ describe('reporters', () => {
),
).rejects.toThrowErrorMatchingSnapshot();
});

it('normalizes the path and options object for custom reporter on Windows', async () => {
// Simulate running in Windows env with USERPROFILE env var undefined.
process.env.USERPROFILE = undefined;
Object.defineProperty(process, 'platform', {
value: 'win32',
});

const {options} = await normalize(
{
reporters: [
['<rootDir>/custom-reporter.js', {banana: 'yes', pineapple: 'no'}],
],
rootDir: '/root/',
},
{} as Config.Argv,
);

expect(options.reporters).toEqual([
['/root/custom-reporter.js', {banana: 'yes', pineapple: 'no'}],
]);
expect(spiedFindNodeModuleFunction.mock.calls[0][1].paths).toBeUndefined();
});
});

describe('transform', () => {
Expand Down
14 changes: 13 additions & 1 deletion packages/jest-config/src/normalize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
clearLine,
replacePathSepForGlob,
requireOrImportModule,
specialChars,
tryRealpath,
} from 'jest-util';
import {ValidationError, validate} from 'jest-validate';
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(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is autogenerated by prettier

presetPath,
)} not found relative to rootDir ${chalk.bold(options.rootDir)}.`,
);
}
throw createConfigError(
Expand Down Expand Up @@ -378,8 +381,17 @@ const normalizeReporters = ({
);

if (!['default', 'github-actions', 'summary'].includes(reporterPath)) {
// There's a chance that users store custom reporter in legacy module paths
// such as $HOME/.node_libraries
const homeDir = specialChars.isWindows
? process.env.USERPROFILE
: process.env.HOME;
const legacyModulePaths = homeDir
? [path.resolve(homeDir, '.node_libraries')]
: undefined;
const reporter = Resolver.findNodeModule(reporterPath, {
basedir: rootDir,
paths: legacyModulePaths,
});
if (!reporter) {
throw new Resolver.ModuleNotFoundError(
Expand Down
2 changes: 1 addition & 1 deletion packages/jest-util/src/specialChars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/

const isWindows = process.platform === 'win32';
export const isWindows = process.platform === 'win32';

export const ARROW = ' \u203A ';
export const ICONS = {
Expand Down
Loading