From 05b1a7c8e28d2659acbd7da6639dc0a5ac5ca79c Mon Sep 17 00:00:00 2001 From: hainenber Date: Sun, 5 Oct 2025 12:06:26 +0700 Subject: [PATCH 1/4] fix: support custom reporters in legacy module path `$HOME/.node_libraries` Signed-off-by: hainenber --- e2e/__tests__/customReporters.test.ts | 24 ++++++++++++++++++++++++ packages/jest-config/src/normalize.ts | 18 +++++++++++++++--- packages/jest-util/src/specialChars.ts | 2 +- 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/e2e/__tests__/customReporters.test.ts b/e2e/__tests__/customReporters.test.ts index bdd4b6c2063f..b5ec90970de3 100644 --- a/e2e/__tests__/customReporters.test.ts +++ b/e2e/__tests__/customReporters.test.ts @@ -179,4 +179,28 @@ 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', () => {});", + 'package.json': JSON.stringify({ + jest: { + reporters: ['@org/custom-reporter'], + }, + }), + 'fakeHome/.node_libraries/@org/custom-reporter/index.js': ` + export default class Reporter { + onRunStart() { + throw new Error('ON_RUN_START_ERROR'); + } + }; + `, + }); + + const {stderr, exitCode} = runJest(DIR, undefined, { + env: {HOME: path.resolve(DIR, 'fakeHome')}, + }); + expect(stderr).toMatch(/ON_RUN_START_ERROR/); + expect(exitCode).toBe(1); + }); }); diff --git a/packages/jest-config/src/normalize.ts b/packages/jest-config/src/normalize.ts index e2ed840cf020..e9d7c8568db2 100644 --- a/packages/jest-config/src/normalize.ts +++ b/packages/jest-config/src/normalize.ts @@ -27,6 +27,7 @@ import { replacePathSepForGlob, requireOrImportModule, tryRealpath, + specialChars, } from 'jest-util'; import {ValidationError, validate} from 'jest-validate'; import DEFAULT_CONFIG from './Defaults'; @@ -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( @@ -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( @@ -1087,8 +1099,8 @@ export default async function normalize( newOptions.ci && !argv.updateSnapshot ? 'none' : argv.updateSnapshot - ? 'all' - : 'new'; + ? 'all' + : 'new'; newOptions.maxConcurrency = Number.parseInt( newOptions.maxConcurrency as unknown as string, diff --git a/packages/jest-util/src/specialChars.ts b/packages/jest-util/src/specialChars.ts index e3dc1f561313..580777af26cb 100644 --- a/packages/jest-util/src/specialChars.ts +++ b/packages/jest-util/src/specialChars.ts @@ -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 = { From f0c67cc8a01ffe85c6f5ec79356ba7a97c3b7c1c Mon Sep 17 00:00:00 2001 From: hainenber Date: Sun, 5 Oct 2025 12:14:22 +0700 Subject: [PATCH 2/4] chore: add CHANGELOG entry Signed-off-by: hainenber --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 917db93ebb8c..1bc7bedde190 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,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)) ## 30.2.0 From 1d82a5eda6d9562db8cd880baa3921d36472759b Mon Sep 17 00:00:00 2001 From: hainenber Date: Sun, 5 Oct 2025 13:14:22 +0700 Subject: [PATCH 3/4] chore: use CJS reporter content to work with Node18 + fix lint issues Signed-off-by: hainenber --- e2e/__tests__/customReporters.test.ts | 22 +++++++++++++++------- packages/jest-config/src/normalize.ts | 6 +++--- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/e2e/__tests__/customReporters.test.ts b/e2e/__tests__/customReporters.test.ts index b5ec90970de3..22082da35b19 100644 --- a/e2e/__tests__/customReporters.test.ts +++ b/e2e/__tests__/customReporters.test.ts @@ -183,22 +183,30 @@ describe('Custom Reporters Integration', () => { test('supports custom reporter stored in legacy module path, i.e. $HOME/.node_libraries', () => { writeFiles(DIR, { '__tests__/test.test.js': "test('test', () => {});", - 'package.json': JSON.stringify({ - jest: { - reporters: ['@org/custom-reporter'], - }, - }), 'fakeHome/.node_libraries/@org/custom-reporter/index.js': ` - export default class Reporter { + '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')}, + 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); diff --git a/packages/jest-config/src/normalize.ts b/packages/jest-config/src/normalize.ts index e9d7c8568db2..936f84374d53 100644 --- a/packages/jest-config/src/normalize.ts +++ b/packages/jest-config/src/normalize.ts @@ -26,8 +26,8 @@ import { clearLine, replacePathSepForGlob, requireOrImportModule, - tryRealpath, specialChars, + tryRealpath, } from 'jest-util'; import {ValidationError, validate} from 'jest-validate'; import DEFAULT_CONFIG from './Defaults'; @@ -1099,8 +1099,8 @@ export default async function normalize( newOptions.ci && !argv.updateSnapshot ? 'none' : argv.updateSnapshot - ? 'all' - : 'new'; + ? 'all' + : 'new'; newOptions.maxConcurrency = Number.parseInt( newOptions.maxConcurrency as unknown as string, From 12fedd602ec7a3739b2bd45c5d5424bf2a19052c Mon Sep 17 00:00:00 2001 From: hainenber Date: Sun, 5 Oct 2025 13:17:44 +0700 Subject: [PATCH 4/4] chore: fix accidentally assimilated package.json Signed-off-by: hainenber --- e2e/__tests__/customReporters.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/__tests__/customReporters.test.ts b/e2e/__tests__/customReporters.test.ts index 22082da35b19..3f8db443d1c9 100644 --- a/e2e/__tests__/customReporters.test.ts +++ b/e2e/__tests__/customReporters.test.ts @@ -190,12 +190,12 @@ describe('Custom Reporters Integration', () => { throw new Error('ON_RUN_START_ERROR'); } }; + `, 'package.json': JSON.stringify({ jest: { reporters: ['@org/custom-reporter'], }, }), - `, }); const {stderr, exitCode} = runJest(DIR, undefined, {