Skip to content

Commit 320a8ad

Browse files
GeoffreyBoothdanielleadams
authored andcommitted
esm: misc test refactors
- add test specific to the event loop - move parallel tests into es-module folder - refactor fixture to add braces for if blocks - use 'os' instead of 'fs' as placeholder - spelling PR-URL: #46631 Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Michaël Zasso <[email protected]>
1 parent dd97b05 commit 320a8ad

9 files changed

+377
-58
lines changed

test/es-module/test-esm-import-meta-resolve.mjs

+1-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ import { mustCall } from '../common/index.mjs';
33
import assert from 'assert';
44

55
const dirname = import.meta.url.slice(0, import.meta.url.lastIndexOf('/') + 1);
6-
const fixtures = dirname.slice(0, dirname.lastIndexOf('/', dirname.length - 2) +
7-
1) + 'fixtures/';
6+
const fixtures = dirname.slice(0, dirname.lastIndexOf('/', dirname.length - 2) + 1) + 'fixtures/';
87

98
(async () => {
109
assert.strictEqual(await import.meta.resolve('./test-esm-import-meta.mjs'),

test/es-module/test-esm-initialization.mjs

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { execPath } from 'node:process';
55
import { describe, it } from 'node:test';
66

77

8-
describe('ESM: ensure initialisation happens only once', { concurrency: true }, () => {
8+
describe('ESM: ensure initialization happens only once', { concurrency: true }, () => {
99
it(async () => {
1010
const { code, stderr, stdout } = await spawnPromisified(execPath, [
1111
'--loader',

test/es-module/test-esm-loader-chaining.mjs

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const setupArgs = [
1010
'--input-type=module',
1111
'--eval',
1212
];
13-
const commonInput = 'import fs from "node:fs"; console.log(fs)';
13+
const commonInput = 'import os from "node:os"; console.log(os)';
1414
const commonArgs = [
1515
...setupArgs,
1616
commonInput,
@@ -115,11 +115,11 @@ describe('ESM: loader chaining', { concurrency: true }, () => {
115115
);
116116

117117
assert.match(stdout, /^resolve arg count: 3$/m);
118-
assert.match(stdout, /specifier: 'node:fs'/);
118+
assert.match(stdout, /specifier: 'node:os'/);
119119
assert.match(stdout, /next: \[AsyncFunction: nextResolve\]/);
120120

121121
assert.match(stdout, /^load arg count: 3$/m);
122-
assert.match(stdout, /url: 'node:fs'/);
122+
assert.match(stdout, /url: 'node:os'/);
123123
assert.match(stdout, /next: \[AsyncFunction: nextLoad\]/);
124124
});
125125

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Flags: --experimental-loader ./test/fixtures/es-module-loaders/hooks-custom.mjs
2+
import { mustCall } from '../common/index.mjs';
3+
4+
const done = mustCall();
5+
6+
7+
// Test that the process doesn't exit because of a caught exception thrown as part of dynamic import().
8+
for (let i = 0; i < 10; i++) {
9+
await import('nonexistent/file.mjs').catch(() => {});
10+
}
11+
12+
done();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
import { spawnPromisified } from '../common/index.mjs';
2+
import * as fixtures from '../common/fixtures.mjs';
3+
import assert from 'node:assert';
4+
import { execPath } from 'node:process';
5+
import { describe, it } from 'node:test';
6+
7+
describe('Loader hooks throwing errors', { concurrency: true }, () => {
8+
it('throws on nonexistent modules', async () => {
9+
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
10+
'--no-warnings',
11+
'--experimental-loader',
12+
fixtures.fileURL('/es-module-loaders/hooks-custom.mjs'),
13+
'--input-type=module',
14+
'--eval',
15+
'import "nonexistent/file.mjs"',
16+
]);
17+
18+
assert.match(stderr, /ERR_MODULE_NOT_FOUND/);
19+
assert.strictEqual(stdout, '');
20+
assert.strictEqual(code, 1);
21+
assert.strictEqual(signal, null);
22+
});
23+
24+
it('throws on unknown extensions', async () => {
25+
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
26+
'--no-warnings',
27+
'--experimental-loader',
28+
fixtures.fileURL('/es-module-loaders/hooks-custom.mjs'),
29+
'--input-type=module',
30+
'--eval',
31+
`import '${fixtures.fileURL('/es-modules/file.unknown')}'`,
32+
]);
33+
34+
assert.match(stderr, /ERR_UNKNOWN_FILE_EXTENSION/);
35+
assert.strictEqual(stdout, '');
36+
assert.strictEqual(code, 1);
37+
assert.strictEqual(signal, null);
38+
});
39+
40+
it('throws on invalid return values', async () => {
41+
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
42+
'--no-warnings',
43+
'--experimental-loader',
44+
fixtures.fileURL('/es-module-loaders/hooks-custom.mjs'),
45+
'--input-type=module',
46+
'--eval',
47+
'import "esmHook/badReturnVal.mjs"',
48+
]);
49+
50+
assert.match(stderr, /ERR_INVALID_RETURN_VALUE/);
51+
assert.strictEqual(stdout, '');
52+
assert.strictEqual(code, 1);
53+
assert.strictEqual(signal, null);
54+
});
55+
56+
it('throws on boolean false', async () => {
57+
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
58+
'--no-warnings',
59+
'--experimental-loader',
60+
fixtures.fileURL('/es-module-loaders/hooks-custom.mjs'),
61+
'--input-type=module',
62+
'--eval',
63+
'import "esmHook/format.false"',
64+
]);
65+
66+
assert.match(stderr, /ERR_INVALID_RETURN_PROPERTY_VALUE/);
67+
assert.strictEqual(stdout, '');
68+
assert.strictEqual(code, 1);
69+
assert.strictEqual(signal, null);
70+
});
71+
it('throws on boolean true', async () => {
72+
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
73+
'--no-warnings',
74+
'--experimental-loader',
75+
fixtures.fileURL('/es-module-loaders/hooks-custom.mjs'),
76+
'--input-type=module',
77+
'--eval',
78+
'import "esmHook/format.true"',
79+
]);
80+
81+
assert.match(stderr, /ERR_INVALID_RETURN_PROPERTY_VALUE/);
82+
assert.strictEqual(stdout, '');
83+
assert.strictEqual(code, 1);
84+
assert.strictEqual(signal, null);
85+
});
86+
87+
it('throws on invalid returned object', async () => {
88+
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
89+
'--no-warnings',
90+
'--experimental-loader',
91+
fixtures.fileURL('/es-module-loaders/hooks-custom.mjs'),
92+
'--input-type=module',
93+
'--eval',
94+
'import "esmHook/badReturnFormatVal.mjs"',
95+
]);
96+
97+
assert.match(stderr, /ERR_INVALID_RETURN_PROPERTY_VALUE/);
98+
assert.strictEqual(stdout, '');
99+
assert.strictEqual(code, 1);
100+
assert.strictEqual(signal, null);
101+
});
102+
103+
it('throws on unsupported format', async () => {
104+
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
105+
'--no-warnings',
106+
'--experimental-loader',
107+
fixtures.fileURL('/es-module-loaders/hooks-custom.mjs'),
108+
'--input-type=module',
109+
'--eval',
110+
'import "esmHook/unsupportedReturnFormatVal.mjs"',
111+
]);
112+
113+
assert.match(stderr, /ERR_UNKNOWN_MODULE_FORMAT/);
114+
assert.strictEqual(stdout, '');
115+
assert.strictEqual(code, 1);
116+
assert.strictEqual(signal, null);
117+
});
118+
119+
it('throws on invalid format property type', async () => {
120+
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
121+
'--no-warnings',
122+
'--experimental-loader',
123+
fixtures.fileURL('/es-module-loaders/hooks-custom.mjs'),
124+
'--input-type=module',
125+
'--eval',
126+
'import "esmHook/badReturnSourceVal.mjs"',
127+
]);
128+
129+
assert.match(stderr, /ERR_INVALID_RETURN_PROPERTY_VALUE/);
130+
assert.strictEqual(stdout, '');
131+
assert.strictEqual(code, 1);
132+
assert.strictEqual(signal, null);
133+
});
134+
135+
it('rejects dynamic imports for all of the error cases checked above', async () => {
136+
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
137+
'--no-warnings',
138+
'--experimental-loader',
139+
fixtures.fileURL('/es-module-loaders/hooks-custom.mjs'),
140+
'--input-type=module',
141+
'--eval',
142+
`import assert from 'node:assert';
143+
await Promise.allSettled([
144+
import('nonexistent/file.mjs'),
145+
import('${fixtures.fileURL('/es-modules/file.unknown')}'),
146+
import('esmHook/badReturnVal.mjs'),
147+
import('esmHook/format.false'),
148+
import('esmHook/format.true'),
149+
import('esmHook/badReturnFormatVal.mjs'),
150+
import('esmHook/unsupportedReturnFormatVal.mjs'),
151+
import('esmHook/badReturnSourceVal.mjs'),
152+
]).then((results) => {
153+
assert.strictEqual(results.every((result) => result.status === 'rejected'), true);
154+
})`,
155+
]);
156+
157+
assert.strictEqual(stderr, '');
158+
assert.strictEqual(stdout, '');
159+
assert.strictEqual(code, 0);
160+
assert.strictEqual(signal, null);
161+
});
162+
});
163+
164+
describe('Loader hooks parsing modules', { concurrency: true }, () => {
165+
it('can parse .js files as ESM', async () => {
166+
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
167+
'--no-warnings',
168+
'--experimental-loader',
169+
fixtures.fileURL('/es-module-loaders/hooks-custom.mjs'),
170+
'--input-type=module',
171+
'--eval',
172+
`import assert from 'node:assert';
173+
await import('${fixtures.fileURL('/es-module-loaders/js-as-esm.js')}')
174+
.then((parsedModule) => {
175+
assert.strictEqual(typeof parsedModule, 'object');
176+
assert.strictEqual(parsedModule.namedExport, 'named-export');
177+
})`,
178+
]);
179+
180+
assert.strictEqual(stderr, '');
181+
assert.strictEqual(stdout, '');
182+
assert.strictEqual(code, 0);
183+
assert.strictEqual(signal, null);
184+
});
185+
186+
it('can define .ext files as ESM', async () => {
187+
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
188+
'--no-warnings',
189+
'--experimental-loader',
190+
fixtures.fileURL('/es-module-loaders/hooks-custom.mjs'),
191+
'--input-type=module',
192+
'--eval',
193+
`import assert from 'node:assert';
194+
await import('${fixtures.fileURL('/es-modules/file.ext')}')
195+
.then((parsedModule) => {
196+
assert.strictEqual(typeof parsedModule, 'object');
197+
const { default: defaultExport } = parsedModule;
198+
assert.strictEqual(typeof defaultExport, 'function');
199+
assert.strictEqual(defaultExport.name, 'iAmReal');
200+
assert.strictEqual(defaultExport(), true);
201+
})`,
202+
]);
203+
204+
assert.strictEqual(stderr, '');
205+
assert.strictEqual(stdout, '');
206+
assert.strictEqual(code, 0);
207+
assert.strictEqual(signal, null);
208+
});
209+
210+
it('can predetermine the format in the custom loader resolve hook', async () => {
211+
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
212+
'--no-warnings',
213+
'--experimental-loader',
214+
fixtures.fileURL('/es-module-loaders/hooks-custom.mjs'),
215+
'--input-type=module',
216+
'--eval',
217+
`import assert from 'node:assert';
218+
await import('esmHook/preknownFormat.pre')
219+
.then((parsedModule) => {
220+
assert.strictEqual(typeof parsedModule, 'object');
221+
assert.strictEqual(parsedModule.default, 'hello world');
222+
})`,
223+
]);
224+
225+
assert.strictEqual(stderr, '');
226+
assert.strictEqual(stdout, '');
227+
assert.strictEqual(code, 0);
228+
assert.strictEqual(signal, null);
229+
});
230+
231+
it('can provide source for a nonexistent file', async () => {
232+
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
233+
'--no-warnings',
234+
'--experimental-loader',
235+
fixtures.fileURL('/es-module-loaders/hooks-custom.mjs'),
236+
'--input-type=module',
237+
'--eval',
238+
`import assert from 'node:assert';
239+
await import('esmHook/virtual.mjs')
240+
.then((parsedModule) => {
241+
assert.strictEqual(typeof parsedModule, 'object');
242+
assert.strictEqual(typeof parsedModule.default, 'undefined');
243+
assert.strictEqual(parsedModule.message, 'WOOHOO!');
244+
})`,
245+
]);
246+
247+
assert.strictEqual(stderr, '');
248+
assert.strictEqual(stdout, '');
249+
assert.strictEqual(code, 0);
250+
assert.strictEqual(signal, null);
251+
});
252+
253+
it('ensures that loaders have a separate context from userland', async () => {
254+
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
255+
'--no-warnings',
256+
'--experimental-loader',
257+
fixtures.fileURL('/es-module-loaders/hooks-custom.mjs'),
258+
'--input-type=module',
259+
'--eval',
260+
`import assert from 'node:assert';
261+
await import('${fixtures.fileURL('/es-modules/stateful.mjs')}')
262+
.then(({ default: count }) => {
263+
assert.strictEqual(count(), 1);
264+
});`,
265+
]);
266+
267+
assert.strictEqual(stderr, '');
268+
assert.strictEqual(stdout, '');
269+
assert.strictEqual(code, 0);
270+
assert.strictEqual(signal, null);
271+
});
272+
273+
it('ensures that user loaders are not bound to the internal loader', async () => {
274+
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
275+
'--no-warnings',
276+
'--experimental-loader',
277+
fixtures.fileURL('/es-module-loaders/loader-this-value-inside-hook-functions.mjs'),
278+
'--input-type=module',
279+
'--eval',
280+
';', // Actual test is inside the loader module.
281+
]);
282+
283+
assert.strictEqual(stderr, '');
284+
assert.strictEqual(stdout, '');
285+
assert.strictEqual(code, 0);
286+
assert.strictEqual(signal, null);
287+
});
288+
});

0 commit comments

Comments
 (0)