Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
4 changes: 0 additions & 4 deletions docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -1482,10 +1482,6 @@ type ResolverOptions = {
moduleDirectory?: Array<string>;
/** List of `require.paths` to use if nothing is found in `node_modules`. */
paths?: Array<string>;
/** Allows transforming parsed `package.json` contents. */
packageFilter?: (pkg: PackageJSON, file: string, dir: string) => PackageJSON;
/** Allows transforms a path within a package. */
pathFilter?: (pkg: PackageJSON, path: string, relativePath: string) => string;
/** Current root directory. */
rootDir?: string;
};
Expand Down
4 changes: 2 additions & 2 deletions e2e/__tests__/__snapshots__/moduleNameMapper.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ exports[`moduleNameMapper wrong array configuration 1`] = `
12 | module.exports = () => 'test';
13 |

at createNoMappedModuleFoundError (../../packages/jest-resolve/build/index.js:1184:17)
at createNoMappedModuleFoundError (../../packages/jest-resolve/build/index.js:1080:17)
at Object.require (index.js:10:1)
at Object.require (__tests__/index.js:10:20)"
`;
Expand Down Expand Up @@ -71,7 +71,7 @@ exports[`moduleNameMapper wrong configuration 1`] = `
12 | module.exports = () => 'test';
13 |

at createNoMappedModuleFoundError (../../packages/jest-resolve/build/index.js:1184:17)
at createNoMappedModuleFoundError (../../packages/jest-resolve/build/index.js:1080:17)
at Object.require (index.js:10:1)
at Object.require (__tests__/index.js:10:20)"
`;
2 changes: 1 addition & 1 deletion e2e/__tests__/__snapshots__/requireMissingExt.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ exports[`shows a proper error from deep requires 1`] = `
12 | test('dummy', () => {
13 | expect(1).toBe(1);

at Resolver._throwModNotFoundError (../../packages/jest-resolve/build/index.js:930:11)
at Resolver._throwModNotFoundError (../../packages/jest-resolve/build/index.js:826:11)
at Object.<anonymous> (node_modules/discord.js/src/index.js:21:12)
at Object.require (__tests__/test.js:10:1)"
`;
2 changes: 1 addition & 1 deletion e2e/pnp/__tests__/undeclared-dependency.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
it('should surface pnp errors', () => {
expect(() => {
require('undeclared');
}).toThrow(expect.objectContaining({code: 'MODULE_NOT_FOUND'}));
}).toThrow("Cannot find module 'unesitent_module__'");
});
10 changes: 3 additions & 7 deletions packages/jest-resolve/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,13 @@
"chalk": "^4.0.0",
"graceful-fs": "^4.2.9",
"jest-haste-map": "workspace:*",
"jest-pnp-resolver": "^1.2.3",
"jest-util": "workspace:*",
"jest-validate": "workspace:*",
"resolve": "^1.20.0",
"resolve.exports": "^2.0.0",
"slash": "^3.0.0"
"slash": "^3.0.0",
"unrs-resolver": "^1.7.8"
},
"devDependencies": {
"@types/graceful-fs": "^4.1.3",
"@types/pnpapi": "^0.0.5",
"@types/resolve": "^1.20.2"
"@types/graceful-fs": "^4.1.3"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
Expand Down
73 changes: 9 additions & 64 deletions packages/jest-resolve/src/__tests__/resolve.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,43 +6,26 @@
*
*/

import * as path from 'path';
import {fileURLToPath, pathToFileURL} from 'url';
import * as fs from 'graceful-fs';
import {sync as resolveSync} from 'resolve';
import {type IModuleMap, ModuleMap} from 'jest-haste-map';
import * as path from 'path';
import {pathToFileURL} from 'url';

import userResolver from '../__mocks__/userResolver';
import userResolverAsync from '../__mocks__/userResolverAsync';
import defaultResolver, {type PackageFilter} from '../defaultResolver';
import defaultResolver from '../defaultResolver';
import nodeModulesPaths from '../nodeModulesPaths';
import Resolver from '../resolver';
import type {ResolverConfig} from '../types';

jest.mock('../__mocks__/userResolver').mock('../__mocks__/userResolverAsync');

// Do not fully mock `resolve` because it is used by Jest. Doing it will crash
// in very strange ways. Instead, just spy on it and its `sync` method.
jest.mock('resolve', () => {
const originalModule =
jest.requireActual<typeof import('resolve')>('resolve');

const m = jest.fn<typeof import('resolve')>((...args) =>
originalModule(...args),
);
Object.assign(m, originalModule);
m.sync = jest.spyOn(originalModule, 'sync');

return m;
});

const mockUserResolver = jest.mocked(userResolver);
const mockUserResolverAsync = jest.mocked(userResolverAsync);
const mockResolveSync = jest.mocked(resolveSync);

beforeEach(() => {
mockUserResolver.mockClear();
mockUserResolverAsync.async.mockClear();
mockResolveSync.mockClear();

Resolver.clearDefaultResolverCache();
});
Expand Down Expand Up @@ -134,25 +117,6 @@ describe('findNodeModule', () => {
});
});

