Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[jest-resolve] Add async resolver support #11540

Merged
merged 50 commits into from Feb 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
7347e92
WIP add async defaultResolver
IanVS Jun 8, 2021
74f1fc5
Create ResolverAsync class
IanVS Jun 8, 2021
66c6356
Forget about meta
IanVS Jun 8, 2021
3916baf
Set asyncResolver properly
IanVS Jun 8, 2021
fa67da8
Add async tests
IanVS Jun 8, 2021
f2e9bb0
Update snapshot tests
IanVS Jun 9, 2021
adaa85f
Recombine into a single class with sync and async methods
IanVS Aug 31, 2021
e9605d3
Use named export for sync defaultResolver
IanVS Aug 31, 2021
aabc2af
Attempt to explain new resolver option
IanVS Aug 31, 2021
04cb717
Consolidate to just defaultResolver in resolver options
IanVS Aug 31, 2021
211e9cb
Fix bad rebase
IanVS Sep 10, 2021
217b8cd
Improve import format of resolve
IanVS Sep 10, 2021
d12bac2
Change questions to TODOs
IanVS Sep 10, 2021
3a544bf
Return pnpResolver result directly
IanVS Sep 10, 2021
2f22e63
Update snapshots
IanVS Sep 10, 2021
b032ef5
Apply changes from #11817 to async method
IanVS Sep 10, 2021
67fce99
Fix test
IanVS Sep 10, 2021
fcccde3
add @ts-expect-error for now
IanVS Sep 10, 2021
af0870d
Update snapshot, again
IanVS Sep 10, 2021
38588b1
Update snapshots
IanVS Sep 13, 2021
a818709
fix mock
SimenB Sep 11, 2021
9cbf64c
Pass conditions from options, update async test
IanVS Sep 13, 2021
e58d96b
Update snapshots
IanVS Sep 14, 2021
46da513
Merge commit 'b5aec031393f465b3513bd221d7ff6ab17a3e2d9~' into 9505-je…
SimenB Dec 15, 2021
bd51216
Merge commit 'b5aec031393f465b3513bd221d7ff6ab17a3e2d9' into 9505-jes…
SimenB Dec 15, 2021
24a8538
Merge branch 'main' into 9505-jest-resolve-async
SimenB Dec 15, 2021
f55fa07
moar package filter
SimenB Dec 15, 2021
a5bd891
Update packages/jest-resolve/src/fileWalkers.ts
IanVS Dec 21, 2021
5944e4d
Update packages/jest-resolve/src/fileWalkers.ts
IanVS Dec 21, 2021
2744433
Update packages/jest-resolve/src/defaultResolver.ts
IanVS Dec 21, 2021
70bddfe
Update packages/jest-resolve/src/defaultResolver.ts
IanVS Dec 21, 2021
6a8fa3b
Merge commit '11d79ec096a25851124356095d60352f6ca2824e' into 9505-jes…
SimenB Feb 22, 2022
a4b0c8e
Merge commit 'b9e3a55ccbf4c1228190ca3eb47bc680abba103b~' into 9505-je…
SimenB Feb 22, 2022
455b072
Merge commit 'b9e3a55ccbf4c1228190ca3eb47bc680abba103b' into 9505-jes…
SimenB Feb 22, 2022
23cc87c
Merge commit '199f9811ae68b15879cbe18b7ef7ebd61eefcf23~' into 9505-je…
SimenB Feb 22, 2022
7344e67
remove Path
SimenB Feb 22, 2022
2d72dab
Merge commit '199f9811ae68b15879cbe18b7ef7ebd61eefcf23' into 9505-jes…
SimenB Feb 22, 2022
e7de5dc
Merge commit 'dec768394f750ca96c932d23a2e7cfe164eec866~' into 9505-je…
SimenB Feb 22, 2022
aab0bf9
Merge commit 'dec768394f750ca96c932d23a2e7cfe164eec866' into 9505-jes…
SimenB Feb 22, 2022
c99ecad
Merge branch 'main' into 9505-jest-resolve-async
SimenB Feb 22, 2022
8c21ab5
remove async from default resolver
SimenB Feb 22, 2022
8cb9c49
docs cleanup
SimenB Feb 22, 2022
c009333
remove unused type
SimenB Feb 22, 2022
8257710
move things to reduce diff
SimenB Feb 22, 2022
9867dc2
changelog
SimenB Feb 22, 2022
b2b7d4b
use in runtime
SimenB Feb 22, 2022
6595c16
snaps
SimenB Feb 22, 2022
067bb55
validate custom resolver
SimenB Feb 22, 2022
c6a2710
async should mock
SimenB Feb 22, 2022
6c4db08
e2e
SimenB Feb 22, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -16,6 +16,7 @@
- `[jest-mock]` Improve `isMockFunction` to infer types of passed function ([#12442](https://github.com/facebook/jest/pull/12442))
- `[jest-resolve]` [**BREAKING**] Add support for `package.json` `exports` ([#11961](https://github.com/facebook/jest/pull/11961), [#12373](https://github.com/facebook/jest/pull/12373))
- `[jest-resolve, jest-runtime]` Add support for `data:` URI import and mock ([#12392](https://github.com/facebook/jest/pull/12392))
- `[jest-resolve, jest-runtime]` Add support for async resolver ([#11540](https://github.com/facebook/jest/pull/11540))
- `[@jest/schemas]` New module for JSON schemas for Jest's config ([#12384](https://github.com/facebook/jest/pull/12384))
- `[jest-worker]` [**BREAKING**] Allow only absolute `workerPath` ([#12343](https://github.com/facebook/jest/pull/12343))
- `[pretty-format]` New `maxWidth` parameter ([#12402](https://github.com/facebook/jest/pull/12402))
Expand Down
13 changes: 8 additions & 5 deletions docs/Configuration.md
Expand Up @@ -779,13 +779,18 @@ By default, each test file gets its own independent module registry. Enabling `r

Default: `undefined`

This option allows the use of a custom resolver. This resolver must be a node module that exports a function expecting a string as the first argument for the path to resolve and an object with the following structure as the second argument:
This option allows the use of a custom resolver. This resolver must be a node module that exports _either_:

1. a function expecting a string as the first argument for the path to resolve and an options object as the second argument. The function should either return a path to the module that should be resolved or throw an error if the module can't be found. _or_
2. an object containing `async` and/or `sync` properties. The `sync` property should be a function with the shape explained above, and the `async` property should also be a function that accepts the same arguments, but returns a promise which resolves with the path to the module or rejects with an error.

The options object provided to resolvers has the shape:

```json
{
"basedir": string,
"conditions": [string],
"defaultResolver": "function(request, options)",
"defaultResolver": "function(request, options) -> string",
"extensions": [string],
"moduleDirectory": [string],
"paths": [string],
Expand All @@ -795,9 +800,7 @@ This option allows the use of a custom resolver. This resolver must be a node mo
}
```

The function should either return a path to the module that should be resolved or throw an error if the module can't be found.

Note: the defaultResolver passed as an option is the Jest default resolver which might be useful when you write your custom one. It takes the same arguments as your custom one, e.g. `(request, options)`.
Note: the `defaultResolver` passed as an option is the Jest default resolver which might be useful when you write your custom one. It takes the same arguments as your custom synchronous one, e.g. `(request, options)` and returns a string or throws.

For example, if you want to respect Browserify's [`"browser"` field](https://github.com/browserify/browserify-handbook/blob/master/readme.markdown#browser-field), you can use the following configuration:

Expand Down
4 changes: 2 additions & 2 deletions e2e/__tests__/__snapshots__/moduleNameMapper.test.ts.snap
Expand Up @@ -41,7 +41,7 @@ exports[`moduleNameMapper wrong array configuration 1`] = `
12 | module.exports = () => 'test';
13 |

at createNoMappedModuleFoundError (../../packages/jest-resolve/build/resolver.js:572:17)
at createNoMappedModuleFoundError (../../packages/jest-resolve/build/resolver.js:897:17)
at Object.require (index.js:10:1)"
`;

Expand Down Expand Up @@ -70,6 +70,6 @@ exports[`moduleNameMapper wrong configuration 1`] = `
12 | module.exports = () => 'test';
13 |

at createNoMappedModuleFoundError (../../packages/jest-resolve/build/resolver.js:572:17)
at createNoMappedModuleFoundError (../../packages/jest-resolve/build/resolver.js:897:17)
at Object.require (index.js:10:1)"
`;
9 changes: 9 additions & 0 deletions e2e/__tests__/__snapshots__/resolveAsync.test.ts.snap
@@ -0,0 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`on node >=12.16.0 runs test with native ESM 1`] = `
"Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: <<REPLACED>>
Ran all test suites."
`;
Expand Up @@ -37,6 +37,6 @@ exports[`show error message with matching files 1`] = `
| ^
9 |

at Resolver.resolveModule (../../packages/jest-resolve/build/resolver.js:317:11)
at Resolver._throwModNotFoundError (../../packages/jest-resolve/build/resolver.js:491:11)
at Object.require (index.js:8:18)"
`;
25 changes: 25 additions & 0 deletions e2e/__tests__/resolveAsync.test.ts
@@ -0,0 +1,25 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import {onNodeVersions} from '@jest/test-utils';
import {extractSummary} from '../Utils';
import runJest from '../runJest';

// The versions where vm.Module exists and commonjs with "exports" is not broken
onNodeVersions('>=12.16.0', () => {
test('runs test with native ESM', () => {
const {exitCode, stderr, stdout} = runJest('resolve-async', [], {
nodeOptions: '--experimental-vm-modules --no-warnings',
});

const {summary} = extractSummary(stderr);

expect(summary).toMatchSnapshot();
expect(stdout).toBe('');
expect(exitCode).toBe(0);
});
});
12 changes: 12 additions & 0 deletions e2e/resolve-async/__tests__/resolveAsync.test.js
@@ -0,0 +1,12 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import greeting from '../some-file';

test('async resolver resolves to correct file', () => {
expect(greeting).toEqual('Hello from mapped file!!');
});
8 changes: 8 additions & 0 deletions e2e/resolve-async/package.json
@@ -0,0 +1,8 @@
{
"type": "module",
"jest": {
"resolver": "<rootDir>/resolver.cjs",
"transform": {
}
}
}
24 changes: 24 additions & 0 deletions e2e/resolve-async/resolver.cjs
@@ -0,0 +1,24 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

const {promisify} = require('util');

const wait = promisify(setTimeout);

module.exports = {
async: async (request, opts) => {
await wait(500);

if (request === '../some-file') {
request = '../some-other-file';
}

return opts.defaultResolver(request, opts);
},
};
8 changes: 8 additions & 0 deletions e2e/resolve-async/some-other-file.js
@@ -0,0 +1,8 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

export default 'Hello from mapped file!!';
1 change: 0 additions & 1 deletion e2e/resolve-get-paths/__tests__/resolveGetPaths.test.js
Expand Up @@ -4,7 +4,6 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';

import {resolve} from 'path';

Expand Down
1 change: 0 additions & 1 deletion e2e/resolve-with-paths/__tests__/resolveWithPaths.test.js
Expand Up @@ -4,7 +4,6 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';

import {resolve} from 'path';

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions packages/jest-resolve/src/__mocks__/package.json
@@ -1,6 +1,5 @@
{
"name": "__mocks__",
"version": "1.0.0",
"dependencies": {
}
"dependencies": {}
}
8 changes: 2 additions & 6 deletions packages/jest-resolve/src/__mocks__/userResolver.d.ts
Expand Up @@ -5,12 +5,8 @@
* LICENSE file in the root directory of this source tree.
*/

import defaultResolver from '../defaultResolver';
import type {Resolver} from '../defaultResolver';

// todo: can be replaced with jest.MockedFunction
declare const userResolver: jest.MockInstance<
ReturnType<typeof defaultResolver>,
Parameters<typeof defaultResolver>
>;
declare const userResolver: Resolver;

export default userResolver;
13 changes: 13 additions & 0 deletions packages/jest-resolve/src/__mocks__/userResolverAsync.d.ts
@@ -0,0 +1,13 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import type {Resolver} from '../defaultResolver';

// todo: can be replaced with jest.MockedFunction
declare const userResolver: Resolver;

export default userResolver;
14 changes: 14 additions & 0 deletions packages/jest-resolve/src/__mocks__/userResolverAsync.js
@@ -0,0 +1,14 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

module.exports = {
async: function userResolver(path, options) {
return Promise.resolve('module');
},
};