diff options
author | Jacob Smith <3012099+JakobJingleheimer@users.noreply.github.com> | 2022-05-04 18:51:12 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-04 18:51:12 +0300 |
commit | d859e9e997a3de9bdd7e116b2878acc2a3cf4bd6 (patch) | |
tree | 319ced739f8800c98eb49bcfd0f523904bf4f8ac /test | |
parent | c3aa86d6784af77121e5e98e75c6dc12e5bb39ec (diff) |
esm: add chaining to loaders
PR-URL: https://github.com/nodejs/node/pull/42623
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Diffstat (limited to 'test')
32 files changed, 543 insertions, 24 deletions
diff --git a/test/es-module/test-esm-experimental-warnings.mjs b/test/es-module/test-esm-experimental-warnings.mjs index bf92b158e48..b6ef757a883 100644 --- a/test/es-module/test-esm-experimental-warnings.mjs +++ b/test/es-module/test-esm-experimental-warnings.mjs @@ -1,10 +1,33 @@ import { mustCall } from '../common/index.mjs'; import { fileURL } from '../common/fixtures.mjs'; -import { match, strictEqual } from 'assert'; +import { doesNotMatch, match, strictEqual } from 'assert'; import { spawn } from 'child_process'; import { execPath } from 'process'; -// Verify experimental warnings are printed +// Verify no warnings are printed when no experimental features are enabled or used +{ + const input = `import ${JSON.stringify(fileURL('es-module-loaders', 'module-named-exports.mjs'))}`; + const child = spawn(execPath, [ + '--input-type=module', + '--eval', + input, + ]); + + let stderr = ''; + child.stderr.setEncoding('utf8'); + child.stderr.on('data', (data) => { stderr += data; }); + child.on('close', mustCall((code, signal) => { + strictEqual(code, 0); + strictEqual(signal, null); + doesNotMatch( + stderr, + /ExperimentalWarning/, + new Error('No experimental warning(s) should be emitted when no experimental feature is enabled') + ); + })); +} + +// Verify experimental warning is printed when experimental feature is enabled for ( const [experiment, arg] of [ [/Custom ESM Loaders/, `--experimental-loader=${fileURL('es-module-loaders', 'hooks-custom.mjs')}`], diff --git a/test/es-module/test-esm-loader-chaining.mjs b/test/es-module/test-esm-loader-chaining.mjs new file mode 100644 index 00000000000..1055c44a156 --- /dev/null +++ b/test/es-module/test-esm-loader-chaining.mjs @@ -0,0 +1,352 @@ +import '../common/index.mjs'; +import fixtures from '../common/fixtures.js'; +import assert from 'node:assert'; +import { spawnSync } from 'node:child_process'; + +const setupArgs = [ + '--no-warnings', + '--input-type=module', + '--eval', +]; +const commonInput = 'import fs from "node:fs"; console.log(fs)'; +const commonArgs = [ + ...setupArgs, + commonInput, +]; + +{ // Verify unadulterated source is loaded when there are no loaders + const { status, stderr, stdout } = spawnSync( + process.execPath, + [ + ...setupArgs, + 'import fs from "node:fs"; console.log(typeof fs?.constants?.F_OK )', + ], + { encoding: 'utf8' }, + ); + + assert.strictEqual(stderr, ''); + assert.strictEqual(status, 0); + assert.match(stdout, /number/); // node:fs is an object +} + +{ // Verify loaded source is properly different when only load changes something + const { status, stderr, stdout } = spawnSync( + process.execPath, + [ + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-resolve-passthru.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-load-foo-or-42.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-load-passthru.mjs'), + ...commonArgs, + ], + { encoding: 'utf8' }, + ); + + assert.strictEqual(stderr, ''); + assert.match(stdout, /load passthru/); + assert.match(stdout, /resolve passthru/); + assert.strictEqual(status, 0); + assert.match(stdout, /foo/); +} + +{ // Verify multiple changes from hooks result in proper output + const { status, stderr, stdout } = spawnSync( + process.execPath, + [ + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-resolve-shortcircuit.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-resolve-foo.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-resolve-42.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-load-foo-or-42.mjs'), + ...commonArgs, + ], + { encoding: 'utf8' }, + ); + + assert.strictEqual(stderr, ''); + assert.match(stdout, /resolve 42/); // It did go thru resolve-42 + assert.strictEqual(status, 0); + assert.match(stdout, /foo/); // LIFO, so resolve-foo won +} + +{ // Verify modifying context within resolve chain is respected + const { status, stderr, stdout } = spawnSync( + process.execPath, + [ + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-resolve-shortcircuit.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-resolve-42.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-load-foo-or-42.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-load-receiving-modified-context.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-load-passing-modified-context.mjs'), + ...commonArgs, + ], + { encoding: 'utf8' }, + ); + + assert.strictEqual(stderr, ''); + assert.match(stdout, /bar/); + assert.strictEqual(status, 0); +} + +{ // Verify multiple changes from hooks result in proper output + const { status, stderr, stdout } = spawnSync( + process.execPath, + [ + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-resolve-shortcircuit.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-resolve-42.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-resolve-foo.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-load-foo-or-42.mjs'), + ...commonArgs, + ], + { encoding: 'utf8' }, + ); + + assert.strictEqual(stderr, ''); + assert.match(stdout, /resolve foo/); // It did go thru resolve-foo + assert.strictEqual(status, 0); + assert.match(stdout, /42/); // LIFO, so resolve-42 won +} + +{ // Verify error thrown for incomplete resolve chain, citing errant loader & hook + const { status, stderr, stdout } = spawnSync( + process.execPath, + [ + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-resolve-incomplete.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-resolve-passthru.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-load-foo-or-42.mjs'), + ...commonArgs, + ], + { encoding: 'utf8' }, + ); + + assert.match(stdout, /resolve passthru/); + assert.strictEqual(status, 1); + assert.match(stderr, /ERR_LOADER_CHAIN_INCOMPLETE/); + assert.match(stderr, /loader-resolve-incomplete\.mjs/); + assert.match(stderr, /"resolve"/); +} + +{ // Verify error NOT thrown when nested resolve hook signaled a short circuit + const { status, stderr, stdout } = spawnSync( + process.execPath, + [ + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-resolve-shortcircuit.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-resolve-next-modified.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-load-foo-or-42.mjs'), + ...commonArgs, + ], + { encoding: 'utf8' }, + ); + + assert.strictEqual(stderr, ''); + assert.strictEqual(stdout.trim(), 'foo'); + assert.strictEqual(status, 0); +} + +{ // Verify error NOT thrown when nested load hook signaled a short circuit + const { status, stderr, stdout } = spawnSync( + process.execPath, + [ + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-resolve-shortcircuit.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-resolve-42.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-load-foo-or-42.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-load-next-modified.mjs'), + ...commonArgs, + ], + { encoding: 'utf8' }, + ); + + assert.strictEqual(stderr, ''); + assert.match(stdout, /421/); + assert.strictEqual(status, 0); +} + +{ // Verify chain does break and throws appropriately + const { status, stderr, stdout } = spawnSync( + process.execPath, + [ + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-resolve-passthru.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-resolve-incomplete.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-load-foo-or-42.mjs'), + ...commonArgs, + ], + { encoding: 'utf8' }, + ); + + assert.doesNotMatch(stdout, /resolve passthru/); + assert.strictEqual(status, 1); + assert.match(stderr, /ERR_LOADER_CHAIN_INCOMPLETE/); + assert.match(stderr, /loader-resolve-incomplete\.mjs/); + assert.match(stderr, /"resolve"/); +} + +{ // Verify error thrown for incomplete load chain, citing errant loader & hook + const { status, stderr, stdout } = spawnSync( + process.execPath, + [ + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-resolve-passthru.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-load-incomplete.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-load-passthru.mjs'), + ...commonArgs, + ], + { encoding: 'utf8' }, + ); + + assert.match(stdout, /load passthru/); + assert.strictEqual(status, 1); + assert.match(stderr, /ERR_LOADER_CHAIN_INCOMPLETE/); + assert.match(stderr, /loader-load-incomplete\.mjs/); + assert.match(stderr, /"load"/); +} + +{ // Verify chain does break and throws appropriately + const { status, stderr, stdout } = spawnSync( + process.execPath, + [ + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-resolve-passthru.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-load-passthru.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-load-incomplete.mjs'), + ...commonArgs, + ], + { encoding: 'utf8' }, + ); + + assert.doesNotMatch(stdout, /load passthru/); + assert.strictEqual(status, 1); + assert.match(stderr, /ERR_LOADER_CHAIN_INCOMPLETE/); + assert.match(stderr, /loader-load-incomplete\.mjs/); + assert.match(stderr, /"load"/); +} + +{ // Verify error thrown when invalid `specifier` argument passed to `resolve…next` + const { status, stderr } = spawnSync( + process.execPath, + [ + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-resolve-passthru.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-resolve-bad-next-specifier.mjs'), + ...commonArgs, + ], + { encoding: 'utf8' }, + ); + + assert.strictEqual(status, 1); + assert.match(stderr, /ERR_INVALID_ARG_TYPE/); + assert.match(stderr, /loader-resolve-bad-next-specifier\.mjs/); + assert.match(stderr, /"resolve"/); + assert.match(stderr, /nextResolve\(specifier\)/); +} + +{ // Verify error thrown when invalid `context` argument passed to `resolve…next` + const { status, stderr } = spawnSync( + process.execPath, + [ + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-resolve-passthru.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-resolve-bad-next-context.mjs'), + ...commonArgs, + ], + { encoding: 'utf8' }, + ); + + assert.strictEqual(status, 1); + assert.match(stderr, /ERR_INVALID_ARG_TYPE/); + assert.match(stderr, /loader-resolve-bad-next-context\.mjs/); + assert.match(stderr, /"resolve"/); + assert.match(stderr, /nextResolve\(, context\)/); +} + +{ // Verify error thrown when invalid `url` argument passed to `load…next` + const { status, stderr } = spawnSync( + process.execPath, + [ + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-load-passthru.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-load-bad-next-url.mjs'), + ...commonArgs, + ], + { encoding: 'utf8' }, + ); + + assert.strictEqual(status, 1); + assert.match(stderr, /ERR_INVALID_ARG_TYPE/); + assert.match(stderr, /loader-load-bad-next-url\.mjs/); + assert.match(stderr, /"load"/); + assert.match(stderr, /nextLoad\(url\)/); +} + +{ // Verify error thrown when invalid `url` argument passed to `load…next` + const { status, stderr } = spawnSync( + process.execPath, + [ + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-load-passthru.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-load-impersonating-next-url.mjs'), + ...commonArgs, + ], + { encoding: 'utf8' }, + ); + + assert.strictEqual(status, 1); + assert.match(stderr, /ERR_INVALID_ARG_VALUE/); + assert.match(stderr, /loader-load-impersonating-next-url\.mjs/); + assert.match(stderr, /"load"/); + assert.match(stderr, /nextLoad\(url\)/); +} + +{ // Verify error thrown when invalid `context` argument passed to `load…next` + const { status, stderr } = spawnSync( + process.execPath, + [ + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-load-passthru.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-load-bad-next-context.mjs'), + ...commonArgs, + ], + { encoding: 'utf8' }, + ); + + assert.strictEqual(status, 1); + assert.match(stderr, /ERR_INVALID_ARG_TYPE/); + assert.match(stderr, /loader-load-bad-next-context\.mjs/); + assert.match(stderr, /"load"/); + assert.match(stderr, /nextLoad\(, context\)/); +} diff --git a/test/es-module/test-esm-loader-hooks.mjs b/test/es-module/test-esm-loader-hooks.mjs index 57a203342ac..d314a4d9aa0 100644 --- a/test/es-module/test-esm-loader-hooks.mjs +++ b/test/es-module/test-esm-loader-hooks.mjs @@ -35,6 +35,7 @@ const { ESMLoader } = esmLoaderModule; return { format: suggestedFormat, + shortCircuit: true, url: resolvedURL, }; } @@ -54,15 +55,21 @@ const { ESMLoader } = esmLoaderModule; // This doesn't matter (just to avoid errors) return { format: 'module', + shortCircuit: true, source: '', }; } - const customLoader = { - // Ensure ESMLoader actually calls the custom hooks - resolve: mustCall(resolve), - load: mustCall(load), - }; + const customLoader = [ + { + exports: { + // Ensure ESMLoader actually calls the custom hooks + resolve: mustCall(resolve), + load: mustCall(load), + }, + url: import.meta.url, + }, + ]; esmLoader.addCustomLoaders(customLoader); diff --git a/test/es-module/test-esm-loader-invalid-url.mjs b/test/es-module/test-esm-loader-invalid-url.mjs index 6294e57404c..1ba7c621f7e 100644 --- a/test/es-module/test-esm-loader-invalid-url.mjs +++ b/test/es-module/test-esm-loader-invalid-url.mjs @@ -4,7 +4,7 @@ import assert from 'assert'; import('../fixtures/es-modules/test-esm-ok.mjs') .then(assert.fail, (error) => { - expectsError({ code: 'ERR_INVALID_URL' })(error); - assert.strictEqual(error.input, '../fixtures/es-modules/test-esm-ok.mjs'); + expectsError({ code: 'ERR_INVALID_RETURN_PROPERTY_VALUE' })(error); + assert.match(error.message, /loader-invalid-url\.mjs/); }) .then(mustCall()); diff --git a/test/es-module/test-esm-tla-unfinished.mjs b/test/es-module/test-esm-tla-unfinished.mjs index d7658c19e98..a7b6e620d06 100644 --- a/test/es-module/test-esm-tla-unfinished.mjs +++ b/test/es-module/test-esm-tla-unfinished.mjs @@ -3,11 +3,17 @@ import assert from 'assert'; import child_process from 'child_process'; import fixtures from '../common/fixtures.js'; +const commonArgs = [ + '--no-warnings', + '--input-type=module', + '--eval', +]; + { // Unresolved TLA promise, --eval const { status, stdout, stderr } = child_process.spawnSync( process.execPath, - ['--input-type=module', '--eval', 'await new Promise(() => {})'], + [...commonArgs, 'await new Promise(() => {})'], { encoding: 'utf8' }); assert.deepStrictEqual([status, stdout, stderr], [13, '', '']); } @@ -16,7 +22,7 @@ import fixtures from '../common/fixtures.js'; // Rejected TLA promise, --eval const { status, stdout, stderr } = child_process.spawnSync( process.execPath, - ['--input-type=module', '-e', 'await Promise.reject(new Error("Xyz"))'], + [...commonArgs, 'await Promise.reject(new Error("Xyz"))'], { encoding: 'utf8' }); assert.deepStrictEqual([status, stdout], [1, '']); assert.match(stderr, /Error: Xyz/); @@ -26,8 +32,10 @@ import fixtures from '../common/fixtures.js'; // Unresolved TLA promise with explicit exit code, --eval const { status, stdout, stderr } = child_process.spawnSync( process.execPath, - ['--input-type=module', '--eval', - 'process.exitCode = 42;await new Promise(() => {})'], + [ + ...commonArgs, + 'process.exitCode = 42;await new Promise(() => {})', + ], { encoding: 'utf8' }); assert.deepStrictEqual([status, stdout, stderr], [42, '', '']); } @@ -36,8 +44,10 @@ import fixtures from '../common/fixtures.js'; // Rejected TLA promise with explicit exit code, --eval const { status, stdout, stderr } = child_process.spawnSync( process.execPath, - ['--input-type=module', '-e', - 'process.exitCode = 42;await Promise.reject(new Error("Xyz"))'], + [ + ...commonArgs, + 'process.exitCode = 42;await Promise.reject(new Error("Xyz"))', + ], { encoding: 'utf8' }); assert.deepStrictEqual([status, stdout], [1, '']); assert.match(stderr, /Error: Xyz/); @@ -47,7 +57,7 @@ import fixtures from '../common/fixtures.js'; // Unresolved TLA promise, module file const { status, stdout, stderr } = child_process.spawnSync( process.execPath, - [fixtures.path('es-modules/tla/unresolved.mjs')], + ['--no-warnings', fixtures.path('es-modules/tla/unresolved.mjs')], { encoding: 'utf8' }); assert.deepStrictEqual([status, stdout, stderr], [13, '', '']); } @@ -56,7 +66,7 @@ import fixtures from '../common/fixtures.js'; // Rejected TLA promise, module file const { status, stdout, stderr } = child_process.spawnSync( process.execPath, - [fixtures.path('es-modules/tla/rejected.mjs')], + ['--no-warnings', fixtures.path('es-modules/tla/rejected.mjs')], { encoding: 'utf8' }); assert.deepStrictEqual([status, stdout], [1, '']); assert.match(stderr, /Error: Xyz/); @@ -66,7 +76,7 @@ import fixtures from '../common/fixtures.js'; // Unresolved TLA promise, module file const { status, stdout, stderr } = child_process.spawnSync( process.execPath, - [fixtures.path('es-modules/tla/unresolved-withexitcode.mjs')], + ['--no-warnings', fixtures.path('es-modules/tla/unresolved-withexitcode.mjs')], { encoding: 'utf8' }); assert.deepStrictEqual([status, stdout, stderr], [42, '', '']); } @@ -75,7 +85,7 @@ import fixtures from '../common/fixtures.js'; // Rejected TLA promise, module file const { status, stdout, stderr } = child_process.spawnSync( process.execPath, - [fixtures.path('es-modules/tla/rejected-withexitcode.mjs')], + ['--no-warnings', fixtures.path('es-modules/tla/rejected-withexitcode.mjs')], { encoding: 'utf8' }); assert.deepStrictEqual([status, stdout], [1, '']); assert.match(stderr, /Error: Xyz/); @@ -85,7 +95,7 @@ import fixtures from '../common/fixtures.js'; // Calling process.exit() in .mjs should return status 0 const { status, stdout, stderr } = child_process.spawnSync( process.execPath, - [fixtures.path('es-modules/tla/process-exit.mjs')], + ['--no-warnings', fixtures.path('es-modules/tla/process-exit.mjs')], { encoding: 'utf8' }); assert.deepStrictEqual([status, stdout, stderr], [0, '', '']); } @@ -94,7 +104,7 @@ import fixtures from '../common/fixtures.js'; // Calling process.exit() in worker thread shouldn't influence main thread const { status, stdout, stderr } = child_process.spawnSync( process.execPath, - [fixtures.path('es-modules/tla/unresolved-with-worker-process-exit.mjs')], + ['--no-warnings', fixtures.path('es-modules/tla/unresolved-with-worker-process-exit.mjs')], { encoding: 'utf8' }); assert.deepStrictEqual([status, stdout, stderr], [13, '', '']); } diff --git a/test/fixtures/es-module-loaders/builtin-named-exports-loader.mjs b/test/fixtures/es-module-loaders/builtin-named-exports-loader.mjs index 8790811c7e7..e303ec196f6 100644 --- a/test/fixtures/es-module-loaders/builtin-named-exports-loader.mjs +++ b/test/fixtures/es-module-loaders/builtin-named-exports-loader.mjs @@ -18,6 +18,7 @@ export async function resolve(specifier, context, next) { if (def.url.startsWith('node:')) { return { + shortCircuit: true, url: `custom-${def.url}`, importAssertions: context.importAssertions, }; @@ -29,6 +30,7 @@ export function load(url, context, next) { if (url.startsWith('custom-node:')) { const urlObj = new URL(url); return { + shortCircuit: true, source: generateBuiltinModule(urlObj.pathname), format: 'module', }; diff --git a/test/fixtures/es-module-loaders/example-loader.mjs b/test/fixtures/es-module-loaders/example-loader.mjs index be480873803..f87054c8b70 100644 --- a/test/fixtures/es-module-loaders/example-loader.mjs +++ b/test/fixtures/es-module-loaders/example-loader.mjs @@ -11,6 +11,7 @@ baseURL.pathname = process.cwd() + '/'; export function resolve(specifier, { parentURL = baseURL }, defaultResolve) { if (builtinModules.includes(specifier)) { return { + shortCircuit: true, url: 'node:' + specifier }; } @@ -22,6 +23,7 @@ export function resolve(specifier, { parentURL = baseURL }, defaultResolve) { } const resolved = new URL(specifier, parentURL); return { + shortCircuit: true, url: resolved.href }; } diff --git a/test/fixtures/es-module-loaders/hooks-custom.mjs b/test/fixtures/es-module-loaders/hooks-custom.mjs index 5173b973879..4c4014db01e 100644 --- a/test/fixtures/es-module-loaders/hooks-custom.mjs +++ b/test/fixtures/es-module-loaders/hooks-custom.mjs @@ -29,25 +29,30 @@ export function load(url, context, next) { if (url.endsWith('esmHook/badReturnFormatVal.mjs')) return { format: Array(0), + shortCircuit: true, source: '', } if (url.endsWith('esmHook/unsupportedReturnFormatVal.mjs')) return { format: 'foo', // Not one of the allowable inputs: no translator named 'foo' + shortCircuit: true, source: '', } if (url.endsWith('esmHook/badReturnSourceVal.mjs')) return { format: 'module', + shortCircuit: true, source: Array(0), } if (url.endsWith('esmHook/preknownFormat.pre')) return { format: context.format, + shortCircuit: true, source: `const msg = 'hello world'; export default msg;` }; if (url.endsWith('esmHook/virtual.mjs')) return { format: 'module', + shortCircuit: true, source: `export const message = 'Woohoo!'.toUpperCase();`, }; @@ -63,6 +68,7 @@ export function resolve(specifier, context, next) { if (specifier.startsWith('esmHook')) return { format, + shortCircuit: true, url: pathToFileURL(specifier).href, importAssertions: context.importAssertions, }; diff --git a/test/fixtures/es-module-loaders/loader-invalid-format.mjs b/test/fixtures/es-module-loaders/loader-invalid-format.mjs index 0210f73b554..438d50dacba 100644 --- a/test/fixtures/es-module-loaders/loader-invalid-format.mjs +++ b/test/fixtures/es-module-loaders/loader-invalid-format.mjs @@ -1,7 +1,8 @@ export async function resolve(specifier, { parentURL, importAssertions }, defaultResolve) { if (parentURL && specifier === '../fixtures/es-modules/test-esm-ok.mjs') { return { - url: 'file:///asdf' + shortCircuit: true, + url: 'file:///asdf', }; } return defaultResolve(specifier, {parentURL, importAssertions}, defaultResolve); @@ -11,6 +12,7 @@ export async function load(url, context, next) { if (url === 'file:///asdf') { return { format: 'esm', + shortCircuit: true, source: '', } } diff --git a/test/fixtures/es-module-loaders/loader-invalid-url.mjs b/test/fixtures/es-module-loaders/loader-invalid-url.mjs index a7cefeca3da..87d1a6a564b 100644 --- a/test/fixtures/es-module-loaders/loader-invalid-url.mjs +++ b/test/fixtures/es-module-loaders/loader-invalid-url.mjs @@ -1,6 +1,7 @@ export async function resolve(specifier, { parentURL, importAssertions }, defaultResolve) { if (parentURL && specifier === '../fixtures/es-modules/test-esm-ok.mjs') { return { + shortCircuit: true, url: specifier, importAssertions, }; diff --git a/test/fixtures/es-module-loaders/loader-load-bad-next-context.mjs b/test/fixtures/es-module-loaders/loader-load-bad-next-context.mjs new file mode 100644 index 00000000000..fe38da04f9f --- /dev/null +++ b/test/fixtures/es-module-loaders/loader-load-bad-next-context.mjs @@ -0,0 +1,3 @@ +export async function load(url, context, next) { + return next(url, []); +} diff --git a/test/fixtures/es-module-loaders/loader-load-bad-next-url.mjs b/test/fixtures/es-module-loaders/loader-load-bad-next-url.mjs new file mode 100644 index 00000000000..4f53b695327 --- /dev/null +++ b/test/fixtures/es-module-loaders/loader-load-bad-next-url.mjs @@ -0,0 +1,3 @@ +export async function load(url, context, next) { + return next([], context); +} diff --git a/test/fixtures/es-module-loaders/loader-load-foo-or-42.mjs b/test/fixtures/es-module-loaders/loader-load-foo-or-42.mjs new file mode 100644 index 00000000000..8d408223e66 --- /dev/null +++ b/test/fixtures/es-module-loaders/loader-load-foo-or-42.mjs @@ -0,0 +1,11 @@ +export async function load(url) { + const val = url.includes('42') + ? '42' + : '"foo"'; + + return { + format: 'module', + shortCircuit: true, + source: `export default ${val}`, + }; +} diff --git a/test/fixtures/es-module-loaders/loader-load-impersonating-next-url.mjs b/test/fixtures/es-module-loaders/loader-load-impersonating-next-url.mjs new file mode 100644 index 00000000000..f98b091c8b9 --- /dev/null +++ b/test/fixtures/es-module-loaders/loader-load-impersonating-next-url.mjs @@ -0,0 +1,3 @@ +export async function load(url, context, next) { + return next('not/a/url', context); +} diff --git a/test/fixtures/es-module-loaders/loader-load-incomplete.mjs b/test/fixtures/es-module-loaders/loader-load-incomplete.mjs new file mode 100644 index 00000000000..d6242488e57 --- /dev/null +++ b/test/fixtures/es-module-loaders/loader-load-incomplete.mjs @@ -0,0 +1,6 @@ +export async function load() { + return { + format: 'module', + source: 'export default 42', + }; +} diff --git a/test/fixtures/es-module-loaders/loader-load-next-modified.mjs b/test/fixtures/es-module-loaders/loader-load-next-modified.mjs new file mode 100644 index 00000000000..1f2382467f7 --- /dev/null +++ b/test/fixtures/es-module-loaders/loader-load-next-modified.mjs @@ -0,0 +1,11 @@ +export async function load(url, context, next) { + const { + format, + source, + } = await next(url, context); + + return { + format, + source: source + 1, + }; +} diff --git a/test/fixtures/es-module-loaders/loader-load-passing-modified-context.mjs b/test/fixtures/es-module-loaders/loader-load-passing-modified-context.mjs new file mode 100644 index 00000000000..7676be766af --- /dev/null +++ b/test/fixtures/es-module-loaders/loader-load-passing-modified-context.mjs @@ -0,0 +1,6 @@ +export async function load(url, context, next) { + return next(url, { + ...context, + foo: 'bar', + }); +} diff --git a/test/fixtures/es-module-loaders/loader-load-passthru.mjs b/test/fixtures/es-module-loaders/loader-load-passthru.mjs new file mode 100644 index 00000000000..8cfbcb6a3a5 --- /dev/null +++ b/test/fixtures/es-module-loaders/loader-load-passthru.mjs @@ -0,0 +1,4 @@ +export async function load(url, context, next) { + console.log('load passthru'); // This log is deliberate + return next(url, context); +} diff --git a/test/fixtures/es-module-loaders/loader-load-receiving-modified-context.mjs b/test/fixtures/es-module-loaders/loader-load-receiving-modified-context.mjs new file mode 100644 index 00000000000..2d7bc350bd8 --- /dev/null +++ b/test/fixtures/es-module-loaders/loader-load-receiving-modified-context.mjs @@ -0,0 +1,4 @@ +export async function load(url, context, next) { + console.log(context.foo); // This log is deliberate + return next(url, context); +} diff --git a/test/fixtures/es-module-loaders/loader-resolve-42.mjs b/test/fixtures/es-module-loaders/loader-resolve-42.mjs new file mode 100644 index 00000000000..f4dffd70fc9 --- /dev/null +++ b/test/fixtures/es-module-loaders/loader-resolve-42.mjs @@ -0,0 +1,4 @@ +export async function resolve(specifier, context, next) { + console.log('resolve 42'); // This log is deliberate + return next('file:///42.mjs', context); +} diff --git a/test/fixtures/es-module-loaders/loader-resolve-bad-next-context.mjs b/test/fixtures/es-module-loaders/loader-resolve-bad-next-context.mjs new file mode 100644 index 00000000000..881f5875dd0 --- /dev/null +++ b/test/fixtures/es-module-loaders/loader-resolve-bad-next-context.mjs @@ -0,0 +1,3 @@ +export async function resolve(specifier, context, next) { + return next(specifier, []); +} diff --git a/test/fixtures/es-module-loaders/loader-resolve-bad-next-specifier.mjs b/test/fixtures/es-module-loaders/loader-resolve-bad-next-specifier.mjs new file mode 100644 index 00000000000..a23785d3d95 --- /dev/null +++ b/test/fixtures/es-module-loaders/loader-resolve-bad-next-specifier.mjs @@ -0,0 +1,3 @@ +export async function resolve(specifier, context, next) { + return next([], context); +} diff --git a/test/fixtures/es-module-loaders/loader-resolve-foo.mjs b/test/fixtures/es-module-loaders/loader-resolve-foo.mjs new file mode 100644 index 00000000000..595385e12a0 --- /dev/null +++ b/test/fixtures/es-module-loaders/loader-resolve-foo.mjs @@ -0,0 +1,4 @@ +export async function resolve(specifier, context, next) { + console.log('resolve foo'); // This log is deliberate + return next('file:///foo.mjs', context); +} diff --git a/test/fixtures/es-module-loaders/loader-resolve-incomplete.mjs b/test/fixtures/es-module-loaders/loader-resolve-incomplete.mjs new file mode 100644 index 00000000000..9eb1617f301 --- /dev/null +++ b/test/fixtures/es-module-loaders/loader-resolve-incomplete.mjs @@ -0,0 +1,5 @@ +export async function resolve() { + return { + url: 'file:///incomplete-resolve-chain.js', + }; +} diff --git a/test/fixtures/es-module-loaders/loader-resolve-next-modified.mjs b/test/fixtures/es-module-loaders/loader-resolve-next-modified.mjs new file mode 100644 index 00000000000..a973345a82f --- /dev/null +++ b/test/fixtures/es-module-loaders/loader-resolve-next-modified.mjs @@ -0,0 +1,11 @@ +export async function resolve(url, context, next) { + const { + format, + url: nextUrl, + } = await next(url, context); + + return { + format, + url: `${nextUrl}?foo`, + }; +} diff --git a/test/fixtures/es-module-loaders/loader-resolve-passing-modified-context.mjs b/test/fixtures/es-module-loaders/loader-resolve-passing-modified-context.mjs new file mode 100644 index 00000000000..6a92a6cd8f6 --- /dev/null +++ b/test/fixtures/es-module-loaders/loader-resolve-passing-modified-context.mjs @@ -0,0 +1,6 @@ +export async function resolve(specifier, context, next) { + return next(specifier, { + ...context, + foo: 'bar', + }); +} diff --git a/test/fixtures/es-module-loaders/loader-resolve-passthru.mjs b/test/fixtures/es-module-loaders/loader-resolve-passthru.mjs new file mode 100644 index 00000000000..1a373bab90b --- /dev/null +++ b/test/fixtures/es-module-loaders/loader-resolve-passthru.mjs @@ -0,0 +1,4 @@ +export async function resolve(specifier, context, next) { + console.log('resolve passthru'); // This log is deliberate + return next(specifier, context); +} diff --git a/test/fixtures/es-module-loaders/loader-resolve-receiving-modified-context.mjs b/test/fixtures/es-module-loaders/loader-resolve-receiving-modified-context.mjs new file mode 100644 index 00000000000..83aa83104e9 --- /dev/null +++ b/test/fixtures/es-module-loaders/loader-resolve-receiving-modified-context.mjs @@ -0,0 +1,4 @@ +export async function resolve(specifier, context, next) { + console.log(context.foo); // This log is deliberate + return next(specifier, context); +} diff --git a/test/fixtures/es-module-loaders/loader-resolve-shortcircuit.mjs b/test/fixtures/es-module-loaders/loader-resolve-shortcircuit.mjs new file mode 100644 index 00000000000..d886b3dfcbf --- /dev/null +++ b/test/fixtures/es-module-loaders/loader-resolve-shortcircuit.mjs @@ -0,0 +1,6 @@ +export async function resolve(specifier) { + return { + shortCircuit: true, + url: specifier, + } +} diff --git a/test/fixtures/es-module-loaders/mock-loader.mjs b/test/fixtures/es-module-loaders/mock-loader.mjs index 7c4592aca96..062be39603e 100644 --- a/test/fixtures/es-module-loaders/mock-loader.mjs +++ b/test/fixtures/es-module-loaders/mock-loader.mjs @@ -171,6 +171,7 @@ export function globalPreload({port}) { export async function resolve(specifier, context, defaultResolve) { if (specifier === 'node:mock') { return { + shortCircuit: true, url: specifier }; } @@ -180,10 +181,12 @@ export async function resolve(specifier, context, defaultResolve) { // Do nothing, let it get the "real" module } else if (mockedModuleExports.has(def.url)) { return { + shortCircuit: true, url: `mock-facade:${currentMockVersion}:${encodeURIComponent(def.url)}` }; }; return { + shortCircuit: true, url: def.url, }; } @@ -196,6 +199,7 @@ export async function load(url, context, defaultLoad) { * channel with preloadCode */ return { + shortCircuit: true, source: 'export default import.meta.doMock', format: 'module' }; @@ -210,6 +214,7 @@ export async function load(url, context, defaultLoad) { decodeURIComponent(encodedTargetURL) )); return { + shortCircuit: true, source: ret, format: 'module' }; diff --git a/test/fixtures/es-module-loaders/string-sources.mjs b/test/fixtures/es-module-loaders/string-sources.mjs index 384098d6d9e..1fc2b7a8d6f 100644 --- a/test/fixtures/es-module-loaders/string-sources.mjs +++ b/test/fixtures/es-module-loaders/string-sources.mjs @@ -22,7 +22,11 @@ const SOURCES = { } export function resolve(specifier, context, next) { if (specifier.startsWith('test:')) { - return { url: specifier, importAssertions: context.importAssertions }; + return { + importAssertions: context.importAssertions, + shortCircuit: true, + url: specifier, + }; } return next(specifier, context); } @@ -31,6 +35,7 @@ export function load(href, context, next) { if (href.startsWith('test:')) { return { format: 'module', + shortCircuit: true, source: SOURCES[href], }; } diff --git a/test/parallel/test-module-main-fail.js b/test/parallel/test-module-main-fail.js index c66b6f2f7a8..2b6f188dd4c 100644 --- a/test/parallel/test-module-main-fail.js +++ b/test/parallel/test-module-main-fail.js @@ -10,7 +10,10 @@ for (const entryPoint of entryPoints) { try { execFileSync(node, [entryPoint], { stdio: 'pipe' }); } catch (e) { - assert(e.toString().match(/Error: Cannot find module/)); + const error = e.toString(); + assert.match(error, /MODULE_NOT_FOUND/); + assert.match(error, /Cannot find module/); + assert(error.includes(entryPoint)); continue; } assert.fail('Executing node with inexistent entry point should ' + |