node/test/parallel/test-vm-module-referrer-rea...

83 lines
2.5 KiB
JavaScript

// Flags: --experimental-vm-modules
import * as common from '../common/index.mjs';
import assert from 'node:assert';
import { Script, SourceTextModule, createContext } from 'node:vm';
/**
* This test verifies that dynamic import in an indirect eval without JS stacks.
* In this case, the referrer for the dynamic import will be null and the
* per-context importModuleDynamically callback will be invoked.
*
* Caveat: this test can be unstable if the loader internals are changed and performs
* microtasks with a JS stack (e.g. with CallbackScope). In this case, the
* referrer will be resolved to the top JS stack frame `node:internal/process/task_queues.js`.
* This is due to the implementation detail of how V8 finds the referrer for a dynamic import
* call.
*/
async function test() {
const foo = new SourceTextModule('export const a = 1;');
await foo.link(common.mustNotCall());
await foo.evaluate();
const ctx = createContext({}, {
importModuleDynamically: common.mustCall((specifier, wrap) => {
assert.strictEqual(specifier, 'foo');
assert.strictEqual(wrap, ctx);
return foo;
}, 2),
});
{
const s = new Script('Promise.resolve("import(\'foo\')").then(eval)', {
importModuleDynamically: common.mustNotCall(),
});
const result = s.runInContext(ctx);
assert.strictEqual(await result, foo.namespace);
}
{
const m = new SourceTextModule('globalThis.fooResult = Promise.resolve("import(\'foo\')").then(eval)', {
context: ctx,
importModuleDynamically: common.mustNotCall(),
});
await m.link(common.mustNotCall());
await m.evaluate();
assert.strictEqual(await ctx.fooResult, foo.namespace);
delete ctx.fooResult;
}
}
async function testMissing() {
const ctx = createContext({});
{
const s = new Script('Promise.resolve("import(\'foo\')").then(eval)', {
importModuleDynamically: common.mustNotCall(),
});
const result = s.runInContext(ctx);
await assert.rejects(result, {
code: 'ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING',
});
}
{
const m = new SourceTextModule('globalThis.fooResult = Promise.resolve("import(\'foo\')").then(eval)', {
context: ctx,
importModuleDynamically: common.mustNotCall(),
});
await m.link(common.mustNotCall());
await m.evaluate();
await assert.rejects(ctx.fooResult, {
code: 'ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING',
});
delete ctx.fooResult;
}
}
await Promise.all([
test(),
testMissing(),
]).then(common.mustCall());