Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b69e2de

Browse files
committed
fix issue with awaiting cjs tests even when they return promise (that should not have been resolved)
1 parent e0948b0 commit b69e2de

4 files changed

Lines changed: 51 additions & 23 deletions

File tree

packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,17 @@ const jestAdapter = async (
9393
if (esm) {
9494
await runtime.unstable_importModule(testPath);
9595
} else {
96-
await runtime.requireModuleWithEsmPreload(testPath);
96+
// Await the ESM preload *before* loading the test file so that
97+
// requireModule() stays synchronous. This preserves jest-circus's
98+
// async-definition detection: microtasks queued by the test file
99+
// (e.g. Promise.resolve().then(() => test(...))) must not flush
100+
// until after run_start has set hasStarted=true.
101+
await runtime.enterCjsEsmContext(testPath);
102+
try {
103+
runtime.requireModule(testPath);
104+
} finally {
105+
runtime.leaveCjsEsmContext();
106+
}
97107
}
98108

99109
const setupAfterEnvPerfStats = {

packages/jest-jasmine2/src/index.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,14 @@ export default async function jasmine2(
196196
if (esm) {
197197
await runtime.unstable_importModule(testPath);
198198
} else {
199-
await runtime.requireModuleWithEsmPreload(testPath);
199+
// Await the ESM preload *before* loading the test file so that
200+
// requireModule() stays synchronous (same timing rationale as jestAdapter).
201+
await runtime.enterCjsEsmContext(testPath);
202+
try {
203+
runtime.requireModule(testPath);
204+
} finally {
205+
runtime.leaveCjsEsmContext();
206+
}
200207
}
201208

202209
await env.execute();

packages/jest-runtime/src/__tests__/runtime_esm_cjs_interop.test.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -114,17 +114,14 @@ describe('Runtime requireModuleWithEsmPreload', () => {
114114
createRuntime = require('createRuntime');
115115
});
116116

117-
itVm(
118-
'allows a CJS entry file to require() an .mjs dependency',
119-
async () => {
120-
const runtime = await createRuntime(__filename, {rootDir: ROOT_DIR});
121-
const exports = (await runtime.requireModuleWithEsmPreload(
122-
FROM,
123-
'./cjs-requires-esm-dep.cjs',
124-
)) as any;
125-
expect(exports.esmValue).toBe(99);
126-
},
127-
);
117+
itVm('allows a CJS entry file to require() an .mjs dependency', async () => {
118+
const runtime = await createRuntime(__filename, {rootDir: ROOT_DIR});
119+
const exports = (await runtime.requireModuleWithEsmPreload(
120+
FROM,
121+
'./cjs-requires-esm-dep.cjs',
122+
)) as any;
123+
expect(exports.esmValue).toBe(99);
124+
});
128125
});
129126

130127
describe('Runtime loadCjsAsEsm SyntaxError fallback', () => {

packages/jest-runtime/src/index.ts

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,21 +1130,35 @@ export default class Runtime {
11301130
// Like requireModule but async-safe: pre-loads ESM transitive dependencies
11311131
// before executing the CJS module so that require() calls inside it that
11321132
// resolve to ESM files succeed (they are served from the ESM cache).
1133-
async requireModuleWithEsmPreload<T = unknown>(
1134-
from: string,
1135-
moduleName?: string,
1136-
): Promise<T> {
1133+
// Preload all ESM deps reachable from the given CJS entry and arm the
1134+
// CJS-as-ESM flag so a subsequent synchronous requireModule() can serve
1135+
// those deps from the ESM registry. Must be paired with leaveCjsEsmContext()
1136+
// once requireModule returns. This two-step API lets callers (e.g.
1137+
// jestAdapter) put the await *before* the test file is loaded, preserving
1138+
// jest-circus's async-definition detection (which relies on no microtask
1139+
// flush happening between requireModule() and run_start being dispatched).
1140+
async enterCjsEsmContext(from: string, moduleName?: string): Promise<void> {
11371141
if (runtimeSupportsVmModules) {
11381142
const modulePath = this._resolveCjsModule(from, moduleName);
11391143
await this._preloadEsmDependencies(modulePath);
11401144
this._resolvingCjsAsEsm = true;
1141-
try {
1142-
return this.requireModule<T>(from, moduleName);
1143-
} finally {
1144-
this._resolvingCjsAsEsm = false;
1145-
}
11461145
}
1147-
return this.requireModule<T>(from, moduleName);
1146+
}
1147+
1148+
leaveCjsEsmContext(): void {
1149+
this._resolvingCjsAsEsm = false;
1150+
}
1151+
1152+
async requireModuleWithEsmPreload<T = unknown>(
1153+
from: string,
1154+
moduleName?: string,
1155+
): Promise<T> {
1156+
await this.enterCjsEsmContext(from, moduleName);
1157+
try {
1158+
return this.requireModule<T>(from, moduleName);
1159+
} finally {
1160+
this.leaveCjsEsmContext();
1161+
}
11481162
}
11491163

11501164
requireInternalModule<T = unknown>(from: string, to?: string): T {

0 commit comments

Comments
 (0)