Skip to content

Commit 2ec6d24

Browse files
lvqqjeysal
andauthored
fix: add global path in require.resolve.paths (#13633)
* fix: add global path in require.resolve.paths * test: update snapshot * test: update snapshot * test: add builtin module test case * refactor: grap global paths only once * test: update cases and snapshot * chore: add path join and update test case * test: update test cases * clarify and add changelog Co-authored-by: Tim Seckinger <seckinger.tim@gmail.com>
1 parent ef91356 commit 2ec6d24

File tree

7 files changed

+97
-9
lines changed

7 files changed

+97
-9
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
### Fixes
66

7+
- `[jest-resolve]` add global paths to `require.resolve.paths` ([#13633](https://github.com/facebook/jest/pull/13633))
8+
79
### Chore & Maintenance
810

911
- `[@jest/fake-timers]` Update `@sinonjs/fake-timers` ([#13612](https://github.com/facebook/jest/pull/13612))

e2e/__tests__/__snapshots__/moduleNameMapper.test.ts.snap

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ exports[`moduleNameMapper wrong array configuration 1`] = `
4141
12 | module.exports = () => 'test';
4242
13 |
4343
44-
at createNoMappedModuleFoundError (../../packages/jest-resolve/build/resolver.js:752:17)
44+
at createNoMappedModuleFoundError (../../packages/jest-resolve/build/resolver.js:758:17)
4545
at Object.require (index.js:10:1)
4646
at Object.require (__tests__/index.js:10:20)"
4747
`;
@@ -71,7 +71,7 @@ exports[`moduleNameMapper wrong configuration 1`] = `
7171
12 | module.exports = () => 'test';
7272
13 |
7373
74-
at createNoMappedModuleFoundError (../../packages/jest-resolve/build/resolver.js:752:17)
74+
at createNoMappedModuleFoundError (../../packages/jest-resolve/build/resolver.js:758:17)
7575
at Object.require (index.js:10:1)
7676
at Object.require (__tests__/index.js:10:20)"
7777
`;

packages/jest-resolve/src/__tests__/resolve.test.ts

+47
Original file line numberDiff line numberDiff line change
@@ -707,3 +707,50 @@ describe('Resolver.getModulePaths() -> nodeModulesPaths()', () => {
707707
expect(dirs_actual).toEqual(expect.arrayContaining(dirs_expected));
708708
});
709709
});
710+
711+
describe('Resolver.getGlobalPaths()', () => {
712+
const _path = path;
713+
let moduleMap: IModuleMap;
714+
beforeEach(() => {
715+
moduleMap = ModuleMap.create('/');
716+
});
717+
718+
it('return global paths with npm package', () => {
719+
jest.doMock('path', () => _path.posix);
720+
const resolver = new Resolver(moduleMap, {} as ResolverConfig);
721+
const globalPaths = resolver.getGlobalPaths('jest');
722+
globalPaths.forEach(globalPath =>
723+
expect(require.resolve.paths('jest')).toContain(globalPath),
724+
);
725+
});
726+
727+
it('return empty array with builtin module', () => {
728+
jest.doMock('path', () => _path.posix);
729+
const resolver = new Resolver(moduleMap, {} as ResolverConfig);
730+
const globalPaths = resolver.getGlobalPaths('fs');
731+
expect(globalPaths).toStrictEqual([]);
732+
});
733+
734+
it('return global paths with absolute path', () => {
735+
jest.doMock('path', () => _path.posix);
736+
const resolver = new Resolver(moduleMap, {} as ResolverConfig);
737+
const globalPaths = resolver.getGlobalPaths('/');
738+
globalPaths.forEach(globalPath =>
739+
expect(require.resolve.paths('/')).toContain(globalPath),
740+
);
741+
});
742+
743+
it('return empty array with relative path', () => {
744+
jest.doMock('path', () => _path.posix);
745+
const resolver = new Resolver(moduleMap, {} as ResolverConfig);
746+
const globalPaths = resolver.getGlobalPaths('./');
747+
expect(globalPaths).toStrictEqual([]);
748+
});
749+
750+
it('return empty array without module name', () => {
751+
jest.doMock('path', () => _path.posix);
752+
const resolver = new Resolver(moduleMap, {} as ResolverConfig);
753+
const globalPaths = resolver.getGlobalPaths();
754+
expect(globalPaths).toStrictEqual([]);
755+
});
756+
});

packages/jest-resolve/src/nodeModulesPaths.ts

+14
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,17 @@ export default function nodeModulesPaths(
7070

7171
return options.paths ? dirs.concat(options.paths) : dirs;
7272
}
73+
74+
function findGlobalPaths(): Array<string> {
75+
const {root} = path.parse(process.cwd());
76+
const globalPath = path.join(root, 'node_modules');
77+
const resolvePaths = require.resolve.paths('/');
78+
79+
if (resolvePaths) {
80+
// the global paths start one after the root node_modules
81+
const rootIndex = resolvePaths.indexOf(globalPath);
82+
return rootIndex > -1 ? resolvePaths.slice(rootIndex + 1) : [];
83+
}
84+
return [];
85+
}
86+
export const GlobalPaths = findGlobalPaths();

packages/jest-resolve/src/resolver.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import defaultResolver, {
2020
} from './defaultResolver';
2121
import {clearFsCache} from './fileWalkers';
2222
import isBuiltinModule from './isBuiltinModule';
23-
import nodeModulesPaths from './nodeModulesPaths';
23+
import nodeModulesPaths, {GlobalPaths} from './nodeModulesPaths';
2424
import shouldLoadAsEsm, {clearCachedLookups} from './shouldLoadAsEsm';
2525
import type {ResolverConfig} from './types';
2626

@@ -526,6 +526,14 @@ export default class Resolver {
526526
return paths;
527527
}
528528

529+
getGlobalPaths(moduleName?: string): Array<string> {
530+
if (!moduleName || moduleName[0] === '.' || this.isCoreModule(moduleName)) {
531+
return [];
532+
}
533+
534+
return GlobalPaths;
535+
}
536+
529537
getModuleID(
530538
virtualMocks: Map<string, boolean>,
531539
from: string,

packages/jest-runtime/src/__tests__/runtime_require_module.test.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,13 @@ describe('Runtime requireModule', () => {
132132
'RegularModule',
133133
);
134134
expect(exports.paths.length).toBeGreaterThan(0);
135-
exports.paths.forEach(path => {
136-
expect(moduleDirectories.some(dir => path.endsWith(dir))).toBe(true);
135+
const root = path.parse(process.cwd()).root;
136+
const globalPath = path.join(root, 'node_modules');
137+
const rootIndex = exports.paths.findIndex(path => path === globalPath);
138+
exports.paths.forEach((path, index) => {
139+
if (index <= rootIndex) {
140+
expect(moduleDirectories.some(dir => path.endsWith(dir))).toBe(true);
141+
}
137142
});
138143
});
139144

packages/jest-runtime/src/index.ts

+16-4
Original file line numberDiff line numberDiff line change
@@ -1066,7 +1066,13 @@ export default class Runtime {
10661066
} else {
10671067
// Only include the fromPath if a moduleName is given. Else treat as root.
10681068
const fromPath = moduleName ? from : null;
1069-
this._execModule(localModule, options, moduleRegistry, fromPath);
1069+
this._execModule(
1070+
localModule,
1071+
options,
1072+
moduleRegistry,
1073+
fromPath,
1074+
moduleName,
1075+
);
10701076
}
10711077
localModule.loaded = true;
10721078
}
@@ -1398,6 +1404,7 @@ export default class Runtime {
13981404
}
13991405

14001406
private _requireResolvePaths(from: string, moduleName?: string) {
1407+
const fromDir = path.resolve(from, '..');
14011408
if (moduleName == null) {
14021409
throw new Error(
14031410
'The first argument to require.resolve.paths must be a string. Received null or undefined.',
@@ -1410,19 +1417,22 @@ export default class Runtime {
14101417
}
14111418

14121419
if (moduleName[0] === '.') {
1413-
return [path.resolve(from, '..')];
1420+
return [fromDir];
14141421
}
14151422
if (this._resolver.isCoreModule(moduleName)) {
14161423
return null;
14171424
}
1418-
return this._resolver.getModulePaths(path.resolve(from, '..'));
1425+
const modulePaths = this._resolver.getModulePaths(fromDir);
1426+
const globalPaths = this._resolver.getGlobalPaths(moduleName);
1427+
return [...modulePaths, ...globalPaths];
14191428
}
14201429

14211430
private _execModule(
14221431
localModule: InitialModule,
14231432
options: InternalModuleOptions | undefined,
14241433
moduleRegistry: ModuleRegistry,
14251434
from: string | null,
1435+
moduleName?: string,
14261436
) {
14271437
if (this.isTornDown) {
14281438
this._logFormattedReferenceError(
@@ -1454,8 +1464,10 @@ export default class Runtime {
14541464
return moduleRegistry.get(key) || null;
14551465
},
14561466
});
1467+
const modulePaths = this._resolver.getModulePaths(module.path);
1468+
const globalPaths = this._resolver.getGlobalPaths(moduleName);
1469+
module.paths = [...modulePaths, ...globalPaths];
14571470

1458-
module.paths = this._resolver.getModulePaths(module.path);
14591471
Object.defineProperty(module, 'require', {
14601472
value: this._createRequireImplementation(module, options),
14611473
});

0 commit comments

Comments
 (0)