Skip to content

Commit

Permalink
fix: isolate esm async import bug (#14397)
Browse files Browse the repository at this point in the history
  • Loading branch information
eryue0220 authored Aug 21, 2023
1 parent 8426b5d commit 58e8491
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 10 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- `[jest-mock]` Revert [#13866](https://github.com/jestjs/jest/pull/13866) as it was a breaking change ([#14429](https://github.com/jestjs/jest/pull/14429))
- `[jest-mock]` Revert [#13867](https://github.com/jestjs/jest/pull/13867) as it was a breaking change ([#14429](https://github.com/jestjs/jest/pull/14429))
- `[@jest/reporters]` Marks Reporter's hooks as optional ([#14433](https://github.com/jestjs/jest/pull/14433))
- `[jest-runtime]` Fix dynamic ESM import module bug when loaded module through `jest.isolateModulesAsync` ([14397](https://github.com/jestjs/jest/pull/14397))

### Chore & Maintenance

Expand Down
9 changes: 9 additions & 0 deletions e2e/__tests__/__snapshots__/isolateModulesAsync.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[`runs test with isolate modules async import 1`] = `
"Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: <<REPLACED>>
Ran all test suites."
`;
20 changes: 20 additions & 0 deletions e2e/__tests__/isolateModulesAsync.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import {extractSummary} from '../Utils';
import runJest from '../runJest';

test('runs test with isolate modules async import', () => {
const {exitCode, stderr} = runJest('isolate-modules-async', [], {
nodeOptions: '--experimental-vm-modules --no-warnings',
});

const {summary} = extractSummary(stderr);

expect(summary).toMatchSnapshot();
expect(exitCode).toBe(0);
});
22 changes: 22 additions & 0 deletions e2e/isolate-modules-async/__tests__/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import {jest} from '@jest/globals';

test('should have a fresh module state in each isolateModulesAsync context', async () => {
await jest.isolateModulesAsync(async () => {
const {getState, incState} = await import('../main.js');
expect(getState()).toBe(0);
incState();
expect(getState()).toBe(1);
});
await jest.isolateModulesAsync(async () => {
const {getState, incState} = await import('../main.js');
expect(getState()).toBe(0);
incState();
expect(getState()).toBe(1);
});
});
15 changes: 15 additions & 0 deletions e2e/isolate-modules-async/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
let myState = 0;

export function incState() {
myState += 1;
}

export function getState() {
return myState;
}
8 changes: 8 additions & 0 deletions e2e/isolate-modules-async/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "isolate-modules-async",
"type": "module",
"jest": {
"transform": {},
"testEnvironment": "node"
}
}
27 changes: 17 additions & 10 deletions packages/jest-runtime/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -416,12 +416,15 @@ export default class Runtime {
query = '',
): Promise<VMModule> {
const cacheKey = modulePath + query;
const registry = this._isolatedModuleRegistry
? this._isolatedModuleRegistry
: this._esmoduleRegistry;

if (this._fileTransformsMutex.has(cacheKey)) {
await this._fileTransformsMutex.get(cacheKey);
}

if (!this._esmoduleRegistry.has(cacheKey)) {
if (!registry.has(cacheKey)) {
invariant(
typeof this._environment.getVmContext === 'function',
'ES Modules are only supported if your test environment has the `getVmContext` function',
Expand Down Expand Up @@ -454,15 +457,15 @@ export default class Runtime {
context,
);

this._esmoduleRegistry.set(cacheKey, wasm);
registry.set(cacheKey, wasm);

transformResolve();
return wasm;
}

if (this._resolver.isCoreModule(modulePath)) {
const core = this._importCoreModule(modulePath, context);
this._esmoduleRegistry.set(cacheKey, core);
registry.set(cacheKey, core);

transformResolve();

Expand Down Expand Up @@ -526,11 +529,11 @@ export default class Runtime {
}

invariant(
!this._esmoduleRegistry.has(cacheKey),
!registry.has(cacheKey),
`Module cache already has entry ${cacheKey}. This is a bug in Jest, please report it!`,
);

this._esmoduleRegistry.set(cacheKey, module);
registry.set(cacheKey, module);

transformResolve();
} catch (error) {
Expand All @@ -539,7 +542,7 @@ export default class Runtime {
}
}

const module = this._esmoduleRegistry.get(cacheKey);
const module = registry.get(cacheKey);

invariant(
module,
Expand All @@ -563,14 +566,18 @@ export default class Runtime {
return;
}

const registry = this._isolatedModuleRegistry
? this._isolatedModuleRegistry
: this._esmoduleRegistry;

if (specifier === '@jest/globals') {
const fromCache = this._esmoduleRegistry.get('@jest/globals');
const fromCache = registry.get('@jest/globals');

if (fromCache) {
return fromCache;
}
const globals = this.getGlobalsForEsm(referencingIdentifier, context);
this._esmoduleRegistry.set('@jest/globals', globals);
registry.set('@jest/globals', globals);

return globals;
}
Expand All @@ -586,7 +593,7 @@ export default class Runtime {
return this.importMock(referencingIdentifier, specifier, context);
}

const fromCache = this._esmoduleRegistry.get(specifier);
const fromCache = registry.get(specifier);

if (fromCache) {
return fromCache;
Expand Down Expand Up @@ -662,7 +669,7 @@ export default class Runtime {
}
}

this._esmoduleRegistry.set(specifier, module);
registry.set(specifier, module);
return module;
}

Expand Down

0 comments on commit 58e8491

Please sign in to comment.