Skip to content

Commit

Permalink
[jest-resolve] Add async resolver support (#11540)
Browse files Browse the repository at this point in the history
Co-authored-by: Simen Bekkhus <sbekkhus91@gmail.com>
  • Loading branch information
IanVS and SimenB authored Feb 22, 2022
1 parent eafc350 commit 2d0496b
Show file tree
Hide file tree
Showing 21 changed files with 872 additions and 110 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
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/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
Original file line number Diff line number Diff line change
@@ -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."
`;
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"type": "module",
"jest": {
"resolver": "<rootDir>/resolver.cjs",
"transform": {
}
}
}
24 changes: 24 additions & 0 deletions e2e/resolve-async/resolver.cjs
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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');
},
};
Loading

0 comments on commit 2d0496b

Please sign in to comment.