diff --git a/lib/internal/modules/esm/loader.js b/lib/internal/modules/esm/loader.js index 223fd68a79fd00..027077cbb6e781 100644 --- a/lib/internal/modules/esm/loader.js +++ b/lib/internal/modules/esm/loader.js @@ -336,7 +336,7 @@ class ESMLoader { * A list of exports from user-defined loaders (as returned by * ESMLoader.import()). */ - async addCustomLoaders( + addCustomLoaders( customLoaders = [], ) { for (let i = 0; i < customLoaders.length; i++) { diff --git a/test/common/index.js b/test/common/index.js index e14fbe59d1946b..9ba2fd9cd9edb5 100644 --- a/test/common/index.js +++ b/test/common/index.js @@ -24,7 +24,7 @@ const process = global.process; // Some tests tamper with the process global. const assert = require('assert'); -const { exec, execSync, spawnSync } = require('child_process'); +const { exec, execSync, spawn, spawnSync } = require('child_process'); const fs = require('fs'); // Do not require 'os' until needed so that test-os-checked-function can // monkey patch it. If 'os' is required here, that test will fail. @@ -842,6 +842,36 @@ function requireNoPackageJSONAbove(dir = __dirname) { } } +function spawnPromisified(...args) { + let stderr = ''; + let stdout = ''; + + const child = spawn(...args); + child.stderr.setEncoding('utf8'); + child.stderr.on('data', (data) => { stderr += data; }); + child.stdout.setEncoding('utf8'); + child.stdout.on('data', (data) => { stdout += data; }); + + return new Promise((resolve, reject) => { + child.on('close', (code, signal) => { + resolve({ + code, + signal, + stderr, + stdout, + }); + }); + child.on('error', (code, signal) => { + reject({ + code, + signal, + stderr, + stdout, + }); + }); + }); +} + const common = { allowGlobals, buildType, @@ -891,6 +921,7 @@ const common = { skipIfEslintMissing, skipIfInspectorDisabled, skipIfWorker, + spawnPromisified, get enoughTestMem() { return require('os').totalmem() > 0x70000000; /* 1.75 Gb */ diff --git a/test/common/index.mjs b/test/common/index.mjs index a3a34ae7f04435..2b30f499343cc4 100644 --- a/test/common/index.mjs +++ b/test/common/index.mjs @@ -23,6 +23,7 @@ const { hasCrypto, hasIPv6, childShouldThrowAndAbort, + checkoutEOL, createZeroFilledFile, platformTimeout, allowGlobals, @@ -47,7 +48,8 @@ const { getArrayBufferViews, getBufferSources, getTTYfd, - runWithInvalidFD + runWithInvalidFD, + spawnPromisified, } = common; export { @@ -70,6 +72,7 @@ export { hasCrypto, hasIPv6, childShouldThrowAndAbort, + checkoutEOL, createZeroFilledFile, platformTimeout, allowGlobals, @@ -95,5 +98,6 @@ export { getBufferSources, getTTYfd, runWithInvalidFD, - createRequire + createRequire, + spawnPromisified, }; diff --git a/test/es-module/test-cjs-esm-warn.js b/test/es-module/test-cjs-esm-warn.js index d7eeb65b152a4a..c1d60a209502bb 100644 --- a/test/es-module/test-cjs-esm-warn.js +++ b/test/es-module/test-cjs-esm-warn.js @@ -1,10 +1,12 @@ 'use strict'; -const common = require('../common'); -const fixtures = require('../common/fixtures'); -const { spawn } = require('child_process'); -const assert = require('assert'); -const path = require('path'); +const { spawnPromisified } = require('../common'); +const fixtures = require('../common/fixtures.js'); +const assert = require('node:assert'); +const path = require('node:path'); +const { execPath } = require('node:process'); +const { describe, it } = require('node:test'); + const requiringCjsAsEsm = path.resolve(fixtures.path('/es-modules/cjs-esm.js')); const requiringEsm = path.resolve(fixtures.path('/es-modules/cjs-esm-esm.js')); @@ -12,53 +14,55 @@ const pjson = path.resolve( fixtures.path('/es-modules/package-type-module/package.json') ); -{ - const required = path.resolve( - fixtures.path('/es-modules/package-type-module/cjs.js') - ); - const basename = 'cjs.js'; - const child = spawn(process.execPath, [requiringCjsAsEsm]); - let stderr = ''; - child.stderr.setEncoding('utf8'); - child.stderr.on('data', (data) => { - stderr += data; - }); - child.on('close', common.mustCall((code, signal) => { + +describe('CJS ↔︎ ESM interop warnings', { concurrency: true }, () => { + + it(async () => { + const required = path.resolve( + fixtures.path('/es-modules/package-type-module/cjs.js') + ); + const basename = 'cjs.js'; + const { code, signal, stderr } = await spawnPromisified(execPath, [requiringCjsAsEsm]); + + assert.ok( + stderr.replaceAll('\r', '').includes( + `Error [ERR_REQUIRE_ESM]: require() of ES Module ${required} from ${requiringCjsAsEsm} not supported.\n` + ) + ); + assert.ok( + stderr.replaceAll('\r', '').includes( + `Instead rename ${basename} to end in .cjs, change the requiring ` + + 'code to use dynamic import() which is available in all CommonJS ' + + `modules, or change "type": "module" to "type": "commonjs" in ${pjson} to ` + + 'treat all .js files as CommonJS (using .mjs for all ES modules ' + + 'instead).\n' + ) + ); + assert.strictEqual(code, 1); assert.strictEqual(signal, null); + }); - assert.ok(stderr.replaceAll('\r', '').includes( - `Error [ERR_REQUIRE_ESM]: require() of ES Module ${required} from ${ - requiringCjsAsEsm} not supported.\n`)); - assert.ok(stderr.replaceAll('\r', '').includes( - `Instead rename ${basename} to end in .cjs, change the requiring ` + - 'code to use dynamic import() which is available in all CommonJS ' + - `modules, or change "type": "module" to "type": "commonjs" in ${pjson} to ` + - 'treat all .js files as CommonJS (using .mjs for all ES modules ' + - 'instead).\n')); - })); -} + it(async () => { + const required = path.resolve( + fixtures.path('/es-modules/package-type-module/esm.js') + ); + const basename = 'esm.js'; + const { code, signal, stderr } = await spawnPromisified(execPath, [requiringEsm]); + + assert.ok( + stderr.replace(/\r/g, '').includes( + `Error [ERR_REQUIRE_ESM]: require() of ES Module ${required} from ${requiringEsm} not supported.\n` + ) + ); + assert.ok( + stderr.replace(/\r/g, '').includes( + `Instead change the require of ${basename} in ${requiringEsm} to` + + ' a dynamic import() which is available in all CommonJS modules.\n' + ) + ); -{ - const required = path.resolve( - fixtures.path('/es-modules/package-type-module/esm.js') - ); - const basename = 'esm.js'; - const child = spawn(process.execPath, [requiringEsm]); - let stderr = ''; - child.stderr.setEncoding('utf8'); - child.stderr.on('data', (data) => { - stderr += data; - }); - child.on('close', common.mustCall((code, signal) => { assert.strictEqual(code, 1); assert.strictEqual(signal, null); - - assert.ok(stderr.replace(/\r/g, '').includes( - `Error [ERR_REQUIRE_ESM]: require() of ES Module ${required} from ${ - requiringEsm} not supported.\n`)); - assert.ok(stderr.replace(/\r/g, '').includes( - `Instead change the require of ${basename} in ${requiringEsm} to` + - ' a dynamic import() which is available in all CommonJS modules.\n')); - })); -} + }); +}); diff --git a/test/es-module/test-esm-cjs-builtins.js b/test/es-module/test-esm-cjs-builtins.js index 63aae732904137..c49abfd8c93222 100644 --- a/test/es-module/test-esm-cjs-builtins.js +++ b/test/es-module/test-esm-cjs-builtins.js @@ -1,21 +1,20 @@ 'use strict'; -const common = require('../common'); -const fixtures = require('../common/fixtures'); -const { spawn } = require('child_process'); -const assert = require('assert'); +const { spawnPromisified } = require('../common'); +const fixtures = require('../common/fixtures.js'); +const assert = require('node:assert'); +const { execPath } = require('node:process'); +const { describe, it } = require('node:test'); + const entry = fixtures.path('/es-modules/builtin-imports-case.mjs'); -const child = spawn(process.execPath, [entry]); -child.stderr.setEncoding('utf8'); -let stdout = ''; -child.stdout.setEncoding('utf8'); -child.stdout.on('data', (data) => { - stdout += data; +describe('ESM: importing builtins & CJS', () => { + it('should work', async () => { + const { code, signal, stdout } = await spawnPromisified(execPath, [entry]); + + assert.strictEqual(code, 0); + assert.strictEqual(signal, null); + assert.strictEqual(stdout, 'ok\n'); + }); }); -child.on('close', common.mustCall((code, signal) => { - assert.strictEqual(code, 0); - assert.strictEqual(signal, null); - assert.strictEqual(stdout, 'ok\n'); -})); diff --git a/test/es-module/test-esm-cjs-exports.js b/test/es-module/test-esm-cjs-exports.js index 7db2c6fdb5971b..4a5a9ffceecc2a 100644 --- a/test/es-module/test-esm-cjs-exports.js +++ b/test/es-module/test-esm-cjs-exports.js @@ -1,35 +1,29 @@ 'use strict'; -const common = require('../common'); -const fixtures = require('../common/fixtures'); -const { spawn } = require('child_process'); -const assert = require('assert'); +const { spawnPromisified } = require('../common'); +const fixtures = require('../common/fixtures.js'); +const assert = require('node:assert'); +const { execPath } = require('node:process'); +const { describe, it } = require('node:test'); -const entry = fixtures.path('/es-modules/cjs-exports.mjs'); -let child = spawn(process.execPath, [entry]); -child.stderr.setEncoding('utf8'); -let stdout = ''; -child.stdout.setEncoding('utf8'); -child.stdout.on('data', (data) => { - stdout += data; -}); -child.on('close', common.mustCall((code, signal) => { - assert.strictEqual(code, 0); - assert.strictEqual(signal, null); - assert.strictEqual(stdout, 'ok\n'); -})); +describe('ESM: importing CJS', { concurrency: true }, () => { + it('should support valid CJS exports', async () => { + const validEntry = fixtures.path('/es-modules/cjs-exports.mjs'); + const { code, signal, stdout } = await spawnPromisified(execPath, [validEntry]); + + assert.strictEqual(code, 0); + assert.strictEqual(signal, null); + assert.strictEqual(stdout, 'ok\n'); + }); + + it('should eror on invalid CJS exports', async () => { + const invalidEntry = fixtures.path('/es-modules/cjs-exports-invalid.mjs'); + const { code, signal, stderr } = await spawnPromisified(execPath, [invalidEntry]); -const entryInvalid = fixtures.path('/es-modules/cjs-exports-invalid.mjs'); -child = spawn(process.execPath, [entryInvalid]); -let stderr = ''; -child.stderr.setEncoding('utf8'); -child.stderr.on('data', (data) => { - stderr += data; + assert.strictEqual(code, 1); + assert.strictEqual(signal, null); + assert.ok(stderr.includes('Warning: To load an ES module')); + assert.ok(stderr.includes('Unexpected token \'export\'')); + }); }); -child.on('close', common.mustCall((code, signal) => { - assert.strictEqual(code, 1); - assert.strictEqual(signal, null); - assert.ok(stderr.includes('Warning: To load an ES module')); - assert.ok(stderr.includes('Unexpected token \'export\'')); -})); diff --git a/test/es-module/test-esm-cjs-load-error-note.mjs b/test/es-module/test-esm-cjs-load-error-note.mjs index 0298432441391c..4df9e903eb627a 100644 --- a/test/es-module/test-esm-cjs-load-error-note.mjs +++ b/test/es-module/test-esm-cjs-load-error-note.mjs @@ -1,163 +1,96 @@ -import { mustCall } from '../common/index.mjs'; -import assert from 'assert'; -import fixtures from '../common/fixtures.js'; -import { spawn } from 'child_process'; +import { spawnPromisified } from '../common/index.mjs'; +import * as fixtures from '../common/fixtures.mjs'; +import assert from 'node:assert'; +import { execPath } from 'node:process'; +import { describe, it } from 'node:test'; -const Export1 = fixtures.path('/es-modules/es-note-unexpected-export-1.cjs'); -const Export2 = fixtures.path('/es-modules/es-note-unexpected-export-2.cjs'); -const Import1 = fixtures.path('/es-modules/es-note-unexpected-import-1.cjs'); -const Import2 = fixtures.path('/es-modules/es-note-promiserej-import-2.cjs'); -const Import3 = fixtures.path('/es-modules/es-note-unexpected-import-3.cjs'); -const Import4 = fixtures.path('/es-modules/es-note-unexpected-import-4.cjs'); -const Import5 = fixtures.path('/es-modules/es-note-unexpected-import-5.cjs'); -const Error1 = fixtures.path('/es-modules/es-note-error-1.mjs'); -const Error2 = fixtures.path('/es-modules/es-note-error-2.mjs'); -const Error3 = fixtures.path('/es-modules/es-note-error-3.mjs'); -const Error4 = fixtures.path('/es-modules/es-note-error-4.mjs'); // Expect note to be included in the error output const expectedNote = 'To load an ES module, ' + 'set "type": "module" in the package.json ' + 'or use the .mjs extension.'; -const expectedCode = 1; - -const pExport1 = spawn(process.execPath, [Export1]); -let pExport1Stderr = ''; -pExport1.stderr.setEncoding('utf8'); -pExport1.stderr.on('data', (data) => { - pExport1Stderr += data; -}); -pExport1.on('close', mustCall((code) => { - assert.strictEqual(code, expectedCode); - assert.ok(pExport1Stderr.includes(expectedNote), - `${expectedNote} not found in ${pExport1Stderr}`); -})); - - -const pExport2 = spawn(process.execPath, [Export2]); -let pExport2Stderr = ''; -pExport2.stderr.setEncoding('utf8'); -pExport2.stderr.on('data', (data) => { - pExport2Stderr += data; -}); -pExport2.on('close', mustCall((code) => { - assert.strictEqual(code, expectedCode); - assert.ok(pExport2Stderr.includes(expectedNote), - `${expectedNote} not found in ${pExport2Stderr}`); -})); - -const pImport1 = spawn(process.execPath, [Import1]); -let pImport1Stderr = ''; -pImport1.stderr.setEncoding('utf8'); -pImport1.stderr.on('data', (data) => { - pImport1Stderr += data; -}); -pImport1.on('close', mustCall((code) => { - assert.strictEqual(code, expectedCode); - assert.ok(pImport1Stderr.includes(expectedNote), - `${expectedNote} not found in ${pExport1Stderr}`); -})); - -// Note this test shouldn't include the note -const pImport2 = spawn(process.execPath, [Import2]); -let pImport2Stderr = ''; -pImport2.stderr.setEncoding('utf8'); -pImport2.stderr.on('data', (data) => { - pImport2Stderr += data; -}); -pImport2.on('close', mustCall((code) => { - assert.strictEqual(code, expectedCode); - assert.ok(!pImport2Stderr.includes(expectedNote), - `${expectedNote} must not be included in ${pImport2Stderr}`); -})); - -const pImport3 = spawn(process.execPath, [Import3]); -let pImport3Stderr = ''; -pImport3.stderr.setEncoding('utf8'); -pImport3.stderr.on('data', (data) => { - pImport3Stderr += data; -}); -pImport3.on('close', mustCall((code) => { - assert.strictEqual(code, expectedCode); - assert.ok(pImport3Stderr.includes(expectedNote), - `${expectedNote} not found in ${pImport3Stderr}`); -})); - - -const pImport4 = spawn(process.execPath, [Import4]); -let pImport4Stderr = ''; -pImport4.stderr.setEncoding('utf8'); -pImport4.stderr.on('data', (data) => { - pImport4Stderr += data; -}); -pImport4.on('close', mustCall((code) => { - assert.strictEqual(code, expectedCode); - assert.ok(pImport4Stderr.includes(expectedNote), - `${expectedNote} not found in ${pImport4Stderr}`); -})); - -// Must exit non-zero and show note -const pImport5 = spawn(process.execPath, [Import5]); -let pImport5Stderr = ''; -pImport5.stderr.setEncoding('utf8'); -pImport5.stderr.on('data', (data) => { - pImport5Stderr += data; -}); -pImport5.on('close', mustCall((code) => { - assert.strictEqual(code, expectedCode); - assert.ok(!pImport5Stderr.includes(expectedNote), - `${expectedNote} must not be included in ${pImport5Stderr}`); -})); - -const pError1 = spawn(process.execPath, [Error1]); -let pError1Stderr = ''; -pError1.stderr.setEncoding('utf8'); -pError1.stderr.on('data', (data) => { - pError1Stderr += data; -}); -pError1.on('close', mustCall((code) => { - assert.strictEqual(code, expectedCode); - assert.ok(pError1Stderr.includes('Error: some error')); - assert.ok(!pError1Stderr.includes(expectedNote), - `${expectedNote} must not be included in ${pError1Stderr}`); -})); - -const pError2 = spawn(process.execPath, [Error2]); -let pError2Stderr = ''; -pError2.stderr.setEncoding('utf8'); -pError2.stderr.on('data', (data) => { - pError2Stderr += data; -}); -pError2.on('close', mustCall((code) => { - assert.strictEqual(code, expectedCode); - assert.ok(pError2Stderr.includes('string')); - assert.ok(!pError2Stderr.includes(expectedNote), - `${expectedNote} must not be included in ${pError2Stderr}`); -})); - -const pError3 = spawn(process.execPath, [Error3]); -let pError3Stderr = ''; -pError3.stderr.setEncoding('utf8'); -pError3.stderr.on('data', (data) => { - pError3Stderr += data; -}); -pError3.on('close', mustCall((code) => { - assert.strictEqual(code, expectedCode); - assert.ok(pError3Stderr.includes('null')); - assert.ok(!pError3Stderr.includes(expectedNote), - `${expectedNote} must not be included in ${pError3Stderr}`); -})); - -const pError4 = spawn(process.execPath, [Error4]); -let pError4Stderr = ''; -pError4.stderr.setEncoding('utf8'); -pError4.stderr.on('data', (data) => { - pError4Stderr += data; +const mustIncludeMessage = { + getMessage: () => (stderr) => `${expectedNote} not found in ${stderr}`, + includeNote: true, +}; +const mustNotIncludeMessage = { + getMessage: () => (stderr) => `${expectedNote} must not be included in ${stderr}`, + includeNote: false, +}; + +describe('ESM: Errors for unexpected exports', { concurrency: true }, () => { + for ( + const { errorNeedle, filePath, getMessage, includeNote } + of [ + { + // name: '', + filePath: fixtures.path('/es-modules/es-note-unexpected-export-1.cjs'), + ...mustIncludeMessage, + }, + { + // name: '', + filePath: fixtures.path('/es-modules/es-note-unexpected-import-1.cjs'), + ...mustIncludeMessage, + }, + { + // name: '', + filePath: fixtures.path('/es-modules/es-note-promiserej-import-2.cjs'), + ...mustNotIncludeMessage, + }, + { + // name: '', + filePath: fixtures.path('/es-modules/es-note-unexpected-import-3.cjs'), + ...mustIncludeMessage, + }, + { + // name: '', + filePath: fixtures.path('/es-modules/es-note-unexpected-import-4.cjs'), + ...mustIncludeMessage, + }, + { + // name: '', + filePath: fixtures.path('/es-modules/es-note-unexpected-import-5.cjs'), + ...mustNotIncludeMessage, + }, + { + // name: '', + filePath: fixtures.path('/es-modules/es-note-error-1.mjs'), + ...mustNotIncludeMessage, + errorNeedle: /Error: some error/, + }, + { + // name: '', + filePath: fixtures.path('/es-modules/es-note-error-2.mjs'), + ...mustNotIncludeMessage, + errorNeedle: /string/, + }, + { + // name: '', + filePath: fixtures.path('/es-modules/es-note-error-3.mjs'), + ...mustNotIncludeMessage, + errorNeedle: /null/, + }, + { + // name: '', + filePath: fixtures.path('/es-modules/es-note-error-4.mjs'), + ...mustNotIncludeMessage, + errorNeedle: /undefined/, + }, + ] + ) { + it(`should ${includeNote ? '' : 'NOT'} include note`, async () => { + const { code, stderr } = await spawnPromisified(execPath, [filePath]); + + assert.strictEqual(code, 1); + + if (errorNeedle != null) assert.match(stderr, errorNeedle); + + const shouldIncludeNote = stderr.includes(expectedNote); + assert.ok( + includeNote ? shouldIncludeNote : !shouldIncludeNote, + `${filePath} ${getMessage(stderr)}`, + ); + }); + } }); -pError4.on('close', mustCall((code) => { - assert.strictEqual(code, expectedCode); - assert.ok(pError4Stderr.includes('undefined')); - assert.ok(!pError4Stderr.includes(expectedNote), - `${expectedNote} must not be included in ${pError4Stderr}`); -})); diff --git a/test/es-module/test-esm-cjs-main.js b/test/es-module/test-esm-cjs-main.js index 92f4124ccaab8a..bb209648356d10 100644 --- a/test/es-module/test-esm-cjs-main.js +++ b/test/es-module/test-esm-cjs-main.js @@ -1,21 +1,20 @@ 'use strict'; -const common = require('../common'); -const fixtures = require('../common/fixtures'); -const { spawn } = require('child_process'); -const assert = require('assert'); +const { spawnPromisified } = require('../common'); +const fixtures = require('../common/fixtures.js'); +const assert = require('node:assert'); +const { execPath } = require('node:process'); +const { describe, it } = require('node:test'); -const entry = fixtures.path('/es-modules/cjs.js'); -const child = spawn(process.execPath, [entry]); -child.stderr.setEncoding('utf8'); -let stdout = ''; -child.stdout.setEncoding('utf8'); -child.stdout.on('data', (data) => { - stdout += data; +describe('ESM: importing CJS', () => { + it('should work', async () => { + const { code, signal, stdout } = await spawnPromisified(execPath, [ + fixtures.path('/es-modules/cjs.js'), + ]); + + assert.strictEqual(code, 0); + assert.strictEqual(signal, null); + assert.strictEqual(stdout, 'executed\n'); + }); }); -child.on('close', common.mustCall((code, signal) => { - assert.strictEqual(code, 0); - assert.strictEqual(signal, null); - assert.strictEqual(stdout, 'executed\n'); -})); diff --git a/test/es-module/test-esm-encoded-path-native.js b/test/es-module/test-esm-encoded-path-native.js index b8f5719b6089ee..7574e55278bd1f 100644 --- a/test/es-module/test-esm-encoded-path-native.js +++ b/test/es-module/test-esm-encoded-path-native.js @@ -1,11 +1,18 @@ 'use strict'; -require('../common'); -const fixtures = require('../common/fixtures'); -const assert = require('assert'); -const { spawn } = require('child_process'); - -const native = fixtures.path('es-module-url/native.mjs'); -const child = spawn(process.execPath, [native]); -child.on('exit', (code) => { - assert.strictEqual(code, 1); + +const { spawnPromisified } = require('../common'); +const fixtures = require('../common/fixtures.js'); +const assert = require('node:assert'); +const { execPath } = require('node:process'); +const { describe, it } = require('node:test'); + + +describe('ESM: importing an encoded path', () => { + it('should throw', async () => { + const { code } = await spawnPromisified(execPath, [ + fixtures.path('es-module-url/native.mjs'), + ]); + + assert.strictEqual(code, 1); + }); }); diff --git a/test/es-module/test-esm-experimental-warnings.mjs b/test/es-module/test-esm-experimental-warnings.mjs index b6ef757a88302e..fc167c63584b87 100644 --- a/test/es-module/test-esm-experimental-warnings.mjs +++ b/test/es-module/test-esm-experimental-warnings.mjs @@ -1,55 +1,48 @@ -import { mustCall } from '../common/index.mjs'; +import { spawnPromisified } from '../common/index.mjs'; import { fileURL } from '../common/fixtures.mjs'; -import { doesNotMatch, match, strictEqual } from 'assert'; -import { spawn } from 'child_process'; -import { execPath } from 'process'; +import { doesNotMatch, match, strictEqual } from 'node:assert'; +import { execPath } from 'node:process'; +import { describe, it } from 'node:test'; -// 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); +describe('ESM: warn for obsolete hooks provided', { concurrency: true }, () => { + it('should not print warnings when no experimental features are enabled or used', async () => { + const { code, signal, stderr } = await spawnPromisified(execPath, [ + '--input-type=module', + '--eval', + `import ${JSON.stringify(fileURL('es-module-loaders', 'module-named-exports.mjs'))}`, + ]); + 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')}`], - [/Network Imports/, '--experimental-network-imports'], - [/specifier resolution/, '--experimental-specifier-resolution=node'], - ] -) { - const input = `import ${JSON.stringify(fileURL('es-module-loaders', 'module-named-exports.mjs'))}`; - const child = spawn(execPath, [ - arg, - '--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); - match(stderr, /ExperimentalWarning/); - match(stderr, experiment); - })); -} + }); + + describe('experimental warnings for enabled experimental feature', () => { + for ( + const [experiment, arg] of [ + [/Custom ESM Loaders/, `--experimental-loader=${fileURL('es-module-loaders', 'hooks-custom.mjs')}`], + [/Network Imports/, '--experimental-network-imports'], + [/specifier resolution/, '--experimental-specifier-resolution=node'], + ] + ) { + it(`should print for ${experiment.toString().replaceAll('/', '')}`, async () => { + const { code, signal, stderr } = await spawnPromisified(execPath, [ + arg, + '--input-type=module', + '--eval', + `import ${JSON.stringify(fileURL('es-module-loaders', 'module-named-exports.mjs'))}`, + ]); + + match(stderr, /ExperimentalWarning/); + match(stderr, experiment); + strictEqual(code, 0); + strictEqual(signal, null); + }); + } + }); +}); diff --git a/test/es-module/test-esm-export-not-found.mjs b/test/es-module/test-esm-export-not-found.mjs index cdfe6df0fcde31..48ccd0f910227f 100644 --- a/test/es-module/test-esm-export-not-found.mjs +++ b/test/es-module/test-esm-export-not-found.mjs @@ -1,39 +1,48 @@ -import { mustCall } from '../common/index.mjs'; -import { path } from '../common/fixtures.mjs'; -import { match, notStrictEqual } from 'assert'; -import { spawn } from 'child_process'; -import { execPath } from 'process'; +import { spawnPromisified } from '../common/index.mjs'; +import * as fixtures from '../common/fixtures.mjs'; +import assert from 'node:assert'; +import { execPath } from 'node:process'; +import { describe, it } from 'node:test'; -const importStatement = - 'import { foo, notfound } from \'./module-named-exports.mjs\';'; + +const importStatement = 'import { foo, notfound } from \'./module-named-exports.mjs\';'; const importStatementMultiline = `import { foo, notfound } from './module-named-exports.mjs'; `; -[importStatement, importStatementMultiline].forEach((input) => { - const child = spawn(execPath, [ - '--input-type=module', - '--eval', - input, - ], { - cwd: path('es-module-loaders'), - }); +describe('ESM: nonexistent exports', { concurrency: true }, () => { + for ( + const { name, input } + of [ + { + input: importStatement, + name: 'single-line import', + }, + { + input: importStatementMultiline, + name: 'multi-line import', + }, + ] + ) { + it(`should throw for nonexistent exports via ${name}`, async () => { + const { code, stderr } = await spawnPromisified(execPath, [ + '--input-type=module', + '--eval', + input, + ], { + cwd: fixtures.path('es-module-loaders'), + }); - let stderr = ''; - child.stderr.setEncoding('utf8'); - child.stderr.on('data', (data) => { - stderr += data; - }); - child.on('close', mustCall((code, _signal) => { - notStrictEqual(code, 0); + assert.notStrictEqual(code, 0); - // SyntaxError: The requested module './module-named-exports.mjs' - // does not provide an export named 'notfound' - match(stderr, /SyntaxError:/); - // The quotes ensure that the path starts with ./ and not ../ - match(stderr, /'\.\/module-named-exports\.mjs'/); - match(stderr, /notfound/); - })); + // SyntaxError: The requested module './module-named-exports.mjs' + // does not provide an export named 'notfound' + assert.match(stderr, /SyntaxError:/); + // The quotes ensure that the path starts with ./ and not ../ + assert.match(stderr, /'\.\/module-named-exports\.mjs'/); + assert.match(stderr, /notfound/); + }); + } }); diff --git a/test/es-module/test-esm-import-json-named-export.mjs b/test/es-module/test-esm-import-json-named-export.mjs index 3c0f3af662c7cc..c8a4ad8dce3e5e 100644 --- a/test/es-module/test-esm-import-json-named-export.mjs +++ b/test/es-module/test-esm-import-json-named-export.mjs @@ -1,24 +1,22 @@ -import { mustCall } from '../common/index.mjs'; -import { path } from '../common/fixtures.mjs'; -import { match, notStrictEqual } from 'assert'; -import { spawn } from 'child_process'; -import { execPath } from 'process'; +import { spawnPromisified } from '../common/index.mjs'; +import * as fixtures from '../common/fixtures.mjs'; +import assert from 'node:assert'; +import { execPath } from 'node:process'; +import { describe, it } from 'node:test'; -const child = spawn(execPath, [ - path('es-modules', 'import-json-named-export.mjs'), -]); -let stderr = ''; -child.stderr.setEncoding('utf8'); -child.stderr.on('data', (data) => { - stderr += data; -}); -child.on('close', mustCall((code, _signal) => { - notStrictEqual(code, 0); +describe('ESM: named JSON exports', { concurrency: true }, () => { + it('should throw, citing named import', async () => { + const { code, stderr } = await spawnPromisified(execPath, [ + fixtures.path('es-modules', 'import-json-named-export.mjs'), + ]); + + // SyntaxError: The requested module '../experimental.json' + // does not provide an export named 'ofLife' + assert.match(stderr, /SyntaxError:/); + assert.match(stderr, /'\.\.\/experimental\.json'/); + assert.match(stderr, /'ofLife'/); - // SyntaxError: The requested module '../experimental.json' - // does not provide an export named 'ofLife' - match(stderr, /SyntaxError:/); - match(stderr, /'\.\.\/experimental\.json'/); - match(stderr, /'ofLife'/); -})); + assert.notStrictEqual(code, 0); + }); +}); diff --git a/test/es-module/test-esm-initialization.mjs b/test/es-module/test-esm-initialization.mjs index ab756c7a3619e1..2bfd16135a0189 100644 --- a/test/es-module/test-esm-initialization.mjs +++ b/test/es-module/test-esm-initialization.mjs @@ -1,30 +1,29 @@ -import '../common/index.mjs'; +import { spawnPromisified } from '../common/index.mjs'; import * as fixtures from '../common/fixtures.mjs'; import assert from 'node:assert'; -import { spawnSync } from 'node:child_process'; +import { execPath } from 'node:process'; +import { describe, it } from 'node:test'; -{ // Verify unadulterated source is loaded when there are no loaders - const { status, stderr, stdout } = spawnSync( - process.execPath, - [ +describe('ESM: ensure initialisation happens only once', { concurrency: true }, () => { + it(async () => { + const { code, stderr, stdout } = await spawnPromisified(execPath, [ '--loader', fixtures.fileURL('es-module-loaders', 'loader-resolve-passthru.mjs'), '--no-warnings', fixtures.path('es-modules', 'runmain.mjs'), - ], - { encoding: 'utf8' }, - ); + ]); - // Length minus 1 because the first match is the needle. - const resolveHookRunCount = (stdout.match(/resolve passthru/g)?.length ?? 0) - 1; + // Length minus 1 because the first match is the needle. + const resolveHookRunCount = (stdout.match(/resolve passthru/g)?.length ?? 0) - 1; - assert.strictEqual(stderr, ''); - /** - * resolveHookRunCount = 2: - * 1. fixtures/…/runmain.mjs - * 2. node:module (imported by fixtures/…/runmain.mjs) - */ - assert.strictEqual(resolveHookRunCount, 2); - assert.strictEqual(status, 0); -} + assert.strictEqual(stderr, ''); + /** + * resolveHookRunCount = 2: + * 1. fixtures/…/runmain.mjs + * 2. node:module (imported by fixtures/…/runmain.mjs) + */ + assert.strictEqual(resolveHookRunCount, 2); + assert.strictEqual(code, 0); + }); +}); diff --git a/test/es-module/test-esm-invalid-extension.js b/test/es-module/test-esm-invalid-extension.js deleted file mode 100644 index cca7704f7994f0..00000000000000 --- a/test/es-module/test-esm-invalid-extension.js +++ /dev/null @@ -1,13 +0,0 @@ -'use strict'; -require('../common'); -const fixtures = require('../common/fixtures'); -const assert = require('assert'); -const { spawnSync } = require('child_process'); -const fixture = fixtures.path('/es-modules/import-invalid-ext.mjs'); -const child = spawnSync(process.execPath, [fixture]); -const errMsg = 'TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension'; - -assert.strictEqual(child.status, 1); -assert.strictEqual(child.signal, null); -assert.strictEqual(child.stdout.toString().trim(), ''); -assert.ok(child.stderr.toString().includes(errMsg)); diff --git a/test/es-module/test-esm-invalid-pjson.js b/test/es-module/test-esm-invalid-pjson.js index cdbebb17b4bb34..f3a38018637aa3 100644 --- a/test/es-module/test-esm-invalid-pjson.js +++ b/test/es-module/test-esm-invalid-pjson.js @@ -1,27 +1,28 @@ 'use strict'; -const { mustCall, checkoutEOL } = require('../common'); -const fixtures = require('../common/fixtures'); -const { spawn } = require('child_process'); -const { strictEqual, ok } = require('assert'); +const { checkoutEOL, spawnPromisified } = require('../common'); +const fixtures = require('../common/fixtures.js'); +const assert = require('node:assert'); +const { execPath } = require('node:process'); +const { describe, it } = require('node:test'); -const entry = fixtures.path('/es-modules/import-invalid-pjson.mjs'); -const invalidJson = fixtures.path('/node_modules/invalid-pjson/package.json'); -const child = spawn(process.execPath, [entry]); -child.stderr.setEncoding('utf8'); -let stderr = ''; -child.stderr.on('data', (data) => { - stderr += data; +describe('ESM: Package.json', { concurrency: true }, () => { + it('should throw on invalid pson', async () => { + const entry = fixtures.path('/es-modules/import-invalid-pjson.mjs'); + const invalidJson = fixtures.path('/node_modules/invalid-pjson/package.json'); + + const { code, signal, stderr } = await spawnPromisified(execPath, [entry]); + + assert.ok( + stderr.includes( + `[ERR_INVALID_PACKAGE_CONFIG]: Invalid package config ${invalidJson} ` + + `while importing "invalid-pjson" from ${entry}. ` + + `Unexpected token } in JSON at position ${12 + checkoutEOL.length * 2}` + ), + stderr + ); + assert.strictEqual(code, 1); + assert.strictEqual(signal, null); + }); }); -child.on('close', mustCall((code, signal) => { - strictEqual(code, 1); - strictEqual(signal, null); - ok( - stderr.includes( - `[ERR_INVALID_PACKAGE_CONFIG]: Invalid package config ${invalidJson} ` + - `while importing "invalid-pjson" from ${entry}. ` + - `Unexpected token } in JSON at position ${12 + checkoutEOL.length * 2}` - ), - stderr); -})); diff --git a/test/es-module/test-esm-json.mjs b/test/es-module/test-esm-json.mjs index 6d55419eedc857..14c86bac80af98 100644 --- a/test/es-module/test-esm-json.mjs +++ b/test/es-module/test-esm-json.mjs @@ -1,27 +1,25 @@ -import '../common/index.mjs'; -import { path } from '../common/fixtures.mjs'; -import { strictEqual, ok } from 'assert'; -import { spawn } from 'child_process'; +import { spawnPromisified } from '../common/index.mjs'; +import * as fixtures from '../common/fixtures.mjs'; +import assert from 'node:assert'; +import { execPath } from 'node:process'; +import { describe, it } from 'node:test'; import secret from '../fixtures/experimental.json' assert { type: 'json' }; -strictEqual(secret.ofLife, 42); -// Test warning message -const child = spawn(process.execPath, [ - path('/es-modules/json-modules.mjs'), -]); +describe('ESM: importing JSON', () => { + it('should load JSON', () => { + assert.strictEqual(secret.ofLife, 42); + }); -let stderr = ''; -child.stderr.setEncoding('utf8'); -child.stderr.on('data', (data) => { - stderr += data; -}); -child.on('close', (code, signal) => { - strictEqual(code, 0); - strictEqual(signal, null); - ok(stderr.toString().includes( - 'ExperimentalWarning: Importing JSON modules is an experimental feature. ' + - 'This feature could change at any time' - )); + it('should print an experimental warning', async () => { + const { code, signal, stderr } = await spawnPromisified(execPath, [ + fixtures.path('/es-modules/json-modules.mjs'), + ]); + + assert.match(stderr, /ExperimentalWarning/); + assert.match(stderr, /JSON modules/); + assert.strictEqual(code, 0); + assert.strictEqual(signal, null); + }); }); diff --git a/test/es-module/test-esm-loader-chaining.mjs b/test/es-module/test-esm-loader-chaining.mjs index f1ea13495ca5c4..14303cb5c42665 100644 --- a/test/es-module/test-esm-loader-chaining.mjs +++ b/test/es-module/test-esm-loader-chaining.mjs @@ -1,7 +1,9 @@ -import '../common/index.mjs'; -import fixtures from '../common/fixtures.js'; +import { spawnPromisified } from '../common/index.mjs'; +import * as fixtures from '../common/fixtures.mjs'; import assert from 'node:assert'; -import { spawnSync } from 'node:child_process'; +import { execPath } from 'node:process'; +import { describe, it } from 'node:test'; + const setupArgs = [ '--no-warnings', @@ -14,420 +16,420 @@ const commonArgs = [ 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.match(stdout, /number/); // node:fs is an object - assert.strictEqual(status, 0); -} - -{ // 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.match(stdout, /foo/); - 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-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.match(stdout, /foo/); // LIFO, so resolve-foo won - assert.strictEqual(status, 0); -} - -{ // 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.match(stdout, /42/); // LIFO, so resolve-42 won - assert.strictEqual(status, 0); -} - -{ // Verify multiple calls to next within same loader receive correct "next" fn - 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-multiple-next-calls.mjs'), - '--loader', - fixtures.fileURL('es-module-loaders', 'loader-load-foo-or-42.mjs'), - ...commonArgs, - ], - { encoding: 'utf8' }, - ); - - const countFoos = stdout.match(/resolve foo/g)?.length; - - assert.strictEqual(stderr, ''); - assert.strictEqual(countFoos, 2); - assert.strictEqual(status, 0); -} - -{ // Verify next function's `name` is correct - 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'), - ...commonArgs, - ], - { encoding: 'utf8' }, - ); - - assert.strictEqual(stderr, ''); - assert.match(stdout, /next: nextResolve/); - assert.strictEqual(status, 0); -} - -{ // 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.match(stderr, /ERR_LOADER_CHAIN_INCOMPLETE/); - assert.match(stderr, /loader-resolve-incomplete\.mjs/); - assert.match(stderr, /'resolve'/); - assert.strictEqual(status, 1); -} - -{ // 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 resolve 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.match(stderr, /ERR_LOADER_CHAIN_INCOMPLETE/); - assert.match(stderr, /loader-resolve-incomplete\.mjs/); - assert.match(stderr, /'resolve'/); - assert.strictEqual(status, 1); -} - -{ // 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.match(stderr, /ERR_LOADER_CHAIN_INCOMPLETE/); - assert.match(stderr, /loader-load-incomplete\.mjs/); - assert.match(stderr, /'load'/); - assert.strictEqual(status, 1); -} - -{ // Verify load 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.match(stderr, /ERR_LOADER_CHAIN_INCOMPLETE/); - assert.match(stderr, /loader-load-incomplete\.mjs/); - assert.match(stderr, /'load'/); - assert.strictEqual(status, 1); -} - -{ // Verify error thrown when invalid `specifier` argument passed to `nextResolve` - 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' hook's nextResolve\(\) specifier/); -} - -{ // Verify error thrown when resolve hook is invalid - const { status, stderr } = spawnSync( - process.execPath, - [ - '--loader', - fixtures.fileURL('es-module-loaders', 'loader-resolve-passthru.mjs'), - '--loader', - fixtures.fileURL('es-module-loaders', 'loader-resolve-null-return.mjs'), - ...commonArgs, - ], - { encoding: 'utf8' }, - ); - - assert.strictEqual(status, 1); - assert.match(stderr, /ERR_INVALID_RETURN_VALUE/); - assert.match(stderr, /loader-resolve-null-return\.mjs/); - assert.match(stderr, /'resolve' hook's nextResolve\(\)/); - assert.match(stderr, /an object/); - assert.match(stderr, /got null/); -} - -{ // Verify error thrown when invalid `context` argument passed to `nextResolve` - 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.match(stderr, /ERR_INVALID_ARG_TYPE/); - assert.match(stderr, /loader-resolve-bad-next-context\.mjs/); - assert.match(stderr, /'resolve' hook's nextResolve\(\) context/); - assert.strictEqual(status, 1); -} - -{ // Verify error thrown when load hook is invalid - const { status, stderr } = spawnSync( - process.execPath, - [ - '--loader', - fixtures.fileURL('es-module-loaders', 'loader-load-passthru.mjs'), - '--loader', - fixtures.fileURL('es-module-loaders', 'loader-load-null-return.mjs'), - ...commonArgs, - ], - { encoding: 'utf8' }, - ); - - assert.strictEqual(status, 1); - assert.match(stderr, /ERR_INVALID_RETURN_VALUE/); - assert.match(stderr, /loader-load-null-return\.mjs/); - assert.match(stderr, /'load' hook's nextLoad\(\)/); - assert.match(stderr, /an object/); - assert.match(stderr, /got null/); -} - -{ // Verify error thrown when invalid `url` argument passed to `nextLoad` - 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.match(stderr, /ERR_INVALID_ARG_TYPE/); - assert.match(stderr, /loader-load-bad-next-url\.mjs/); - assert.match(stderr, /'load' hook's nextLoad\(\) url/); - assert.strictEqual(status, 1); -} - -{ // Verify error thrown when invalid `url` argument passed to `nextLoad` - 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.match(stderr, /ERR_INVALID_ARG_VALUE/); - assert.match(stderr, /loader-load-impersonating-next-url\.mjs/); - assert.match(stderr, /'load' hook's nextLoad\(\) url/); - assert.strictEqual(status, 1); -} - -{ // Verify error thrown when invalid `context` argument passed to `nextLoad` - 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.match(stderr, /ERR_INVALID_ARG_TYPE/); - assert.match(stderr, /loader-load-bad-next-context\.mjs/); - assert.match(stderr, /'load' hook's nextLoad\(\) context/); - assert.strictEqual(status, 1); -} +describe('ESM: loader chaining', { concurrency: true }, () => { + it('should load unadulterated source when there are no loaders', async () => { + const { code, stderr, stdout } = await spawnPromisified( + execPath, + [ + ...setupArgs, + 'import fs from "node:fs"; console.log(typeof fs?.constants?.F_OK )', + ], + { encoding: 'utf8' }, + ); + + assert.strictEqual(stderr, ''); + assert.match(stdout, /number/); // node:fs is an object + assert.strictEqual(code, 0); + }); + + it('should load properly different source when only load changes something', async () => { + const { code, stderr, stdout } = await spawnPromisified( + 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.match(stdout, /foo/); + assert.strictEqual(code, 0); + }); + + it('should result in proper output from multiple changes in resolve hooks', async () => { + const { code, stderr, stdout } = await spawnPromisified( + 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.match(stdout, /foo/); // LIFO, so resolve-foo won + assert.strictEqual(code, 0); + }); + + it('should respect modified context within resolve chain', async () => { + const { code, stderr, stdout } = await spawnPromisified( + 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(code, 0); + }); + + it('should result in proper output from multiple changes in resolve hooks', async () => { + const { code, stderr, stdout } = await spawnPromisified( + 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.match(stdout, /42/); // LIFO, so resolve-42 won + assert.strictEqual(code, 0); + }); + + it('should provide the correct "next" fn when multiple calls to next within same loader', async () => { + const { code, stderr, stdout } = await spawnPromisified( + 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-multiple-next-calls.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-load-foo-or-42.mjs'), + ...commonArgs, + ], + { encoding: 'utf8' }, + ); + + const countFoos = stdout.match(/resolve foo/g)?.length; + + assert.strictEqual(stderr, ''); + assert.strictEqual(countFoos, 2); + assert.strictEqual(code, 0); + }); + + it('should use the correct `name` for next\'s function', async () => { + const { code, stderr, stdout } = await spawnPromisified( + 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'), + ...commonArgs, + ], + { encoding: 'utf8' }, + ); + + assert.strictEqual(stderr, ''); + assert.match(stdout, /next: nextResolve/); + assert.strictEqual(code, 0); + }); + + it('should throw for incomplete resolve chain, citing errant loader & hook', async () => { + const { code, stderr, stdout } = await spawnPromisified( + 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.match(stderr, /ERR_LOADER_CHAIN_INCOMPLETE/); + assert.match(stderr, /loader-resolve-incomplete\.mjs/); + assert.match(stderr, /'resolve'/); + assert.strictEqual(code, 1); + }); + + it('should NOT throw when nested resolve hook signaled a short circuit', async () => { + const { code, stderr, stdout } = await spawnPromisified( + 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(code, 0); + }); + + it('should NOT throw when nested load hook signaled a short circuit', async () => { + const { code, stderr, stdout } = await spawnPromisified( + 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(code, 0); + }); + + it('should throw when the resolve chain is broken', async () => { + const { code, stderr, stdout } = await spawnPromisified( + 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.match(stderr, /ERR_LOADER_CHAIN_INCOMPLETE/); + assert.match(stderr, /loader-resolve-incomplete\.mjs/); + assert.match(stderr, /'resolve'/); + assert.strictEqual(code, 1); + }); + + it('should throw for incomplete load chain, citing errant loader & hook', async () => { + const { code, stderr, stdout } = await spawnPromisified( + 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.match(stderr, /ERR_LOADER_CHAIN_INCOMPLETE/); + assert.match(stderr, /loader-load-incomplete\.mjs/); + assert.match(stderr, /'load'/); + assert.strictEqual(code, 1); + }); + + it('should throw when the load chain is broken', async () => { + const { code, stderr, stdout } = await spawnPromisified( + 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.match(stderr, /ERR_LOADER_CHAIN_INCOMPLETE/); + assert.match(stderr, /loader-load-incomplete\.mjs/); + assert.match(stderr, /'load'/); + assert.strictEqual(code, 1); + }); + + it('should throw when invalid `specifier` argument passed to `nextResolve`', async () => { + const { code, stderr } = await spawnPromisified( + 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(code, 1); + assert.match(stderr, /ERR_INVALID_ARG_TYPE/); + assert.match(stderr, /loader-resolve-bad-next-specifier\.mjs/); + assert.match(stderr, /'resolve' hook's nextResolve\(\) specifier/); + }); + + it('should throw when resolve hook is invalid', async () => { + const { code, stderr } = await spawnPromisified( + execPath, + [ + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-resolve-passthru.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-resolve-null-return.mjs'), + ...commonArgs, + ], + { encoding: 'utf8' }, + ); + + assert.strictEqual(code, 1); + assert.match(stderr, /ERR_INVALID_RETURN_VALUE/); + assert.match(stderr, /loader-resolve-null-return\.mjs/); + assert.match(stderr, /'resolve' hook's nextResolve\(\)/); + assert.match(stderr, /an object/); + assert.match(stderr, /got null/); + }); + + it('should throw when invalid `context` argument passed to `nextResolve`', async () => { + const { code, stderr } = await spawnPromisified( + 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.match(stderr, /ERR_INVALID_ARG_TYPE/); + assert.match(stderr, /loader-resolve-bad-next-context\.mjs/); + assert.match(stderr, /'resolve' hook's nextResolve\(\) context/); + assert.strictEqual(code, 1); + }); + + it('should throw when load hook is invalid', async () => { + const { code, stderr } = await spawnPromisified( + execPath, + [ + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-load-passthru.mjs'), + '--loader', + fixtures.fileURL('es-module-loaders', 'loader-load-null-return.mjs'), + ...commonArgs, + ], + { encoding: 'utf8' }, + ); + + assert.strictEqual(code, 1); + assert.match(stderr, /ERR_INVALID_RETURN_VALUE/); + assert.match(stderr, /loader-load-null-return\.mjs/); + assert.match(stderr, /'load' hook's nextLoad\(\)/); + assert.match(stderr, /an object/); + assert.match(stderr, /got null/); + }); + + it('should throw when invalid `url` argument passed to `nextLoad`', async () => { + const { code, stderr } = await spawnPromisified( + 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.match(stderr, /ERR_INVALID_ARG_TYPE/); + assert.match(stderr, /loader-load-bad-next-url\.mjs/); + assert.match(stderr, /'load' hook's nextLoad\(\) url/); + assert.strictEqual(code, 1); + }); + + it('should throw when invalid `url` argument passed to `nextLoad`', async () => { + const { code, stderr } = await spawnPromisified( + 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.match(stderr, /ERR_INVALID_ARG_VALUE/); + assert.match(stderr, /loader-load-impersonating-next-url\.mjs/); + assert.match(stderr, /'load' hook's nextLoad\(\) url/); + assert.strictEqual(code, 1); + }); + + it('should throw when invalid `context` argument passed to `nextLoad`', async () => { + const { code, stderr } = await spawnPromisified( + 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.match(stderr, /ERR_INVALID_ARG_TYPE/); + assert.match(stderr, /loader-load-bad-next-context\.mjs/); + assert.match(stderr, /'load' hook's nextLoad\(\) context/); + assert.strictEqual(code, 1); + }); +}); diff --git a/test/es-module/test-esm-loader-http-imports.mjs b/test/es-module/test-esm-loader-http-imports.mjs index 5f6cc47f388271..ad42829f5d1cee 100644 --- a/test/es-module/test-esm-loader-http-imports.mjs +++ b/test/es-module/test-esm-loader-http-imports.mjs @@ -1,10 +1,11 @@ -import { mustCall } from '../common/index.mjs'; +import { spawnPromisified } from '../common/index.mjs'; import fixtures from '../common/fixtures.js'; -import { strictEqual } from 'node:assert'; -import { spawn } from 'node:child_process'; +import assert from 'node:assert'; import http from 'node:http'; import path from 'node:path'; +import { execPath } from 'node:process'; import { promisify } from 'node:util'; +import { describe, it } from 'node:test'; const files = { @@ -40,33 +41,31 @@ const { port, } = server.address(); -{ // Verify nested HTTP imports work - const child = spawn( // ! `spawn` MUST be used (vs `spawnSync`) to avoid blocking the event loop - process.execPath, - [ - '--no-warnings', - '--loader', - fixtures.fileURL('es-module-loaders', 'http-loader.mjs'), - '--input-type=module', - '--eval', - `import * as main from 'http://${host}:${port}/main.mjs'; console.log(main)`, - ] - ); +/** + * ! If more cases are added to this test, they cannot (yet) be concurrent because there is no + * ! `afterAll` teardown in which to close the server. + */ - let stderr = ''; - let stdout = ''; +describe('ESM: http import via loader', { concurrency: false }, () => { + it('should work', async () => { + // ! MUST NOT use spawnSync to avoid blocking the event loop + const { code, signal, stderr, stdout } = await spawnPromisified( + execPath, + [ + '--no-warnings', + '--loader', + fixtures.fileURL('es-module-loaders', 'http-loader.mjs'), + '--input-type=module', + '--eval', + `import * as main from 'http://${host}:${port}/main.mjs'; console.log(main)`, + ] + ); - child.stderr.setEncoding('utf8'); - child.stderr.on('data', (data) => stderr += data); - child.stdout.setEncoding('utf8'); - child.stdout.on('data', (data) => stdout += data); + assert.strictEqual(stderr, ''); + assert.strictEqual(stdout, '[Module: null prototype] { sum: [Function: sum] }\n'); + assert.strictEqual(code, 0); + assert.strictEqual(signal, null); - child.on('close', mustCall((code, signal) => { - strictEqual(stderr, ''); - strictEqual(stdout, '[Module: null prototype] { sum: [Function: sum] }\n'); - strictEqual(code, 0); - strictEqual(signal, null); - - server.close(); - })); -} + server.close(); // ! This MUST come after the final test, but inside the async `it` function + }); +}); diff --git a/test/es-module/test-esm-loader-not-found.mjs b/test/es-module/test-esm-loader-not-found.mjs index 275f0b0f1e8515..2abaf3078d113d 100644 --- a/test/es-module/test-esm-loader-not-found.mjs +++ b/test/es-module/test-esm-loader-not-found.mjs @@ -1,27 +1,24 @@ -import { mustCall } from '../common/index.mjs'; -import { path } from '../common/fixtures.mjs'; -import { match, ok, notStrictEqual } from 'assert'; -import { spawn } from 'child_process'; -import { execPath } from 'process'; +import { spawnPromisified } from '../common/index.mjs'; +import * as fixtures from '../common/fixtures.mjs'; +import assert from 'node:assert'; +import { execPath } from 'node:process'; +import { describe, it } from 'node:test'; -const child = spawn(execPath, [ - '--experimental-loader', - 'i-dont-exist', - path('print-error-message.js'), -]); -let stderr = ''; -child.stderr.setEncoding('utf8'); -child.stderr.on('data', (data) => { - stderr += data; -}); -child.on('close', mustCall((code, _signal) => { - notStrictEqual(code, 0); +describe('ESM: nonexistent loader', () => { + it('should throw', async () => { + const { code, stderr } = await spawnPromisified(execPath, [ + '--experimental-loader', + 'i-dont-exist', + fixtures.path('print-error-message.js'), + ]); + + assert.notStrictEqual(code, 0); - // Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'i-dont-exist' - // imported from - match(stderr, /ERR_MODULE_NOT_FOUND/); - match(stderr, /'i-dont-exist'/); + // Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'i-dont-exist' imported from + assert.match(stderr, /ERR_MODULE_NOT_FOUND/); + assert.match(stderr, /'i-dont-exist'/); - ok(!stderr.includes('Bad command or file name')); -})); + assert.ok(!stderr.includes('Bad command or file name')); + }); +}); diff --git a/test/es-module/test-esm-loader-obsolete-hooks.mjs b/test/es-module/test-esm-loader-obsolete-hooks.mjs index eff4104fc265ae..fa0baef8a216b7 100644 --- a/test/es-module/test-esm-loader-obsolete-hooks.mjs +++ b/test/es-module/test-esm-loader-obsolete-hooks.mjs @@ -1,30 +1,28 @@ -import { mustCall } from '../common/index.mjs'; +import { spawnPromisified } from '../common/index.mjs'; import { fileURL, path } from '../common/fixtures.mjs'; -import { match, notStrictEqual } from 'assert'; -import { spawn } from 'child_process'; -import { execPath } from 'process'; +import { match, notStrictEqual } from 'node:assert'; +import { execPath } from 'node:process'; +import { describe, it } from 'node:test'; -const child = spawn(execPath, [ - '--no-warnings', - '--throw-deprecation', - '--experimental-loader', - fileURL('es-module-loaders', 'hooks-obsolete.mjs').href, - path('print-error-message.js'), -]); -let stderr = ''; -child.stderr.setEncoding('utf8'); -child.stderr.on('data', (data) => { - stderr += data; -}); -child.on('close', mustCall((code, _signal) => { - notStrictEqual(code, 0); +describe('ESM: deprecation warnings for obsolete hooks', { concurrency: true }, () => { + it(async () => { + const { code, stderr } = await spawnPromisified(execPath, [ + '--no-warnings', + '--throw-deprecation', + '--experimental-loader', + fileURL('es-module-loaders', 'hooks-obsolete.mjs').href, + path('print-error-message.js'), + ]); + + // DeprecationWarning: Obsolete loader hook(s) supplied and will be ignored: + // dynamicInstantiate, getFormat, getSource, transformSource + match(stderr, /DeprecationWarning:/); + match(stderr, /dynamicInstantiate/); + match(stderr, /getFormat/); + match(stderr, /getSource/); + match(stderr, /transformSource/); - // DeprecationWarning: Obsolete loader hook(s) supplied and will be ignored: - // dynamicInstantiate, getFormat, getSource, transformSource - match(stderr, /DeprecationWarning:/); - match(stderr, /dynamicInstantiate/); - match(stderr, /getFormat/); - match(stderr, /getSource/); - match(stderr, /transformSource/); -})); + notStrictEqual(code, 0); + }); +}); diff --git a/test/es-module/test-esm-loader-thenable.mjs b/test/es-module/test-esm-loader-thenable.mjs index c8c3ec2778e7e9..5e802b8393bcd4 100644 --- a/test/es-module/test-esm-loader-thenable.mjs +++ b/test/es-module/test-esm-loader-thenable.mjs @@ -1,65 +1,43 @@ -import { mustCall } from '../common/index.mjs'; +import { spawnPromisified } from '../common/index.mjs'; import { fileURL, path } from '../common/fixtures.mjs'; import { match, ok, notStrictEqual, strictEqual } from 'assert'; -import { spawn } from 'child_process'; -import { execPath } from 'process'; +import { execPath } from 'node:process'; +import { describe, it } from 'node:test'; -{ - const child = spawn(execPath, [ - '--experimental-loader', - fileURL('es-module-loaders', 'thenable-load-hook.mjs').href, - path('es-modules', 'test-esm-ok.mjs'), - ]); - let stderr = ''; - child.stderr.setEncoding('utf8'); - child.stderr.on('data', (data) => { - stderr += data; - }); - child.on('close', mustCall((code, _signal) => { +describe('ESM: thenable loader hooks', { concurrency: true }, () => { + it('should behave as a normal promise resolution', async () => { + const { code, stderr } = await spawnPromisified(execPath, [ + '--experimental-loader', + fileURL('es-module-loaders', 'thenable-load-hook.mjs').href, + path('es-modules', 'test-esm-ok.mjs'), + ]); + strictEqual(code, 0); ok(!stderr.includes('must not call')); - })); -} + }); -{ - const child = spawn(execPath, [ - '--experimental-loader', - fileURL('es-module-loaders', 'thenable-load-hook-rejected.mjs').href, - path('es-modules', 'test-esm-ok.mjs'), - ]); + it('should crash the node process rejection with an error', async () => { + const { code, stderr } = await spawnPromisified(execPath, [ + '--experimental-loader', + fileURL('es-module-loaders', 'thenable-load-hook-rejected.mjs').href, + path('es-modules', 'test-esm-ok.mjs'), + ]); - let stderr = ''; - child.stderr.setEncoding('utf8'); - child.stderr.on('data', (data) => { - stderr += data; - }); - child.on('close', mustCall((code, _signal) => { notStrictEqual(code, 0); - match(stderr, /\sError: must crash the process\r?\n/); - ok(!stderr.includes('must not call')); - })); -} + }); -{ - const child = spawn(execPath, [ - '--experimental-loader', - fileURL('es-module-loaders', 'thenable-load-hook-rejected-no-arguments.mjs').href, - path('es-modules', 'test-esm-ok.mjs'), - ]); + it('should just reject without an error (but NOT crash the node process)', async () => { + const { code, stderr } = await spawnPromisified(execPath, [ + '--experimental-loader', + fileURL('es-module-loaders', 'thenable-load-hook-rejected-no-arguments.mjs').href, + path('es-modules', 'test-esm-ok.mjs'), + ]); - let stderr = ''; - child.stderr.setEncoding('utf8'); - child.stderr.on('data', (data) => { - stderr += data; - }); - child.on('close', mustCall((code, _signal) => { notStrictEqual(code, 0); - match(stderr, /\sundefined\r?\n/); - ok(!stderr.includes('must not call')); - })); -} + }); +}); diff --git a/test/es-module/test-esm-loader-with-syntax-error.mjs b/test/es-module/test-esm-loader-with-syntax-error.mjs index d973e72975e88f..0ed995ad510ee7 100644 --- a/test/es-module/test-esm-loader-with-syntax-error.mjs +++ b/test/es-module/test-esm-loader-with-syntax-error.mjs @@ -1,24 +1,20 @@ -import { mustCall } from '../common/index.mjs'; +import { spawnPromisified } from '../common/index.mjs'; import { fileURL, path } from '../common/fixtures.mjs'; -import { match, ok, notStrictEqual } from 'assert'; -import { spawn } from 'child_process'; -import { execPath } from 'process'; +import { match, ok, notStrictEqual } from 'node:assert'; +import { execPath } from 'node:process'; +import { describe, it } from 'node:test'; -const child = spawn(execPath, [ - '--experimental-loader', - fileURL('es-module-loaders', 'syntax-error.mjs').href, - path('print-error-message.js'), -]); -let stderr = ''; -child.stderr.setEncoding('utf8'); -child.stderr.on('data', (data) => { - stderr += data; -}); -child.on('close', mustCall((code, _signal) => { - notStrictEqual(code, 0); - - match(stderr, /SyntaxError:/); +describe('ESM: loader with syntax error', { concurrency: true }, () => { + it('should crash the node process', async () => { + const { code, stderr } = await spawnPromisified(execPath, [ + '--experimental-loader', + fileURL('es-module-loaders', 'syntax-error.mjs').href, + path('print-error-message.js'), + ]); - ok(!stderr.includes('Bad command or file name')); -})); + match(stderr, /SyntaxError:/); + ok(!stderr.includes('Bad command or file name')); + notStrictEqual(code, 0); + }); +}); diff --git a/test/es-module/test-esm-module-not-found-commonjs-hint.mjs b/test/es-module/test-esm-module-not-found-commonjs-hint.mjs index 58f70d0b685391..51633564f81458 100644 --- a/test/es-module/test-esm-module-not-found-commonjs-hint.mjs +++ b/test/es-module/test-esm-module-not-found-commonjs-hint.mjs @@ -1,35 +1,34 @@ -import { mustCall } from '../common/index.mjs'; +import { spawnPromisified } from '../common/index.mjs'; import { fixturesDir } from '../common/fixtures.mjs'; -import { match, notStrictEqual } from 'assert'; -import { spawn } from 'child_process'; -import { execPath } from 'process'; +import { match, notStrictEqual } from 'node:assert'; +import { execPath } from 'node:process'; +import { describe, it } from 'node:test'; -[ - { - input: 'import "./print-error-message"', - // Did you mean to import ../print-error-message.js? - expected: / \.\.\/print-error-message\.js\?/, - }, - { - input: 'import obj from "some_module/obj"', - expected: / some_module\/obj\.js\?/, - }, -].forEach(({ input, expected }) => { - const child = spawn(execPath, [ - '--input-type=module', - '--eval', - input, - ], { - cwd: fixturesDir, - }); - let stderr = ''; - child.stderr.setEncoding('utf8'); - child.stderr.on('data', (data) => { - stderr += data; - }); - child.on('close', mustCall((code, _signal) => { - notStrictEqual(code, 0); +describe('ESM: module not found hint', { concurrency: true }, () => { + for ( + const { input, expected } + of [ + { + input: 'import "./print-error-message"', + // Did you mean to import ../print-error-message.js? + expected: / \.\.\/print-error-message\.js\?/, + }, + { + input: 'import obj from "some_module/obj"', + expected: / some_module\/obj\.js\?/, + }, + ] + ) it('should cite a variant form', async () => { + const { code, stderr } = await spawnPromisified(execPath, [ + '--input-type=module', + '--eval', + input, + ], { + cwd: fixturesDir, + }); + match(stderr, expected); - })); + notStrictEqual(code, 0); + }); }); diff --git a/test/es-module/test-esm-non-js.mjs b/test/es-module/test-esm-non-js.mjs index 749cd0b6132086..2630d3136a42ba 100644 --- a/test/es-module/test-esm-non-js.mjs +++ b/test/es-module/test-esm-non-js.mjs @@ -1,23 +1,20 @@ -import { mustCall } from '../common/index.mjs'; +import { spawnPromisified } from '../common/index.mjs'; import { fileURL } from '../common/fixtures.mjs'; -import { match, strictEqual } from 'assert'; -import { spawn } from 'child_process'; -import { execPath } from 'process'; +import { match, strictEqual } from 'node:assert'; +import { execPath } from 'node:process'; +import { describe, it } from 'node:test'; -// Verify non-js extensions fail for ESM -const child = spawn(execPath, [ - '--input-type=module', - '--eval', - `import ${JSON.stringify(fileURL('es-modules', 'file.unknown'))}`, -]); -let stderr = ''; -child.stderr.setEncoding('utf8'); -child.stderr.on('data', (data) => { - stderr += data; +describe('ESM: non-js extensions fail', { concurrency: true }, () => { + it(async () => { + const { code, stderr, signal } = await spawnPromisified(execPath, [ + '--input-type=module', + '--eval', + `import ${JSON.stringify(fileURL('es-modules', 'file.unknown'))}`, + ]); + + match(stderr, /ERR_UNKNOWN_FILE_EXTENSION/); + strictEqual(code, 1); + strictEqual(signal, null); + }); }); -child.on('close', mustCall((code, signal) => { - strictEqual(code, 1); - strictEqual(signal, null); - match(stderr, /ERR_UNKNOWN_FILE_EXTENSION/); -})); diff --git a/test/es-module/test-esm-nowarn-exports.mjs b/test/es-module/test-esm-nowarn-exports.mjs index 57d5bc58c72356..695e924e03ccbe 100644 --- a/test/es-module/test-esm-nowarn-exports.mjs +++ b/test/es-module/test-esm-nowarn-exports.mjs @@ -1,25 +1,19 @@ -import '../common/index.mjs'; +import { spawnPromisified } from '../common/index.mjs'; import { path } from '../common/fixtures.mjs'; -import { strictEqual, ok } from 'assert'; -import { spawn } from 'child_process'; +import { strictEqual } from 'node:assert'; +import { execPath } from 'node:process'; +import { describe, it } from 'node:test'; -const child = spawn(process.execPath, [ - '--experimental-import-meta-resolve', - path('/es-modules/import-resolve-exports.mjs'), -]); -let stderr = ''; -child.stderr.setEncoding('utf8'); -child.stderr.on('data', (data) => { - stderr += data; -}); -child.on('close', (code, signal) => { - strictEqual(code, 0); - strictEqual(signal, null); - ok(!stderr.toString().includes( - 'ExperimentalWarning: The ESM module loader is experimental' - )); - ok(!stderr.toString().includes( - 'ExperimentalWarning: Conditional exports' - )); +describe('ESM: experiemental warning for import.meta.resolve', { concurrency: true }, () => { + it('should not warn when caught', async () => { + const { code, signal, stderr } = await spawnPromisified(execPath, [ + '--experimental-import-meta-resolve', + path('es-modules/import-resolve-exports.mjs'), + ]); + + strictEqual(stderr, ''); + strictEqual(code, 0); + strictEqual(signal, null); + }); }); diff --git a/test/es-module/test-esm-preserve-symlinks-main.js b/test/es-module/test-esm-preserve-symlinks-main.js index b8fb301e02d85b..6f921f656fe22f 100644 --- a/test/es-module/test-esm-preserve-symlinks-main.js +++ b/test/es-module/test-esm-preserve-symlinks-main.js @@ -39,15 +39,15 @@ function doTest(flags, done) { // dictates that it'll resolve relative imports in the main file relative to // the symlink, and not relative to the symlink target; the file structure set // up above requires this to not crash when loading ./submodule_link.js - spawn(process.execPath, - flags.concat([ - '--preserve-symlinks', - '--preserve-symlinks-main', entry_link_absolute_path, - ]), - { stdio: 'inherit' }).on('exit', (code) => { - assert.strictEqual(code, 0); - done(); - }); + spawn(process.execPath, [ + '--preserve-symlinks', + '--preserve-symlinks-main', + entry_link_absolute_path, + ], { stdio: 'inherit' }) + .on('exit', (code) => { + assert.strictEqual(code, 0); + done(); + }); } // First test the commonjs module loader diff --git a/test/es-module/test-esm-repl-imports.js b/test/es-module/test-esm-repl-imports.js index d2b39e05fb0588..9547824756f5ec 100644 --- a/test/es-module/test-esm-repl-imports.js +++ b/test/es-module/test-esm-repl-imports.js @@ -1,19 +1,28 @@ 'use strict'; + const { mustCall } = require('../common'); -const assert = require('assert'); const fixtures = require('../common/fixtures'); -const { spawn } = require('child_process'); +const assert = require('node:assert'); +const { spawn } = require('node:child_process'); +const { execPath } = require('node:process'); +const { describe, it } = require('node:test'); -const child = spawn(process.execPath, [ - '--interactive', -], { - cwd: fixtures.path('es-modules', 'pkgimports'), -}); -child.stdin.end( - 'try{require("#test");await import("#test")}catch{process.exit(-1)}' -); +describe('ESM: REPL runs', { concurrency: true }, () => { + it((context, done) => { + const child = spawn(execPath, [ + '--interactive', + ], { + cwd: fixtures.path('es-modules', 'pkgimports'), + }); -child.on('exit', mustCall((code) => { - assert.strictEqual(code, 0); -})); + child.stdin.end( + 'try{require("#test");await import("#test")}catch{process.exit(-1)}' + ); + + child.on('exit', mustCall((code) => { + assert.strictEqual(code, 0); + done(); + })); + }); +}); diff --git a/test/es-module/test-esm-specifiers.mjs b/test/es-module/test-esm-specifiers.mjs index bc6125f5f94ad9..670cd93c9b0b28 100644 --- a/test/es-module/test-esm-specifiers.mjs +++ b/test/es-module/test-esm-specifiers.mjs @@ -1,62 +1,79 @@ -// Flags: --experimental-specifier-resolution=node -import { mustNotCall } from '../common/index.mjs'; -import assert from 'assert'; -import path from 'path'; -import { spawn } from 'child_process'; -import { fileURLToPath } from 'url'; - -// commonJS index.js -import commonjs from '../fixtures/es-module-specifiers/package-type-commonjs'; -// esm index.js -import module from '../fixtures/es-module-specifiers/package-type-module'; -// Notice the trailing slash -import success, { explicit, implicit, implicitModule, getImplicitCommonjs } - from '../fixtures/es-module-specifiers/'; - -assert.strictEqual(commonjs, 'commonjs'); -assert.strictEqual(module, 'module'); -assert.strictEqual(success, 'success'); -assert.strictEqual(explicit, 'esm'); -assert.strictEqual(implicit, 'cjs'); -assert.strictEqual(implicitModule, 'cjs'); - -async function main() { - try { - await import('../fixtures/es-module-specifiers/do-not-exist.js'); - } catch (e) { - // Files that do not exist should throw - assert.strictEqual(e.name, 'Error'); - } - try { - await getImplicitCommonjs(); - } catch (e) { - // Legacy loader cannot resolve .mjs automatically from main - assert.strictEqual(e.name, 'Error'); - } -} - -main().catch(mustNotCall); - -// Test path from command line arguments -[ - 'package-type-commonjs', - 'package-type-module', - '/', - '/index', -].forEach((item) => { - const modulePath = path.join( - fileURLToPath(import.meta.url), - '../../fixtures/es-module-specifiers', - item, - ); - [ - '--experimental-specifier-resolution', - '--es-module-specifier-resolution', - ].forEach((option) => { - spawn(process.execPath, - [`${option}=node`, modulePath], - { stdio: 'inherit' }).on('exit', (code) => { - assert.strictEqual(code, 0); - }); +import { spawnPromisified } from '../common/index.mjs'; +import * as fixtures from '../common/fixtures.mjs'; +import { match, strictEqual } from 'node:assert'; +import { execPath } from 'node:process'; +import { describe, it } from 'node:test'; + + +describe('ESM: specifier-resolution=node', { concurrency: true }, () => { + it(async () => { + const { code, stderr, stdout } = await spawnPromisified(execPath, [ + '--no-warnings', + '--experimental-specifier-resolution=node', + '--input-type=module', + '--eval', + [ + 'import { strictEqual } from "node:assert";', + // commonJS index.js + `import commonjs from ${JSON.stringify(fixtures.fileURL('es-module-specifiers/package-type-commonjs'))};`, + // esm index.js + `import module from ${JSON.stringify(fixtures.fileURL('es-module-specifiers/package-type-module'))};`, + // Notice the trailing slash + `import success, { explicit, implicit, implicitModule } from ${JSON.stringify(fixtures.fileURL('es-module-specifiers/'))};`, + 'strictEqual(commonjs, "commonjs");', + 'strictEqual(module, "module");', + 'strictEqual(success, "success");', + 'strictEqual(explicit, "esm");', + 'strictEqual(implicit, "cjs");', + 'strictEqual(implicitModule, "cjs");', + ].join('\n'), + ]); + + strictEqual(stderr, ''); + strictEqual(stdout, ''); + strictEqual(code, 0); + }); + + it('should throw when the file doesn\'t exist', async () => { + const { code, stderr, stdout } = await spawnPromisified(execPath, [ + '--no-warnings', + fixtures.path('es-module-specifiers/do-not-exist.js'), + ]); + + match(stderr, /Cannot find module/); + strictEqual(stdout, ''); + strictEqual(code, 1); + }); + + it('should throw when the omitted file extension is .mjs (legacy loader doesn\'t support it)', async () => { + const { code, stderr, stdout } = await spawnPromisified(execPath, [ + '--no-warnings', + '--experimental-specifier-resolution=node', + '--input-type=module', + '--eval', + `import whatever from ${JSON.stringify(fixtures.fileURL('es-module-specifiers/implicit-main-type-commonjs'))};`, + ]); + + match(stderr, /ERR_MODULE_NOT_FOUND/); + strictEqual(stdout, ''); + strictEqual(code, 1); + }); + + for ( + const item of [ + 'package-type-commonjs', + 'package-type-module', + '/', + '/index', + ] + ) it('should ', async () => { + const { code } = await spawnPromisified(execPath, [ + '--no-warnings', + '--experimental-specifier-resolution=node', + '--es-module-specifier-resolution=node', + fixtures.path('es-module-specifiers', item), + ]); + + strictEqual(code, 0); }); }); diff --git a/test/es-module/test-esm-syntax-error.mjs b/test/es-module/test-esm-syntax-error.mjs index a8c019171717dd..de87187b069441 100644 --- a/test/es-module/test-esm-syntax-error.mjs +++ b/test/es-module/test-esm-syntax-error.mjs @@ -1,19 +1,16 @@ -import { mustCall } from '../common/index.mjs'; +import { spawnPromisified } from '../common/index.mjs'; import { path } from '../common/fixtures.mjs'; -import { match, notStrictEqual } from 'assert'; -import { spawn } from 'child_process'; -import { execPath } from 'process'; +import { match, notStrictEqual } from 'node:assert'; +import { execPath } from 'node:process'; +import { describe, it } from 'node:test'; -const child = spawn(execPath, [ - path('es-module-loaders', 'syntax-error.mjs'), -]); -let stderr = ''; -child.stderr.setEncoding('utf8'); -child.stderr.on('data', (data) => { - stderr += data; +describe('ESM: importing a module with syntax error(s)', { concurrency: true }, () => { + it('should throw', async () => { + const { code, stderr } = await spawnPromisified(execPath, [ + path('es-module-loaders', 'syntax-error.mjs'), + ]); + match(stderr, /SyntaxError:/); + notStrictEqual(code, 0); + }); }); -child.on('close', mustCall((code, _signal) => { - notStrictEqual(code, 0); - match(stderr, /SyntaxError:/); -})); diff --git a/test/es-module/test-esm-tla-unfinished.mjs b/test/es-module/test-esm-tla-unfinished.mjs index a7b6e620d0620a..48bc4d77f42b4e 100644 --- a/test/es-module/test-esm-tla-unfinished.mjs +++ b/test/es-module/test-esm-tla-unfinished.mjs @@ -1,7 +1,9 @@ -import '../common/index.mjs'; -import assert from 'assert'; -import child_process from 'child_process'; +import { spawnPromisified } from '../common/index.mjs'; import fixtures from '../common/fixtures.js'; +import assert from 'node:assert'; +import { execPath } from 'node:process'; +import { describe, it } from 'node:test'; + const commonArgs = [ '--no-warnings', @@ -9,102 +11,117 @@ const commonArgs = [ '--eval', ]; -{ - // Unresolved TLA promise, --eval - const { status, stdout, stderr } = child_process.spawnSync( - process.execPath, - [...commonArgs, 'await new Promise(() => {})'], - { encoding: 'utf8' }); - assert.deepStrictEqual([status, stdout, stderr], [13, '', '']); -} - -{ - // Rejected TLA promise, --eval - const { status, stdout, stderr } = child_process.spawnSync( - process.execPath, - [...commonArgs, 'await Promise.reject(new Error("Xyz"))'], - { encoding: 'utf8' }); - assert.deepStrictEqual([status, stdout], [1, '']); - assert.match(stderr, /Error: Xyz/); -} - -{ - // Unresolved TLA promise with explicit exit code, --eval - const { status, stdout, stderr } = child_process.spawnSync( - process.execPath, - [ +describe('ESM: unsettled and rejected promises', { concurrency: true }, () => { + it('should exit for an unsettled TLA promise via --eval', async () => { + const { code, stderr, stdout } = await spawnPromisified(execPath, [ + ...commonArgs, + 'await new Promise(() => {})', + ]); + + assert.strictEqual(stderr, ''); + assert.strictEqual(stdout, ''); + assert.strictEqual(code, 13); + }); + + it('should throw for a rejected TLA promise via --eval', async () => { + // Rejected TLA promise, --eval + const { code, stderr, stdout } = await spawnPromisified(execPath, [ + ...commonArgs, + 'await Promise.reject(new Error("Xyz"))', + ]); + + assert.match(stderr, /Error: Xyz/); + assert.strictEqual(stdout, ''); + assert.strictEqual(code, 1); + }); + + it('should exit for an unsettled TLA promise and respect explicit exit code via --eval', async () => { + // Rejected TLA promise, --eval + const { code, stderr, stdout } = await spawnPromisified(execPath, [ ...commonArgs, 'process.exitCode = 42;await new Promise(() => {})', - ], - { encoding: 'utf8' }); - assert.deepStrictEqual([status, stdout, stderr], [42, '', '']); -} - -{ - // Rejected TLA promise with explicit exit code, --eval - const { status, stdout, stderr } = child_process.spawnSync( - process.execPath, - [ + ]); + + assert.strictEqual(stderr, ''); + assert.strictEqual(stdout, ''); + assert.strictEqual(code, 42); + }); + + it('should throw for a rejected TLA promise and ignore explicit exit code via --eval', async () => { + // Rejected TLA promise, --eval + const { code, stderr, stdout } = await spawnPromisified(execPath, [ ...commonArgs, 'process.exitCode = 42;await Promise.reject(new Error("Xyz"))', - ], - { encoding: 'utf8' }); - assert.deepStrictEqual([status, stdout], [1, '']); - assert.match(stderr, /Error: Xyz/); -} - -{ - // Unresolved TLA promise, module file - const { status, stdout, stderr } = child_process.spawnSync( - process.execPath, - ['--no-warnings', fixtures.path('es-modules/tla/unresolved.mjs')], - { encoding: 'utf8' }); - assert.deepStrictEqual([status, stdout, stderr], [13, '', '']); -} - -{ - // Rejected TLA promise, module file - const { status, stdout, stderr } = child_process.spawnSync( - process.execPath, - ['--no-warnings', fixtures.path('es-modules/tla/rejected.mjs')], - { encoding: 'utf8' }); - assert.deepStrictEqual([status, stdout], [1, '']); - assert.match(stderr, /Error: Xyz/); -} - -{ - // Unresolved TLA promise, module file - const { status, stdout, stderr } = child_process.spawnSync( - process.execPath, - ['--no-warnings', fixtures.path('es-modules/tla/unresolved-withexitcode.mjs')], - { encoding: 'utf8' }); - assert.deepStrictEqual([status, stdout, stderr], [42, '', '']); -} - -{ - // Rejected TLA promise, module file - const { status, stdout, stderr } = child_process.spawnSync( - process.execPath, - ['--no-warnings', fixtures.path('es-modules/tla/rejected-withexitcode.mjs')], - { encoding: 'utf8' }); - assert.deepStrictEqual([status, stdout], [1, '']); - assert.match(stderr, /Error: Xyz/); -} - -{ - // Calling process.exit() in .mjs should return status 0 - const { status, stdout, stderr } = child_process.spawnSync( - process.execPath, - ['--no-warnings', fixtures.path('es-modules/tla/process-exit.mjs')], - { encoding: 'utf8' }); - assert.deepStrictEqual([status, stdout, stderr], [0, '', '']); -} - -{ - // Calling process.exit() in worker thread shouldn't influence main thread - const { status, stdout, stderr } = child_process.spawnSync( - process.execPath, - ['--no-warnings', fixtures.path('es-modules/tla/unresolved-with-worker-process-exit.mjs')], - { encoding: 'utf8' }); - assert.deepStrictEqual([status, stdout, stderr], [13, '', '']); -} + ]); + + assert.match(stderr, /Error: Xyz/); + assert.strictEqual(stdout, ''); + assert.strictEqual(code, 1); + }); + + it('should exit for an unsettled TLA promise via stdin', async () => { + const { code, stderr, stdout } = await spawnPromisified(execPath, [ + '--no-warnings', + fixtures.path('es-modules/tla/unresolved.mjs'), + ]); + + assert.strictEqual(stderr, ''); + assert.strictEqual(stdout, ''); + assert.strictEqual(code, 13); + }); + + it('should throw for a rejected TLA promise via stdin', async () => { + const { code, stderr, stdout } = await spawnPromisified(execPath, [ + '--no-warnings', + fixtures.path('es-modules/tla/rejected.mjs'), + ]); + + assert.match(stderr, /Error: Xyz/); + assert.strictEqual(stdout, ''); + assert.strictEqual(code, 1); + }); + + it('should exit for an unsettled TLA promise and respect explicit exit code via stdin', async () => { + const { code, stderr, stdout } = await spawnPromisified(execPath, [ + '--no-warnings', + fixtures.path('es-modules/tla/unresolved-withexitcode.mjs'), + ]); + + assert.strictEqual(stderr, ''); + assert.strictEqual(stdout, ''); + assert.strictEqual(code, 42); + }); + + it('should throw for a rejected TLA promise and ignore explicit exit code via stdin', async () => { + const { code, stderr, stdout } = await spawnPromisified(execPath, [ + '--no-warnings', + fixtures.path('es-modules/tla/rejected-withexitcode.mjs'), + ]); + + assert.match(stderr, /Error: Xyz/); + assert.strictEqual(stdout, ''); + assert.strictEqual(code, 1); + }); + + it('should exit successfully when calling `process.exit()` in `.mjs` file', async () => { + const { code, stderr, stdout } = await spawnPromisified(execPath, [ + '--no-warnings', + fixtures.path('es-modules/tla/process-exit.mjs'), + ]); + + assert.strictEqual(stderr, ''); + assert.strictEqual(stdout, ''); + assert.strictEqual(code, 0); + }); + + it('should be unaffected by `process.exit()` in worker thread', async () => { + const { code, stderr, stdout } = await spawnPromisified(execPath, [ + '--no-warnings', + fixtures.path('es-modules/tla/unresolved-with-worker-process-exit.mjs'), + ]); + + assert.strictEqual(stderr, ''); + assert.strictEqual(stdout, ''); + assert.strictEqual(code, 13); + }); +}); diff --git a/test/es-module/test-esm-unknown-or-no-extension.js b/test/es-module/test-esm-unknown-or-no-extension.js index 40f840ad670cf3..3f0660e5aa9225 100644 --- a/test/es-module/test-esm-unknown-or-no-extension.js +++ b/test/es-module/test-esm-unknown-or-no-extension.js @@ -1,40 +1,36 @@ 'use strict'; -const common = require('../common'); -const fixtures = require('../common/fixtures'); -const { spawn } = require('child_process'); -const assert = require('assert'); +const { spawnPromisified } = require('../common'); +const fixtures = require('../common/fixtures.js'); +const assert = require('node:assert'); +const { execPath } = require('node:process'); +const { describe, it } = require('node:test'); + // In a "type": "module" package scope, files with unknown extensions or no // extensions should throw; both when used as a main entry point and also when // referenced via `import`. +describe('ESM: extensionless and unknown specifiers', { concurrency: true }, () => { + for ( + const fixturePath of [ + '/es-modules/package-type-module/noext-esm', + '/es-modules/package-type-module/imports-noext.mjs', + '/es-modules/package-type-module/extension.unknown', + '/es-modules/package-type-module/imports-unknownext.mjs', + ] + ) { + it('should throw', async () => { + const entry = fixtures.path(fixturePath); + const { code, signal, stderr, stdout } = await spawnPromisified(execPath, [entry]); -[ - '/es-modules/package-type-module/noext-esm', - '/es-modules/package-type-module/imports-noext.mjs', - '/es-modules/package-type-module/extension.unknown', - '/es-modules/package-type-module/imports-unknownext.mjs', -].forEach((fixturePath) => { - const entry = fixtures.path(fixturePath); - const child = spawn(process.execPath, [entry]); - let stdout = ''; - let stderr = ''; - child.stderr.setEncoding('utf8'); - child.stdout.setEncoding('utf8'); - child.stdout.on('data', (data) => { - stdout += data; - }); - child.stderr.on('data', (data) => { - stderr += data; - }); - child.on('close', common.mustCall((code, signal) => { - assert.strictEqual(code, 1); - assert.strictEqual(signal, null); - assert.strictEqual(stdout, ''); - assert.ok(stderr.includes('ERR_UNKNOWN_FILE_EXTENSION')); - if (fixturePath.includes('noext')) { - // Check for explanation to users - assert.ok(stderr.includes('extensionless')); - } - })); + assert.strictEqual(code, 1); + assert.strictEqual(signal, null); + assert.strictEqual(stdout, ''); + assert.ok(stderr.includes('ERR_UNKNOWN_FILE_EXTENSION')); + if (fixturePath.includes('noext')) { + // Check for explanation to users + assert.ok(stderr.includes('extensionless')); + } + }); + } }); diff --git a/test/es-module/test-esm-wasm.mjs b/test/es-module/test-esm-wasm.mjs index 01717c47714f6a..fac1d4b2837df0 100644 --- a/test/es-module/test-esm-wasm.mjs +++ b/test/es-module/test-esm-wasm.mjs @@ -1,37 +1,43 @@ -// Flags: --experimental-wasm-modules -import '../common/index.mjs'; -import { path } from '../common/fixtures.mjs'; -import { add, addImported } from '../fixtures/es-modules/simple.wasm'; -import { state } from '../fixtures/es-modules/wasm-dep.mjs'; -import { strictEqual, ok } from 'assert'; -import { spawn } from 'child_process'; +import { spawnPromisified } from '../common/index.mjs'; +import * as fixtures from '../common/fixtures.mjs'; +import { strictEqual, match } from 'node:assert'; +import { execPath } from 'node:process'; +import { describe, it } from 'node:test'; -strictEqual(state, 'WASM Start Executed'); -strictEqual(add(10, 20), 30); +describe('ESM: WASM modules', { concurrency: true }, () => { + it('should load exports', async () => { + const { code, stderr, stdout } = await spawnPromisified(execPath, [ + '--no-warnings', + '--experimental-wasm-modules', + '--input-type=module', + '--eval', + [ + 'import { strictEqual, match } from "node:assert";', + `import { add, addImported } from ${JSON.stringify(fixtures.fileURL('es-modules/simple.wasm'))};`, + `import { state } from ${JSON.stringify(fixtures.fileURL('es-modules/wasm-dep.mjs'))};`, + 'strictEqual(state, "WASM Start Executed");', + 'strictEqual(add(10, 20), 30);', + 'strictEqual(addImported(0), 42);', + 'strictEqual(state, "WASM JS Function Executed");', + 'strictEqual(addImported(1), 43);', + ].join('\n'), + ]); -strictEqual(addImported(0), 42); + strictEqual(stderr, ''); + strictEqual(stdout, ''); + strictEqual(code, 0); + }); -strictEqual(state, 'WASM JS Function Executed'); + it('should emit experimental warning', async () => { + const { code, signal, stderr } = await spawnPromisified(execPath, [ + '--experimental-wasm-modules', + fixtures.path('es-modules/wasm-modules.mjs'), + ]); -strictEqual(addImported(1), 43); - -// Test warning message -const child = spawn(process.execPath, [ - '--experimental-wasm-modules', - path('/es-modules/wasm-modules.mjs'), -]); - -let stderr = ''; -child.stderr.setEncoding('utf8'); -child.stderr.on('data', (data) => { - stderr += data; -}); -child.on('close', (code, signal) => { - strictEqual(code, 0); - strictEqual(signal, null); - ok(stderr.toString().includes( - 'ExperimentalWarning: Importing WebAssembly modules is ' + - 'an experimental feature. This feature could change at any time' - )); + strictEqual(code, 0); + strictEqual(signal, null); + match(stderr, /ExperimentalWarning/); + match(stderr, /WebAssembly/); + }); }); diff --git a/test/es-module/test-http-imports-cli.mjs b/test/es-module/test-http-imports-cli.mjs index 67cefd69ddd889..7deb31a288c7f7 100644 --- a/test/es-module/test-http-imports-cli.mjs +++ b/test/es-module/test-http-imports-cli.mjs @@ -1,48 +1,48 @@ -import { mustCall } from '../common/index.mjs'; -import { match, notStrictEqual } from 'assert'; -import { spawn } from 'child_process'; -import { execPath } from 'process'; - -{ - const child = spawn(execPath, [ - '--experimental-network-imports', - '--input-type=module', - '-e', - 'import "http://example.com"', - ]); - - let stderr = ''; - child.stderr.setEncoding('utf8'); - child.stderr.on('data', (data) => { - stderr += data; - }); - child.on('close', mustCall((code, _signal) => { +import { mustCall, spawnPromisified } from '../common/index.mjs'; +import { ok, match, notStrictEqual } from 'node:assert'; +import { spawn as spawnAsync } from 'node:child_process'; +import { execPath } from 'node:process'; +import { describe, it } from 'node:test'; + + +describe('ESM: http import via CLI', { concurrency: true }, () => { + const disallowedSpecifier = 'http://example.com'; + + it('should throw disallowed error for insecure protocol', async () => { + const { code, stderr } = await spawnPromisified(execPath, [ + '--experimental-network-imports', + '--input-type=module', + '--eval', + `import ${JSON.stringify(disallowedSpecifier)}`, + ]); + notStrictEqual(code, 0); // [ERR_NETWORK_IMPORT_DISALLOWED]: import of 'http://example.com/' by // …/[eval1] is not supported: http can only be used to load local // resources (use https instead). - match(stderr, /[ERR_NETWORK_IMPORT_DISALLOWED]/); - })); -} -{ - const child = spawn(execPath, [ - '--experimental-network-imports', - '--input-type=module', - ]); - child.stdin.end('import "http://example.com"'); - - let stderr = ''; - child.stderr.setEncoding('utf8'); - child.stderr.on('data', (data) => { - stderr += data; + match(stderr, /ERR_NETWORK_IMPORT_DISALLOWED/); + ok(stderr.includes(disallowedSpecifier)); }); - child.on('close', mustCall((code, _signal) => { - notStrictEqual(code, 0); - // [ERR_NETWORK_IMPORT_DISALLOWED]: import of 'http://example.com/' by - // …/[stdin] is not supported: http can only be used to load local - // resources (use https instead). - match(stderr, /[ERR_NETWORK_IMPORT_DISALLOWED]/); - })); -} + it('should throw disallowed error for insecure protocol in REPL', () => { + const child = spawnAsync(execPath, [ + '--experimental-network-imports', + '--input-type=module', + ]); + child.stdin.end(`import ${JSON.stringify(disallowedSpecifier)}`); + + let stderr = ''; + child.stderr.setEncoding('utf8'); + child.stderr.on('data', (data) => stderr += data); + child.on('close', mustCall((code, _signal) => { + notStrictEqual(code, 0); + + // [ERR_NETWORK_IMPORT_DISALLOWED]: import of 'http://example.com/' by + // …/[stdin] is not supported: http can only be used to load local + // resources (use https instead). + match(stderr, /\[ERR_NETWORK_IMPORT_DISALLOWED\]/); + ok(stderr.includes(disallowedSpecifier)); + })); + }); +}); diff --git a/test/fixtures/es-module-loaders/assertionless-json-import.mjs b/test/fixtures/es-module-loaders/assertionless-json-import.mjs index c5c2fadf28fb58..07656d4ec40fa3 100644 --- a/test/fixtures/es-module-loaders/assertionless-json-import.mjs +++ b/test/fixtures/es-module-loaders/assertionless-json-import.mjs @@ -4,14 +4,14 @@ const JSON_URL_PATTERN = /\.json(\?[^#]*)?(#.*)?$/; export function resolve(url, context, next) { // Mutation from resolve hook should be discarded. context.importAssertions.type = 'whatever'; - return next(url, context); + return next(url); } export function load(url, context, next) { - if (context.importAssertions.type == null && + if (context.importAssertions.type == null && (DATA_URL_PATTERN.test(url) || JSON_URL_PATTERN.test(url))) { const { importAssertions } = context; importAssertions.type = 'json'; } - return next(url, context); + return next(url); } 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 e303ec196f6c6d..8c317c1b7ce31e 100644 --- a/test/fixtures/es-module-loaders/builtin-named-exports-loader.mjs +++ b/test/fixtures/es-module-loaders/builtin-named-exports-loader.mjs @@ -35,7 +35,7 @@ export function load(url, context, next) { format: 'module', }; } - return next(url, context); + return next(url); } function generateBuiltinModule(builtinName) { diff --git a/test/fixtures/es-module-loaders/example-loader.mjs b/test/fixtures/es-module-loaders/example-loader.mjs index f87054c8b70502..77d44d55f91523 100644 --- a/test/fixtures/es-module-loaders/example-loader.mjs +++ b/test/fixtures/es-module-loaders/example-loader.mjs @@ -8,7 +8,7 @@ const JS_EXTENSIONS = new Set(['.js', '.mjs']); const baseURL = new URL('file://'); baseURL.pathname = process.cwd() + '/'; -export function resolve(specifier, { parentURL = baseURL }, defaultResolve) { +export function resolve(specifier, { parentURL = baseURL }, next) { if (builtinModules.includes(specifier)) { return { shortCircuit: true, @@ -17,7 +17,7 @@ export function resolve(specifier, { parentURL = baseURL }, defaultResolve) { } if (/^\.{1,2}[/]/.test(specifier) !== true && !specifier.startsWith('file:')) { // For node_modules support: - // return defaultResolve(specifier, {parentURL}, defaultResolve); + // return next(specifier); throw new Error( `imports must be URLs or begin with './', or '../'; '${specifier}' does not`); } diff --git a/test/fixtures/es-module-loaders/hook-resolve-type.mjs b/test/fixtures/es-module-loaders/hook-resolve-type.mjs index 5068d6265c57b2..b1f5606c0e4a0a 100644 --- a/test/fixtures/es-module-loaders/hook-resolve-type.mjs +++ b/test/fixtures/es-module-loaders/hook-resolve-type.mjs @@ -3,7 +3,7 @@ let importedCJS = 0; global.getModuleTypeStats = () => { return {importedESM, importedCJS} }; export async function load(url, context, next) { - return next(url, context, next); + return next(url); } export async function resolve(specifier, context, next) { diff --git a/test/fixtures/es-module-loaders/hooks-custom.mjs b/test/fixtures/es-module-loaders/hooks-custom.mjs index 4c4014db01ef3f..65dba3535c2d95 100644 --- a/test/fixtures/es-module-loaders/hooks-custom.mjs +++ b/test/fixtures/es-module-loaders/hooks-custom.mjs @@ -56,10 +56,10 @@ export function load(url, context, next) { source: `export const message = 'Woohoo!'.toUpperCase();`, }; - return next(url, context, next); + return next(url); } -export function resolve(specifier, context, next) { +export function resolve(specifier, { importAssertions }, next) { let format = ''; if (specifier === 'esmHook/format.false') format = false; @@ -70,8 +70,8 @@ export function resolve(specifier, context, next) { format, shortCircuit: true, url: pathToFileURL(specifier).href, - importAssertions: context.importAssertions, + importAssertions, }; - return next(specifier, context, next); + return next(specifier); } diff --git a/test/fixtures/es-module-loaders/hooks-obsolete.mjs b/test/fixtures/es-module-loaders/hooks-obsolete.mjs index 9d12251923d7e9..bb10ef8ef4b29a 100644 --- a/test/fixtures/es-module-loaders/hooks-obsolete.mjs +++ b/test/fixtures/es-module-loaders/hooks-obsolete.mjs @@ -4,19 +4,19 @@ export function getSource() {} export function transformSource() {} -export function load(url, context, next) { - if (url === 'whatever') return { - format: 'module', - source: '', +export function resolve(specifier, context, next) { + if (specifier === 'whatever') return { + url: specifier, }; - return next(url, context, next); + return next(specifier); } -export function resolve(specifier, context, next) { - if (specifier === 'whatever') return { - url: specifier, +export function load(url, context, next) { + if (url === 'whatever') return { + format: 'module', + source: '', }; - return next(specifier, context, next); + return next(url); } diff --git a/test/fixtures/es-module-loaders/http-loader.mjs b/test/fixtures/es-module-loaders/http-loader.mjs index f0add5d5b419f8..8096dd9bb73a4c 100644 --- a/test/fixtures/es-module-loaders/http-loader.mjs +++ b/test/fixtures/es-module-loaders/http-loader.mjs @@ -15,7 +15,7 @@ export function resolve(specifier, context, nextResolve) { }; } - return nextResolve(specifier, context); + return nextResolve(specifier); } export function load(url, context, nextLoad) { @@ -36,5 +36,5 @@ export function load(url, context, nextLoad) { }); } - return nextLoad(url, context); + return nextLoad(url); } diff --git a/test/fixtures/es-module-loaders/loader-get-format.mjs b/test/fixtures/es-module-loaders/loader-get-format.mjs deleted file mode 100644 index 7ade70fca0ebe6..00000000000000 --- a/test/fixtures/es-module-loaders/loader-get-format.mjs +++ /dev/null @@ -1,10 +0,0 @@ -export async function getFormat(url, context, defaultGetFormat) { - try { - if (new URL(url).pathname.endsWith('.unknown')) { - return { - format: 'module' - }; - } - } catch {} - return defaultGetFormat(url, context, defaultGetFormat); -} diff --git a/test/fixtures/es-module-loaders/loader-invalid-format.mjs b/test/fixtures/es-module-loaders/loader-invalid-format.mjs index 438d50dacba433..e7dd06c108ba1d 100644 --- a/test/fixtures/es-module-loaders/loader-invalid-format.mjs +++ b/test/fixtures/es-module-loaders/loader-invalid-format.mjs @@ -1,11 +1,11 @@ -export async function resolve(specifier, { parentURL, importAssertions }, defaultResolve) { +export async function resolve(specifier, { parentURL, importAssertions }, next) { if (parentURL && specifier === '../fixtures/es-modules/test-esm-ok.mjs') { return { shortCircuit: true, url: 'file:///asdf', }; } - return defaultResolve(specifier, {parentURL, importAssertions}, defaultResolve); + return next(specifier); } export async function load(url, context, next) { @@ -16,5 +16,5 @@ export async function load(url, context, next) { source: '', } } - return next(url, context, next); + return next(url); } diff --git a/test/fixtures/es-module-loaders/loader-invalid-url.mjs b/test/fixtures/es-module-loaders/loader-invalid-url.mjs index 87d1a6a564b461..a54f39521f29ac 100644 --- a/test/fixtures/es-module-loaders/loader-invalid-url.mjs +++ b/test/fixtures/es-module-loaders/loader-invalid-url.mjs @@ -1,4 +1,4 @@ -export async function resolve(specifier, { parentURL, importAssertions }, defaultResolve) { +export async function resolve(specifier, { parentURL, importAssertions }, next) { if (parentURL && specifier === '../fixtures/es-modules/test-esm-ok.mjs') { return { shortCircuit: true, @@ -6,5 +6,5 @@ export async function resolve(specifier, { parentURL, importAssertions }, defaul importAssertions, }; } - return defaultResolve(specifier, {parentURL, importAssertions}, defaultResolve); + return next(specifier); } 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 index 4f53b695327dd1..c6a4c7504d43e5 100644 --- a/test/fixtures/es-module-loaders/loader-load-bad-next-url.mjs +++ b/test/fixtures/es-module-loaders/loader-load-bad-next-url.mjs @@ -1,3 +1,3 @@ export async function load(url, context, next) { - return next([], context); + return next([]); } 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 index f98b091c8b9ff5..1028e093e46819 100644 --- a/test/fixtures/es-module-loaders/loader-load-impersonating-next-url.mjs +++ b/test/fixtures/es-module-loaders/loader-load-impersonating-next-url.mjs @@ -1,3 +1,3 @@ export async function load(url, context, next) { - return next('not/a/url', context); + return next('not/a/url'); } diff --git a/test/fixtures/es-module-loaders/loader-load-next-modified.mjs b/test/fixtures/es-module-loaders/loader-load-next-modified.mjs index 1f2382467f7122..401b52971311a7 100644 --- a/test/fixtures/es-module-loaders/loader-load-next-modified.mjs +++ b/test/fixtures/es-module-loaders/loader-load-next-modified.mjs @@ -2,7 +2,7 @@ export async function load(url, context, next) { const { format, source, - } = await next(url, context); + } = await next(url); return { format, diff --git a/test/fixtures/es-module-loaders/loader-load-passthru.mjs b/test/fixtures/es-module-loaders/loader-load-passthru.mjs index 8cfbcb6a3a5d0b..0de06142007562 100644 --- a/test/fixtures/es-module-loaders/loader-load-passthru.mjs +++ b/test/fixtures/es-module-loaders/loader-load-passthru.mjs @@ -1,4 +1,4 @@ export async function load(url, context, next) { console.log('load passthru'); // This log is deliberate - return next(url, context); + return next(url); } 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 index a23785d3d956db..66c941754f90cc 100644 --- a/test/fixtures/es-module-loaders/loader-resolve-bad-next-specifier.mjs +++ b/test/fixtures/es-module-loaders/loader-resolve-bad-next-specifier.mjs @@ -1,3 +1,3 @@ export async function resolve(specifier, context, next) { - return next([], context); + return next([]); } diff --git a/test/fixtures/es-module-loaders/loader-resolve-foo.mjs b/test/fixtures/es-module-loaders/loader-resolve-foo.mjs index 595385e12a0cf7..7d23d6c49088c9 100644 --- a/test/fixtures/es-module-loaders/loader-resolve-foo.mjs +++ b/test/fixtures/es-module-loaders/loader-resolve-foo.mjs @@ -1,4 +1,4 @@ export async function resolve(specifier, context, next) { console.log('resolve foo'); // This log is deliberate - return next('file:///foo.mjs', context); + return next('file:///foo.mjs'); } diff --git a/test/fixtures/es-module-loaders/loader-resolve-multiple-next-calls.mjs b/test/fixtures/es-module-loaders/loader-resolve-multiple-next-calls.mjs index 88d333c2404a3c..91dbec251edeba 100644 --- a/test/fixtures/es-module-loaders/loader-resolve-multiple-next-calls.mjs +++ b/test/fixtures/es-module-loaders/loader-resolve-multiple-next-calls.mjs @@ -1,6 +1,6 @@ export async function resolve(specifier, context, next) { - const { url: first } = await next(specifier, context); - const { url: second } = await next(specifier, context); + const { url: first } = await next(specifier); + const { url: second } = await next(specifier); return { format: 'module', diff --git a/test/fixtures/es-module-loaders/loader-resolve-passthru.mjs b/test/fixtures/es-module-loaders/loader-resolve-passthru.mjs index 1a373bab90ba57..3db5b21bb98793 100644 --- a/test/fixtures/es-module-loaders/loader-resolve-passthru.mjs +++ b/test/fixtures/es-module-loaders/loader-resolve-passthru.mjs @@ -1,4 +1,4 @@ export async function resolve(specifier, context, next) { console.log('resolve passthru'); // This log is deliberate - return next(specifier, context); + return next(specifier); } diff --git a/test/fixtures/es-module-loaders/loader-shared-dep.mjs b/test/fixtures/es-module-loaders/loader-shared-dep.mjs index 387575794c00dc..d41c1ae403399e 100644 --- a/test/fixtures/es-module-loaders/loader-shared-dep.mjs +++ b/test/fixtures/es-module-loaders/loader-shared-dep.mjs @@ -5,7 +5,7 @@ import { createRequire } from '../../common/index.mjs'; const require = createRequire(import.meta.url); const dep = require('./loader-dep.js'); -export function resolve(specifier, { parentURL, importAssertions }, defaultResolve) { +export function resolve(specifier, context, next) { assert.strictEqual(dep.format, 'module'); - return defaultResolve(specifier, { parentURL, importAssertions }, defaultResolve); + return next(specifier); } diff --git a/test/fixtures/es-module-loaders/loader-unknown-builtin-module.mjs b/test/fixtures/es-module-loaders/loader-unknown-builtin-module.mjs index 1063f8dfd65f2f..65e1adf909d0bc 100644 --- a/test/fixtures/es-module-loaders/loader-unknown-builtin-module.mjs +++ b/test/fixtures/es-module-loaders/loader-unknown-builtin-module.mjs @@ -3,5 +3,5 @@ export function resolve(specifier, context, next) { url: 'node:unknown-builtin-module' }; - return next(specifier, context, next); + return next(specifier); } diff --git a/test/fixtures/es-module-loaders/missing-dynamic-instantiate-hook.mjs b/test/fixtures/es-module-loaders/missing-dynamic-instantiate-hook.mjs index ec15eb0bb8fc24..5d61d81bc31ed5 100644 --- a/test/fixtures/es-module-loaders/missing-dynamic-instantiate-hook.mjs +++ b/test/fixtures/es-module-loaders/missing-dynamic-instantiate-hook.mjs @@ -1,10 +1,10 @@ -export function resolve(specifier, { parentURL }, defaultResolve) { +export function resolve(specifier, context, next) { if (specifier === 'test') { return { url: 'file://' }; } - return defaultResolve(specifier, {parentURL}, defaultResolve); + return next(specifier); } export function getFormat(url, context, defaultGetFormat) { diff --git a/test/fixtures/es-module-loaders/not-found-assert-loader.mjs b/test/fixtures/es-module-loaders/not-found-assert-loader.mjs index 5213ddedb34e8d..ea4c73724298db 100644 --- a/test/fixtures/es-module-loaders/not-found-assert-loader.mjs +++ b/test/fixtures/es-module-loaders/not-found-assert-loader.mjs @@ -1,15 +1,15 @@ -import assert from 'assert'; +import assert from 'node:assert'; // a loader that asserts that the defaultResolve will throw "not found" // (skipping the top-level main of course) let mainLoad = true; -export async function resolve(specifier, { parentURL, importAssertions }, defaultResolve) { +export async function resolve(specifier, { importAssertions }, next) { if (mainLoad) { mainLoad = false; - return defaultResolve(specifier, {parentURL, importAssertions}, defaultResolve); + return next(specifier); } try { - await defaultResolve(specifier, {parentURL, importAssertions}, defaultResolve); + await next(specifier); } catch (e) { assert.strictEqual(e.code, 'ERR_MODULE_NOT_FOUND'); diff --git a/test/fixtures/es-module-loaders/string-sources.mjs b/test/fixtures/es-module-loaders/string-sources.mjs index 1fc2b7a8d6f7e3..396d17cb17a75c 100644 --- a/test/fixtures/es-module-loaders/string-sources.mjs +++ b/test/fixtures/es-module-loaders/string-sources.mjs @@ -28,7 +28,7 @@ export function resolve(specifier, context, next) { url: specifier, }; } - return next(specifier, context); + return next(specifier); } export function load(href, context, next) { @@ -39,5 +39,5 @@ export function load(href, context, next) { source: SOURCES[href], }; } - return next(href, context); + return next(href); }