Skip to content

Commit aa657f0

Browse files
legendecastargos
authored andcommitted
test: split indirect eval import tests
Split indirect eval import tests as they depends on the JS stack to resolve the referrer. PR-URL: #58637 Reviewed-By: Jacob Smith <jacob@frende.me> Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
1 parent 76e3c8a commit aa657f0

4 files changed

Lines changed: 90 additions & 30 deletions

File tree

‎test/es-module/test-esm-dynamic-import.js‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,15 @@ function expectFsNamespace(result) {
3535
}
3636

3737
// For direct use of import expressions inside of CJS or ES modules, including
38-
// via eval, all kinds of specifiers should work without issue.
38+
// via direct/indirect eval, all kinds of specifiers should work without issue.
3939
(functiontestScriptOrModuleImport(){
40-
// Importing another file, both direct & via eval
40+
// Importing another file, both direct & via direct eval
4141
// expectOkNamespace(import(relativePath));
4242
expectOkNamespace(eval(`import("${relativePath}")`));
4343
expectOkNamespace(eval(`import("${relativePath}")`));
4444
expectOkNamespace(eval(`import(${JSON.stringify(targetURL)})`));
4545

46-
// Importing a built-in, both direct & via eval
46+
// Importing a built-in, both direct & via direct eval
4747
expectFsNamespace(import('fs'));
4848
expectFsNamespace(eval('import("fs")'));
4949
expectFsNamespace(eval('import("fs")'));
@@ -70,6 +70,8 @@ function expectFsNamespace(result) {
7070
// be treated as a file: URL.
7171
expectOkNamespace(import(targetURL.pathname));
7272

73+
// Import with an indirect eval. In this case, the referrer is null and
74+
// defaults to the realm record.
7375
// If the referrer is a realm record, there is no way to resolve the
7476
// specifier.
7577
// TODO(legendecas): https://github.com/tc39/ecma262/pull/3195
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
'use strict';
2+
/**
3+
* This test verifies that dynamic import in an indirect eval without JS stacks.
4+
* In this case, the referrer for the dynamic import will be null and the main
5+
* context default loader in createContext() resolves to cwd.
6+
*
7+
* Caveat: this test can be unstable if the loader internals are changed and performs
8+
* microtasks with a JS stack (e.g. with CallbackScope). In this case, the
9+
* referrer will be resolved to the top JS stack frame `node:internal/process/task_queues.js`.
10+
* This is due to the implementation detail of how V8 finds the referrer for a dynamic import
11+
* call.
12+
*/
13+
14+
constcommon=require('../common');
15+
16+
// Can't process.chdir() in worker.
17+
const{ isMainThread }=require('worker_threads');
18+
19+
if(!isMainThread){
20+
common.skip('This test only works on a main thread');
21+
}
22+
23+
consttmpdir=require('../common/tmpdir');
24+
constfixtures=require('../common/fixtures');
25+
constfs=require('node:fs');
26+
const{
27+
Script,
28+
createContext,
29+
constants: {USE_MAIN_CONTEXT_DEFAULT_LOADER},
30+
}=require('node:vm');
31+
constassert=require('node:assert');
32+
33+
common.expectWarning('ExperimentalWarning',
34+
'vm.USE_MAIN_CONTEXT_DEFAULT_LOADER is an experimental feature and might change at any time');
35+
assert(
36+
!process.execArgv.includes('--experimental-vm-modules'),
37+
'This test must be run without --experimental-vm-modules');
38+
assert.strictEqual(typeofUSE_MAIN_CONTEXT_DEFAULT_LOADER,'symbol');
39+
40+
asyncfunctionmain(){
41+
tmpdir.refresh();
42+
process.chdir(tmpdir.path);
43+
44+
//
45+
{
46+
constoptions={
47+
importModuleDynamically: USE_MAIN_CONTEXT_DEFAULT_LOADER,
48+
};
49+
constctx=createContext({},options);
50+
consts=newScript('Promise.resolve("import(\'./message.mjs\')").then(eval)',{
51+
importModuleDynamically: common.mustNotCall(),
52+
});
53+
awaitassert.rejects(s.runInContext(ctx),{code: 'ERR_MODULE_NOT_FOUND'});
54+
}
55+
56+
constmoduleUrl=fixtures.fileURL('es-modules','message.mjs');
57+
fs.copyFileSync(moduleUrl,tmpdir.resolve('message.mjs'));
58+
{
59+
constoptions={
60+
importModuleDynamically: USE_MAIN_CONTEXT_DEFAULT_LOADER,
61+
};
62+
constctx=createContext({},options);
63+
constmoduleUrl=fixtures.fileURL('es-modules','message.mjs');
64+
constnamespace=awaitimport(moduleUrl.href);
65+
constscript=newScript('Promise.resolve("import(\'./message.mjs\')").then(eval)',{
66+
importModuleDynamically: common.mustNotCall(),
67+
});
68+
constresult=awaitscript.runInContext(ctx);
69+
assert.deepStrictEqual(result,namespace);
70+
}
71+
}
72+
73+
main().catch(common.mustNotCall());

‎test/es-module/test-vm-main-context-default-loader.js‎

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ const fs = require('fs');
1616
const{
1717
compileFunction,
1818
Script,
19-
createContext,
2019
constants: {USE_MAIN_CONTEXT_DEFAULT_LOADER},
2120
}=require('vm');
2221
constassert=require('assert');
@@ -112,34 +111,8 @@ async function main() {
112111
awaittestNotFoundErrors(undefinedOptions);
113112
awaittestNotFoundErrors(nonPathOptions);
114113

115-
// createContext() with null referrer also resolves to cwd.
116-
{
117-
constoptions={
118-
importModuleDynamically: USE_MAIN_CONTEXT_DEFAULT_LOADER,
119-
};
120-
constctx=createContext({},options);
121-
consts=newScript('Promise.resolve("import(\'./message.mjs\')").then(eval)',{
122-
importModuleDynamically: common.mustNotCall(),
123-
});
124-
awaitassert.rejects(s.runInContext(ctx),{code: 'ERR_MODULE_NOT_FOUND'});
125-
}
126-
127114
awaittestLoader(undefinedOptions);
128115
awaittestLoader(nonPathOptions);
129-
130-
{
131-
constoptions={
132-
importModuleDynamically: USE_MAIN_CONTEXT_DEFAULT_LOADER,
133-
};
134-
constctx=createContext({},options);
135-
constmoduleUrl=fixtures.fileURL('es-modules','message.mjs');
136-
constnamespace=awaitimport(moduleUrl.href);
137-
constscript=newScript('Promise.resolve("import(\'./message.mjs\')").then(eval)',{
138-
importModuleDynamically: common.mustNotCall(),
139-
});
140-
constresult=awaitscript.runInContext(ctx);
141-
assert.deepStrictEqual(result,namespace);
142-
}
143116
}
144117
}
145118

‎test/parallel/test-vm-module-referrer-realm.mjs‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,18 @@ import * as common from '../common/index.mjs';
33
importassertfrom'node:assert';
44
import{Script,SourceTextModule,createContext}from'node:vm';
55

6+
/**
7+
* This test verifies that dynamic import in an indirect eval without JS stacks.
8+
* In this case, the referrer for the dynamic import will be null and the
9+
* per-context importModuleDynamically callback will be invoked.
10+
*
11+
* Caveat: this test can be unstable if the loader internals are changed and performs
12+
* microtasks with a JS stack (e.g. with CallbackScope). In this case, the
13+
* referrer will be resolved to the top JS stack frame `node:internal/process/task_queues.js`.
14+
* This is due to the implementation detail of how V8 finds the referrer for a dynamic import
15+
* call.
16+
*/
17+
618
asyncfunctiontest(){
719
constfoo=newSourceTextModule('export const a = 1;');
820
awaitfoo.link(common.mustNotCall());

0 commit comments

Comments
 (0)