node/test/parallel/test-vm-module-dynamic-import-promise.js
Chengzhong Wu 1d0b4e8b91
vm: import call should return a promise in the current context
A `import` call should returns a promise created in the context where
the `import` was called, not the context of `importModuleDynamically`
callback.

PR-URL: https://github.com/nodejs/node/pull/58309
Fixes: https://github.com/nodejs/node/issues/53575
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>
2025-05-16 07:43:48 +00:00

135 lines
3.8 KiB
JavaScript

// Flags: --experimental-vm-modules
'use strict';
const common = require('../common');
const assert = require('assert');
const { createContext, Script, SourceTextModule } = require('vm');
// Verifies that a `import` call returns a promise created in the context
// where the `import` was called, not the context of `importModuleDynamically`
// callback.
async function testScript() {
const ctx = createContext();
const mod1 = new SourceTextModule('export const a = 1;', {
context: ctx,
});
// No import statements, so must not link statically.
await mod1.link(common.mustNotCall());
const script2 = new Script(`
const promise = import("mod1");
if (Object.getPrototypeOf(promise) !== Promise.prototype) {
throw new Error('Expected promise to be created in the current context');
}
globalThis.__result = promise;
`, {
importModuleDynamically: common.mustCall((specifier, referrer) => {
assert.strictEqual(specifier, 'mod1');
assert.strictEqual(referrer, script2);
return mod1;
}),
});
script2.runInContext(ctx);
// Wait for the promise to resolve.
await ctx.__result;
}
async function testScriptImportFailed() {
const ctx = createContext();
const mod1 = new SourceTextModule('export const a = 1;', {
context: ctx,
});
// No import statements, so must not link statically.
await mod1.link(common.mustNotCall());
const err = new Error('import failed');
const script2 = new Script(`
const promise = import("mod1");
if (Object.getPrototypeOf(promise) !== Promise.prototype) {
throw new Error('Expected promise to be created in the current context');
}
globalThis.__result = promise;
`, {
importModuleDynamically: common.mustCall((specifier, referrer) => {
throw err;
}),
});
script2.runInContext(ctx);
// Wait for the promise to reject.
await assert.rejects(ctx.__result, err);
}
async function testModule() {
const ctx = createContext();
const mod1 = new SourceTextModule('export const a = 1;', {
context: ctx,
});
// No import statements, so must not link statically.
await mod1.link(common.mustNotCall());
const mod2 = new SourceTextModule(`
const promise = import("mod1");
if (Object.getPrototypeOf(promise) !== Promise.prototype) {
throw new Error('Expected promise to be created in the current context');
}
await promise;
`, {
context: ctx,
importModuleDynamically: common.mustCall((specifier, referrer) => {
assert.strictEqual(specifier, 'mod1');
assert.strictEqual(referrer, mod2);
return mod1;
}),
});
// No import statements, so must not link statically.
await mod2.link(common.mustNotCall());
await mod2.evaluate();
}
async function testModuleImportFailed() {
const ctx = createContext();
const mod1 = new SourceTextModule('export const a = 1;', {
context: ctx,
});
// No import statements, so must not link statically.
await mod1.link(common.mustNotCall());
const err = new Error('import failed');
ctx.__err = err;
const mod2 = new SourceTextModule(`
const promise = import("mod1");
if (Object.getPrototypeOf(promise) !== Promise.prototype) {
throw new Error('Expected promise to be created in the current context');
}
await promise.then(() => {
throw new Error('Expected promise to be rejected');
}, (e) => {
if (e !== globalThis.__err) {
throw new Error('Expected promise to be rejected with "import failed"');
}
});
`, {
context: ctx,
importModuleDynamically: common.mustCall((specifier, referrer) => {
throw err;
}),
});
// No import statements, so must not link statically.
await mod2.link(common.mustNotCall());
await mod2.evaluate();
}
Promise.all([
testScript(),
testScriptImportFailed(),
testModule(),
testModuleImportFailed(),
]).then(common.mustCall());