it('wraps passed packageFilter to the resolve module when using the default resolver', () => {
const packageFilter = jest.fn<PackageFilter>();

// A resolver that delegates to defaultResolver with a packageFilter implementation
mockUserResolver.mockImplementation((request, opts) =>
opts.defaultResolver(request, {...opts, packageFilter}),
);

Resolver.findNodeModule('./test', {
basedir: path.resolve(__dirname, '../__mocks__/'),
resolver: require.resolve('../__mocks__/userResolver'),
});

expect(packageFilter).toHaveBeenCalledWith(
expect.objectContaining({name: '__mocks__'}),
expect.any(String),
);
});

it('supports file URLs', () => {
const path = pathToFileURL(__filename).href;
const newPath = Resolver.findNodeModule(path, {
Expand Down Expand Up @@ -209,7 +173,7 @@ describe('findNodeModule', () => {
);
});

test('respects order in package.json, not conditions', () => {
test('respects order in conditions over package.json', () => {
Copy link
Collaborator Author

@JounQin JounQin May 29, 2025

Choose a reason for hiding this comment

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

I test with node -C x -C require -C import vs node -C x -C import -C require, the order actually matters, so this test case is a false postive, and I've changed the behavior at unrs/unrs-resolver#115 for un-ts/eslint-plugin-import-x#272 (comment), but if the previous behavior is still desired, I'll consider to add a new option to control whether the order of conditionNames should matter.

cc @cpojer @SimenB

const resultImport = Resolver.findNodeModule('exports', {
basedir: conditionsRoot,
conditions: ['import', 'require'],
Expand All @@ -219,7 +183,7 @@ describe('findNodeModule', () => {
conditions: ['require', 'import'],
});

expect(resultImport).toEqual(resultRequire);
expect(resultImport).not.toEqual(resultRequire);
});

test('supports nested paths', () => {
Expand Down Expand Up @@ -407,7 +371,9 @@ describe('findNodeModule', () => {
basedir: path.resolve(importsRoot, './foo-import/index.js'),
conditions: [],
});
}).toThrow('Missing "#something-else" specifier in "foo-import" package');
}).toThrow(
`Package import specifier "#something-else" is not defined in package ${path.join(importsRoot, 'foo-import/package.json')}`,
);
});
});
});
Expand Down Expand Up @@ -446,27 +412,6 @@ describe('findNodeModuleAsync', () => {
});
});

it('passes packageFilter to the resolve module when using the default resolver', async () => {
const packageFilter = jest.fn<PackageFilter>();

// A resolver that delegates to defaultResolver with a packageFilter implementation
mockUserResolverAsync.async.mockImplementation((request, opts) =>
Promise.resolve(opts.defaultResolver(request, {...opts, packageFilter})),
);

await Resolver.findNodeModuleAsync('test', {
basedir: '/',
resolver: require.resolve('../__mocks__/userResolverAsync'),
});

expect(mockResolveSync).toHaveBeenCalledWith(
'test',
expect.objectContaining({
packageFilter,
}),
);
});

it('supports file URLs', async () => {
const path = pathToFileURL(__filename).href;
const newPath = await Resolver.findNodeModuleAsync(path, {
Expand Down
Loading
Loading