mirror of
https://github.com/zebrajr/node.git
synced 2025-12-06 12:20:27 +01:00
test: refactor ESM tests to improve performance
PR-URL: https://github.com/nodejs/node/pull/43784 Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
This commit is contained in:
parent
e5add6659d
commit
447635b440
|
|
@ -336,7 +336,7 @@ class ESMLoader {
|
||||||
* A list of exports from user-defined loaders (as returned by
|
* A list of exports from user-defined loaders (as returned by
|
||||||
* ESMLoader.import()).
|
* ESMLoader.import()).
|
||||||
*/
|
*/
|
||||||
async addCustomLoaders(
|
addCustomLoaders(
|
||||||
customLoaders = [],
|
customLoaders = [],
|
||||||
) {
|
) {
|
||||||
for (let i = 0; i < customLoaders.length; i++) {
|
for (let i = 0; i < customLoaders.length; i++) {
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@
|
||||||
const process = global.process; // Some tests tamper with the process global.
|
const process = global.process; // Some tests tamper with the process global.
|
||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const { exec, execSync, spawnSync } = require('child_process');
|
const { exec, execSync, spawn, spawnSync } = require('child_process');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
// Do not require 'os' until needed so that test-os-checked-function can
|
// 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.
|
// 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 = {
|
const common = {
|
||||||
allowGlobals,
|
allowGlobals,
|
||||||
buildType,
|
buildType,
|
||||||
|
|
@ -891,6 +921,7 @@ const common = {
|
||||||
skipIfEslintMissing,
|
skipIfEslintMissing,
|
||||||
skipIfInspectorDisabled,
|
skipIfInspectorDisabled,
|
||||||
skipIfWorker,
|
skipIfWorker,
|
||||||
|
spawnPromisified,
|
||||||
|
|
||||||
get enoughTestMem() {
|
get enoughTestMem() {
|
||||||
return require('os').totalmem() > 0x70000000; /* 1.75 Gb */
|
return require('os').totalmem() > 0x70000000; /* 1.75 Gb */
|
||||||
|
|
|
||||||
|
|
@ -23,53 +23,7 @@ const {
|
||||||
hasCrypto,
|
hasCrypto,
|
||||||
hasIPv6,
|
hasIPv6,
|
||||||
childShouldThrowAndAbort,
|
childShouldThrowAndAbort,
|
||||||
createZeroFilledFile,
|
checkoutEOL,
|
||||||
platformTimeout,
|
|
||||||
allowGlobals,
|
|
||||||
mustCall,
|
|
||||||
mustCallAtLeast,
|
|
||||||
mustSucceed,
|
|
||||||
hasMultiLocalhost,
|
|
||||||
skipIfDumbTerminal,
|
|
||||||
skipIfEslintMissing,
|
|
||||||
canCreateSymLink,
|
|
||||||
getCallSite,
|
|
||||||
mustNotCall,
|
|
||||||
mustNotMutateObjectDeep,
|
|
||||||
printSkipMessage,
|
|
||||||
skip,
|
|
||||||
nodeProcessAborted,
|
|
||||||
isAlive,
|
|
||||||
expectWarning,
|
|
||||||
expectsError,
|
|
||||||
skipIfInspectorDisabled,
|
|
||||||
skipIf32Bits,
|
|
||||||
getArrayBufferViews,
|
|
||||||
getBufferSources,
|
|
||||||
getTTYfd,
|
|
||||||
runWithInvalidFD
|
|
||||||
} = common;
|
|
||||||
|
|
||||||
export {
|
|
||||||
isMainThread,
|
|
||||||
isWindows,
|
|
||||||
isAIX,
|
|
||||||
isIBMi,
|
|
||||||
isLinuxPPCBE,
|
|
||||||
isSunOS,
|
|
||||||
isDumbTerminal,
|
|
||||||
isFreeBSD,
|
|
||||||
isOpenBSD,
|
|
||||||
isLinux,
|
|
||||||
isOSX,
|
|
||||||
enoughTestMem,
|
|
||||||
buildType,
|
|
||||||
localIPv6Hosts,
|
|
||||||
opensslCli,
|
|
||||||
PIPE,
|
|
||||||
hasCrypto,
|
|
||||||
hasIPv6,
|
|
||||||
childShouldThrowAndAbort,
|
|
||||||
createZeroFilledFile,
|
createZeroFilledFile,
|
||||||
platformTimeout,
|
platformTimeout,
|
||||||
allowGlobals,
|
allowGlobals,
|
||||||
|
|
@ -95,5 +49,55 @@ export {
|
||||||
getBufferSources,
|
getBufferSources,
|
||||||
getTTYfd,
|
getTTYfd,
|
||||||
runWithInvalidFD,
|
runWithInvalidFD,
|
||||||
createRequire
|
spawnPromisified,
|
||||||
|
} = common;
|
||||||
|
|
||||||
|
export {
|
||||||
|
isMainThread,
|
||||||
|
isWindows,
|
||||||
|
isAIX,
|
||||||
|
isIBMi,
|
||||||
|
isLinuxPPCBE,
|
||||||
|
isSunOS,
|
||||||
|
isDumbTerminal,
|
||||||
|
isFreeBSD,
|
||||||
|
isOpenBSD,
|
||||||
|
isLinux,
|
||||||
|
isOSX,
|
||||||
|
enoughTestMem,
|
||||||
|
buildType,
|
||||||
|
localIPv6Hosts,
|
||||||
|
opensslCli,
|
||||||
|
PIPE,
|
||||||
|
hasCrypto,
|
||||||
|
hasIPv6,
|
||||||
|
childShouldThrowAndAbort,
|
||||||
|
checkoutEOL,
|
||||||
|
createZeroFilledFile,
|
||||||
|
platformTimeout,
|
||||||
|
allowGlobals,
|
||||||
|
mustCall,
|
||||||
|
mustCallAtLeast,
|
||||||
|
mustSucceed,
|
||||||
|
hasMultiLocalhost,
|
||||||
|
skipIfDumbTerminal,
|
||||||
|
skipIfEslintMissing,
|
||||||
|
canCreateSymLink,
|
||||||
|
getCallSite,
|
||||||
|
mustNotCall,
|
||||||
|
mustNotMutateObjectDeep,
|
||||||
|
printSkipMessage,
|
||||||
|
skip,
|
||||||
|
nodeProcessAborted,
|
||||||
|
isAlive,
|
||||||
|
expectWarning,
|
||||||
|
expectsError,
|
||||||
|
skipIfInspectorDisabled,
|
||||||
|
skipIf32Bits,
|
||||||
|
getArrayBufferViews,
|
||||||
|
getBufferSources,
|
||||||
|
getTTYfd,
|
||||||
|
runWithInvalidFD,
|
||||||
|
createRequire,
|
||||||
|
spawnPromisified,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const common = require('../common');
|
const { spawnPromisified } = require('../common');
|
||||||
const fixtures = require('../common/fixtures');
|
const fixtures = require('../common/fixtures.js');
|
||||||
const { spawn } = require('child_process');
|
const assert = require('node:assert');
|
||||||
const assert = require('assert');
|
const path = require('node:path');
|
||||||
const path = require('path');
|
const { execPath } = require('node:process');
|
||||||
|
const { describe, it } = require('node:test');
|
||||||
|
|
||||||
|
|
||||||
const requiringCjsAsEsm = path.resolve(fixtures.path('/es-modules/cjs-esm.js'));
|
const requiringCjsAsEsm = path.resolve(fixtures.path('/es-modules/cjs-esm.js'));
|
||||||
const requiringEsm = path.resolve(fixtures.path('/es-modules/cjs-esm-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')
|
fixtures.path('/es-modules/package-type-module/package.json')
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
|
||||||
const required = path.resolve(
|
describe('CJS ↔︎ ESM interop warnings', { concurrency: true }, () => {
|
||||||
fixtures.path('/es-modules/package-type-module/cjs.js')
|
|
||||||
);
|
it(async () => {
|
||||||
const basename = 'cjs.js';
|
const required = path.resolve(
|
||||||
const child = spawn(process.execPath, [requiringCjsAsEsm]);
|
fixtures.path('/es-modules/package-type-module/cjs.js')
|
||||||
let stderr = '';
|
);
|
||||||
child.stderr.setEncoding('utf8');
|
const basename = 'cjs.js';
|
||||||
child.stderr.on('data', (data) => {
|
const { code, signal, stderr } = await spawnPromisified(execPath, [requiringCjsAsEsm]);
|
||||||
stderr += data;
|
|
||||||
});
|
assert.ok(
|
||||||
child.on('close', common.mustCall((code, signal) => {
|
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(code, 1);
|
||||||
assert.strictEqual(signal, null);
|
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'));
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
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) => {
|
|
||||||
|
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'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
assert.strictEqual(code, 1);
|
assert.strictEqual(code, 1);
|
||||||
assert.strictEqual(signal, null);
|
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'));
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,20 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const common = require('../common');
|
const { spawnPromisified } = require('../common');
|
||||||
const fixtures = require('../common/fixtures');
|
const fixtures = require('../common/fixtures.js');
|
||||||
const { spawn } = require('child_process');
|
const assert = require('node:assert');
|
||||||
const assert = require('assert');
|
const { execPath } = require('node:process');
|
||||||
|
const { describe, it } = require('node:test');
|
||||||
|
|
||||||
|
|
||||||
const entry = fixtures.path('/es-modules/builtin-imports-case.mjs');
|
const entry = fixtures.path('/es-modules/builtin-imports-case.mjs');
|
||||||
|
|
||||||
const child = spawn(process.execPath, [entry]);
|
describe('ESM: importing builtins & CJS', () => {
|
||||||
child.stderr.setEncoding('utf8');
|
it('should work', async () => {
|
||||||
let stdout = '';
|
const { code, signal, stdout } = await spawnPromisified(execPath, [entry]);
|
||||||
child.stdout.setEncoding('utf8');
|
|
||||||
child.stdout.on('data', (data) => {
|
assert.strictEqual(code, 0);
|
||||||
stdout += data;
|
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');
|
|
||||||
}));
|
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,29 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const common = require('../common');
|
const { spawnPromisified } = require('../common');
|
||||||
const fixtures = require('../common/fixtures');
|
const fixtures = require('../common/fixtures.js');
|
||||||
const { spawn } = require('child_process');
|
const assert = require('node:assert');
|
||||||
const assert = require('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]);
|
describe('ESM: importing CJS', { concurrency: true }, () => {
|
||||||
child.stderr.setEncoding('utf8');
|
it('should support valid CJS exports', async () => {
|
||||||
let stdout = '';
|
const validEntry = fixtures.path('/es-modules/cjs-exports.mjs');
|
||||||
child.stdout.setEncoding('utf8');
|
const { code, signal, stdout } = await spawnPromisified(execPath, [validEntry]);
|
||||||
child.stdout.on('data', (data) => {
|
|
||||||
stdout += data;
|
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]);
|
||||||
|
|
||||||
|
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, 0);
|
|
||||||
assert.strictEqual(signal, null);
|
|
||||||
assert.strictEqual(stdout, 'ok\n');
|
|
||||||
}));
|
|
||||||
|
|
||||||
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;
|
|
||||||
});
|
|
||||||
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\''));
|
|
||||||
}));
|
|
||||||
|
|
|
||||||
|
|
@ -1,163 +1,96 @@
|
||||||
import { mustCall } from '../common/index.mjs';
|
import { spawnPromisified } from '../common/index.mjs';
|
||||||
import assert from 'assert';
|
import * as fixtures from '../common/fixtures.mjs';
|
||||||
import fixtures from '../common/fixtures.js';
|
import assert from 'node:assert';
|
||||||
import { spawn } from 'child_process';
|
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
|
// Expect note to be included in the error output
|
||||||
const expectedNote = 'To load an ES module, ' +
|
const expectedNote = 'To load an ES module, ' +
|
||||||
'set "type": "module" in the package.json ' +
|
'set "type": "module" in the package.json ' +
|
||||||
'or use the .mjs extension.';
|
'or use the .mjs extension.';
|
||||||
|
|
||||||
const expectedCode = 1;
|
const mustIncludeMessage = {
|
||||||
|
getMessage: () => (stderr) => `${expectedNote} not found in ${stderr}`,
|
||||||
|
includeNote: true,
|
||||||
|
};
|
||||||
|
const mustNotIncludeMessage = {
|
||||||
|
getMessage: () => (stderr) => `${expectedNote} must not be included in ${stderr}`,
|
||||||
|
includeNote: false,
|
||||||
|
};
|
||||||
|
|
||||||
const pExport1 = spawn(process.execPath, [Export1]);
|
describe('ESM: Errors for unexpected exports', { concurrency: true }, () => {
|
||||||
let pExport1Stderr = '';
|
for (
|
||||||
pExport1.stderr.setEncoding('utf8');
|
const { errorNeedle, filePath, getMessage, includeNote }
|
||||||
pExport1.stderr.on('data', (data) => {
|
of [
|
||||||
pExport1Stderr += data;
|
{
|
||||||
|
// 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)}`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
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;
|
|
||||||
});
|
|
||||||
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}`);
|
|
||||||
}));
|
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,20 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const common = require('../common');
|
const { spawnPromisified } = require('../common');
|
||||||
const fixtures = require('../common/fixtures');
|
const fixtures = require('../common/fixtures.js');
|
||||||
const { spawn } = require('child_process');
|
const assert = require('node:assert');
|
||||||
const assert = require('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]);
|
describe('ESM: importing CJS', () => {
|
||||||
child.stderr.setEncoding('utf8');
|
it('should work', async () => {
|
||||||
let stdout = '';
|
const { code, signal, stdout } = await spawnPromisified(execPath, [
|
||||||
child.stdout.setEncoding('utf8');
|
fixtures.path('/es-modules/cjs.js'),
|
||||||
child.stdout.on('data', (data) => {
|
]);
|
||||||
stdout += data;
|
|
||||||
|
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');
|
|
||||||
}));
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,18 @@
|
||||||
'use strict';
|
'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 { spawnPromisified } = require('../common');
|
||||||
const child = spawn(process.execPath, [native]);
|
const fixtures = require('../common/fixtures.js');
|
||||||
child.on('exit', (code) => {
|
const assert = require('node:assert');
|
||||||
assert.strictEqual(code, 1);
|
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);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,55 +1,48 @@
|
||||||
import { mustCall } from '../common/index.mjs';
|
import { spawnPromisified } from '../common/index.mjs';
|
||||||
import { fileURL } from '../common/fixtures.mjs';
|
import { fileURL } from '../common/fixtures.mjs';
|
||||||
import { doesNotMatch, match, strictEqual } from 'assert';
|
import { doesNotMatch, match, strictEqual } from 'node:assert';
|
||||||
import { spawn } from 'child_process';
|
import { execPath } from 'node:process';
|
||||||
import { execPath } from '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 = '';
|
describe('ESM: warn for obsolete hooks provided', { concurrency: true }, () => {
|
||||||
child.stderr.setEncoding('utf8');
|
it('should not print warnings when no experimental features are enabled or used', async () => {
|
||||||
child.stderr.on('data', (data) => { stderr += data; });
|
const { code, signal, stderr } = await spawnPromisified(execPath, [
|
||||||
child.on('close', mustCall((code, signal) => {
|
'--input-type=module',
|
||||||
strictEqual(code, 0);
|
'--eval',
|
||||||
strictEqual(signal, null);
|
`import ${JSON.stringify(fileURL('es-module-loaders', 'module-named-exports.mjs'))}`,
|
||||||
|
]);
|
||||||
|
|
||||||
doesNotMatch(
|
doesNotMatch(
|
||||||
stderr,
|
stderr,
|
||||||
/ExperimentalWarning/,
|
/ExperimentalWarning/,
|
||||||
new Error('No experimental warning(s) should be emitted when no experimental feature is enabled')
|
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(code, 0);
|
||||||
strictEqual(signal, null);
|
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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,48 @@
|
||||||
import { mustCall } from '../common/index.mjs';
|
import { spawnPromisified } from '../common/index.mjs';
|
||||||
import { path } from '../common/fixtures.mjs';
|
import * as fixtures from '../common/fixtures.mjs';
|
||||||
import { match, notStrictEqual } from 'assert';
|
import assert from 'node:assert';
|
||||||
import { spawn } from 'child_process';
|
import { execPath } from 'node:process';
|
||||||
import { execPath } from '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 {
|
const importStatementMultiline = `import {
|
||||||
foo,
|
foo,
|
||||||
notfound
|
notfound
|
||||||
} from './module-named-exports.mjs';
|
} from './module-named-exports.mjs';
|
||||||
`;
|
`;
|
||||||
|
|
||||||
[importStatement, importStatementMultiline].forEach((input) => {
|
describe('ESM: nonexistent exports', { concurrency: true }, () => {
|
||||||
const child = spawn(execPath, [
|
for (
|
||||||
'--input-type=module',
|
const { name, input }
|
||||||
'--eval',
|
of [
|
||||||
input,
|
{
|
||||||
], {
|
input: importStatement,
|
||||||
cwd: path('es-module-loaders'),
|
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 = '';
|
assert.notStrictEqual(code, 0);
|
||||||
child.stderr.setEncoding('utf8');
|
|
||||||
child.stderr.on('data', (data) => {
|
|
||||||
stderr += data;
|
|
||||||
});
|
|
||||||
child.on('close', mustCall((code, _signal) => {
|
|
||||||
notStrictEqual(code, 0);
|
|
||||||
|
|
||||||
// SyntaxError: The requested module './module-named-exports.mjs'
|
// SyntaxError: The requested module './module-named-exports.mjs'
|
||||||
// does not provide an export named 'notfound'
|
// does not provide an export named 'notfound'
|
||||||
match(stderr, /SyntaxError:/);
|
assert.match(stderr, /SyntaxError:/);
|
||||||
// The quotes ensure that the path starts with ./ and not ../
|
// The quotes ensure that the path starts with ./ and not ../
|
||||||
match(stderr, /'\.\/module-named-exports\.mjs'/);
|
assert.match(stderr, /'\.\/module-named-exports\.mjs'/);
|
||||||
match(stderr, /notfound/);
|
assert.match(stderr, /notfound/);
|
||||||
}));
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,22 @@
|
||||||
import { mustCall } from '../common/index.mjs';
|
import { spawnPromisified } from '../common/index.mjs';
|
||||||
import { path } from '../common/fixtures.mjs';
|
import * as fixtures from '../common/fixtures.mjs';
|
||||||
import { match, notStrictEqual } from 'assert';
|
import assert from 'node:assert';
|
||||||
import { spawn } from 'child_process';
|
import { execPath } from 'node:process';
|
||||||
import { execPath } from 'process';
|
import { describe, it } from 'node:test';
|
||||||
|
|
||||||
const child = spawn(execPath, [
|
|
||||||
path('es-modules', 'import-json-named-export.mjs'),
|
|
||||||
]);
|
|
||||||
|
|
||||||
let stderr = '';
|
describe('ESM: named JSON exports', { concurrency: true }, () => {
|
||||||
child.stderr.setEncoding('utf8');
|
it('should throw, citing named import', async () => {
|
||||||
child.stderr.on('data', (data) => {
|
const { code, stderr } = await spawnPromisified(execPath, [
|
||||||
stderr += data;
|
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'/);
|
||||||
|
|
||||||
|
assert.notStrictEqual(code, 0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
child.on('close', mustCall((code, _signal) => {
|
|
||||||
notStrictEqual(code, 0);
|
|
||||||
|
|
||||||
// SyntaxError: The requested module '../experimental.json'
|
|
||||||
// does not provide an export named 'ofLife'
|
|
||||||
match(stderr, /SyntaxError:/);
|
|
||||||
match(stderr, /'\.\.\/experimental\.json'/);
|
|
||||||
match(stderr, /'ofLife'/);
|
|
||||||
}));
|
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,29 @@
|
||||||
import '../common/index.mjs';
|
import { spawnPromisified } from '../common/index.mjs';
|
||||||
import * as fixtures from '../common/fixtures.mjs';
|
import * as fixtures from '../common/fixtures.mjs';
|
||||||
import assert from 'node:assert';
|
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
|
describe('ESM: ensure initialisation happens only once', { concurrency: true }, () => {
|
||||||
const { status, stderr, stdout } = spawnSync(
|
it(async () => {
|
||||||
process.execPath,
|
const { code, stderr, stdout } = await spawnPromisified(execPath, [
|
||||||
[
|
|
||||||
'--loader',
|
'--loader',
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-resolve-passthru.mjs'),
|
fixtures.fileURL('es-module-loaders', 'loader-resolve-passthru.mjs'),
|
||||||
'--no-warnings',
|
'--no-warnings',
|
||||||
fixtures.path('es-modules', 'runmain.mjs'),
|
fixtures.path('es-modules', 'runmain.mjs'),
|
||||||
],
|
]);
|
||||||
{ encoding: 'utf8' },
|
|
||||||
);
|
|
||||||
|
|
||||||
// Length minus 1 because the first match is the needle.
|
// Length minus 1 because the first match is the needle.
|
||||||
const resolveHookRunCount = (stdout.match(/resolve passthru/g)?.length ?? 0) - 1;
|
const resolveHookRunCount = (stdout.match(/resolve passthru/g)?.length ?? 0) - 1;
|
||||||
|
|
||||||
assert.strictEqual(stderr, '');
|
assert.strictEqual(stderr, '');
|
||||||
/**
|
/**
|
||||||
* resolveHookRunCount = 2:
|
* resolveHookRunCount = 2:
|
||||||
* 1. fixtures/…/runmain.mjs
|
* 1. fixtures/…/runmain.mjs
|
||||||
* 2. node:module (imported by fixtures/…/runmain.mjs)
|
* 2. node:module (imported by fixtures/…/runmain.mjs)
|
||||||
*/
|
*/
|
||||||
assert.strictEqual(resolveHookRunCount, 2);
|
assert.strictEqual(resolveHookRunCount, 2);
|
||||||
assert.strictEqual(status, 0);
|
assert.strictEqual(code, 0);
|
||||||
}
|
});
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -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));
|
|
||||||
|
|
@ -1,27 +1,28 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { mustCall, checkoutEOL } = require('../common');
|
const { checkoutEOL, spawnPromisified } = require('../common');
|
||||||
const fixtures = require('../common/fixtures');
|
const fixtures = require('../common/fixtures.js');
|
||||||
const { spawn } = require('child_process');
|
const assert = require('node:assert');
|
||||||
const { strictEqual, ok } = require('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]);
|
describe('ESM: Package.json', { concurrency: true }, () => {
|
||||||
child.stderr.setEncoding('utf8');
|
it('should throw on invalid pson', async () => {
|
||||||
let stderr = '';
|
const entry = fixtures.path('/es-modules/import-invalid-pjson.mjs');
|
||||||
child.stderr.on('data', (data) => {
|
const invalidJson = fixtures.path('/node_modules/invalid-pjson/package.json');
|
||||||
stderr += data;
|
|
||||||
|
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);
|
|
||||||
}));
|
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,25 @@
|
||||||
import '../common/index.mjs';
|
import { spawnPromisified } from '../common/index.mjs';
|
||||||
import { path } from '../common/fixtures.mjs';
|
import * as fixtures from '../common/fixtures.mjs';
|
||||||
import { strictEqual, ok } from 'assert';
|
import assert from 'node:assert';
|
||||||
import { spawn } from 'child_process';
|
import { execPath } from 'node:process';
|
||||||
|
import { describe, it } from 'node:test';
|
||||||
|
|
||||||
import secret from '../fixtures/experimental.json' assert { type: 'json' };
|
import secret from '../fixtures/experimental.json' assert { type: 'json' };
|
||||||
|
|
||||||
strictEqual(secret.ofLife, 42);
|
|
||||||
|
|
||||||
// Test warning message
|
describe('ESM: importing JSON', () => {
|
||||||
const child = spawn(process.execPath, [
|
it('should load JSON', () => {
|
||||||
path('/es-modules/json-modules.mjs'),
|
assert.strictEqual(secret.ofLife, 42);
|
||||||
]);
|
});
|
||||||
|
|
||||||
let stderr = '';
|
it('should print an experimental warning', async () => {
|
||||||
child.stderr.setEncoding('utf8');
|
const { code, signal, stderr } = await spawnPromisified(execPath, [
|
||||||
child.stderr.on('data', (data) => {
|
fixtures.path('/es-modules/json-modules.mjs'),
|
||||||
stderr += data;
|
]);
|
||||||
});
|
|
||||||
child.on('close', (code, signal) => {
|
assert.match(stderr, /ExperimentalWarning/);
|
||||||
strictEqual(code, 0);
|
assert.match(stderr, /JSON modules/);
|
||||||
strictEqual(signal, null);
|
assert.strictEqual(code, 0);
|
||||||
ok(stderr.toString().includes(
|
assert.strictEqual(signal, null);
|
||||||
'ExperimentalWarning: Importing JSON modules is an experimental feature. ' +
|
});
|
||||||
'This feature could change at any time'
|
|
||||||
));
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
import '../common/index.mjs';
|
import { spawnPromisified } from '../common/index.mjs';
|
||||||
import fixtures from '../common/fixtures.js';
|
import * as fixtures from '../common/fixtures.mjs';
|
||||||
import assert from 'node:assert';
|
import assert from 'node:assert';
|
||||||
import { spawnSync } from 'node:child_process';
|
import { execPath } from 'node:process';
|
||||||
|
import { describe, it } from 'node:test';
|
||||||
|
|
||||||
|
|
||||||
const setupArgs = [
|
const setupArgs = [
|
||||||
'--no-warnings',
|
'--no-warnings',
|
||||||
|
|
@ -14,420 +16,420 @@ const commonArgs = [
|
||||||
commonInput,
|
commonInput,
|
||||||
];
|
];
|
||||||
|
|
||||||
{ // Verify unadulterated source is loaded when there are no loaders
|
describe('ESM: loader chaining', { concurrency: true }, () => {
|
||||||
const { status, stderr, stdout } = spawnSync(
|
it('should load unadulterated source when there are no loaders', async () => {
|
||||||
process.execPath,
|
const { code, stderr, stdout } = await spawnPromisified(
|
||||||
[
|
execPath,
|
||||||
...setupArgs,
|
[
|
||||||
'import fs from "node:fs"; console.log(typeof fs?.constants?.F_OK )',
|
...setupArgs,
|
||||||
],
|
'import fs from "node:fs"; console.log(typeof fs?.constants?.F_OK )',
|
||||||
{ encoding: 'utf8' },
|
],
|
||||||
);
|
{ encoding: 'utf8' },
|
||||||
|
);
|
||||||
|
|
||||||
assert.strictEqual(stderr, '');
|
assert.strictEqual(stderr, '');
|
||||||
assert.match(stdout, /number/); // node:fs is an object
|
assert.match(stdout, /number/); // node:fs is an object
|
||||||
assert.strictEqual(status, 0);
|
assert.strictEqual(code, 0);
|
||||||
}
|
});
|
||||||
|
|
||||||
{ // Verify loaded source is properly different when only load changes something
|
it('should load properly different source when only load changes something', async () => {
|
||||||
const { status, stderr, stdout } = spawnSync(
|
const { code, stderr, stdout } = await spawnPromisified(
|
||||||
process.execPath,
|
execPath,
|
||||||
[
|
[
|
||||||
'--loader',
|
'--loader',
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-resolve-passthru.mjs'),
|
fixtures.fileURL('es-module-loaders', 'loader-resolve-passthru.mjs'),
|
||||||
'--loader',
|
'--loader',
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-load-foo-or-42.mjs'),
|
fixtures.fileURL('es-module-loaders', 'loader-load-foo-or-42.mjs'),
|
||||||
'--loader',
|
'--loader',
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-load-passthru.mjs'),
|
fixtures.fileURL('es-module-loaders', 'loader-load-passthru.mjs'),
|
||||||
...commonArgs,
|
...commonArgs,
|
||||||
],
|
],
|
||||||
{ encoding: 'utf8' },
|
{ encoding: 'utf8' },
|
||||||
);
|
);
|
||||||
|
|
||||||
assert.strictEqual(stderr, '');
|
assert.strictEqual(stderr, '');
|
||||||
assert.match(stdout, /load passthru/);
|
assert.match(stdout, /load passthru/);
|
||||||
assert.match(stdout, /resolve passthru/);
|
assert.match(stdout, /resolve passthru/);
|
||||||
assert.match(stdout, /foo/);
|
assert.match(stdout, /foo/);
|
||||||
assert.strictEqual(status, 0);
|
assert.strictEqual(code, 0);
|
||||||
}
|
});
|
||||||
|
|
||||||
{ // Verify multiple changes from hooks result in proper output
|
it('should result in proper output from multiple changes in resolve hooks', async () => {
|
||||||
const { status, stderr, stdout } = spawnSync(
|
const { code, stderr, stdout } = await spawnPromisified(
|
||||||
process.execPath,
|
execPath,
|
||||||
[
|
[
|
||||||
'--loader',
|
'--loader',
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-resolve-shortcircuit.mjs'),
|
fixtures.fileURL('es-module-loaders', 'loader-resolve-shortcircuit.mjs'),
|
||||||
'--loader',
|
'--loader',
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-resolve-foo.mjs'),
|
fixtures.fileURL('es-module-loaders', 'loader-resolve-foo.mjs'),
|
||||||
'--loader',
|
'--loader',
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-resolve-42.mjs'),
|
fixtures.fileURL('es-module-loaders', 'loader-resolve-42.mjs'),
|
||||||
'--loader',
|
'--loader',
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-load-foo-or-42.mjs'),
|
fixtures.fileURL('es-module-loaders', 'loader-load-foo-or-42.mjs'),
|
||||||
...commonArgs,
|
...commonArgs,
|
||||||
],
|
],
|
||||||
{ encoding: 'utf8' },
|
{ encoding: 'utf8' },
|
||||||
);
|
);
|
||||||
|
|
||||||
assert.strictEqual(stderr, '');
|
assert.strictEqual(stderr, '');
|
||||||
assert.match(stdout, /resolve 42/); // It did go thru resolve-42
|
assert.match(stdout, /resolve 42/); // It did go thru resolve-42
|
||||||
assert.match(stdout, /foo/); // LIFO, so resolve-foo won
|
assert.match(stdout, /foo/); // LIFO, so resolve-foo won
|
||||||
assert.strictEqual(status, 0);
|
assert.strictEqual(code, 0);
|
||||||
}
|
});
|
||||||
|
|
||||||
{ // Verify modifying context within resolve chain is respected
|
it('should respect modified context within resolve chain', async () => {
|
||||||
const { status, stderr, stdout } = spawnSync(
|
const { code, stderr, stdout } = await spawnPromisified(
|
||||||
process.execPath,
|
execPath,
|
||||||
[
|
[
|
||||||
'--loader',
|
'--loader',
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-resolve-shortcircuit.mjs'),
|
fixtures.fileURL('es-module-loaders', 'loader-resolve-shortcircuit.mjs'),
|
||||||
'--loader',
|
'--loader',
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-resolve-42.mjs'),
|
fixtures.fileURL('es-module-loaders', 'loader-resolve-42.mjs'),
|
||||||
'--loader',
|
'--loader',
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-load-foo-or-42.mjs'),
|
fixtures.fileURL('es-module-loaders', 'loader-load-foo-or-42.mjs'),
|
||||||
'--loader',
|
'--loader',
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-load-receiving-modified-context.mjs'),
|
fixtures.fileURL('es-module-loaders', 'loader-load-receiving-modified-context.mjs'),
|
||||||
'--loader',
|
'--loader',
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-load-passing-modified-context.mjs'),
|
fixtures.fileURL('es-module-loaders', 'loader-load-passing-modified-context.mjs'),
|
||||||
...commonArgs,
|
...commonArgs,
|
||||||
],
|
],
|
||||||
{ encoding: 'utf8' },
|
{ encoding: 'utf8' },
|
||||||
);
|
);
|
||||||
|
|
||||||
assert.strictEqual(stderr, '');
|
assert.strictEqual(stderr, '');
|
||||||
assert.match(stdout, /bar/);
|
assert.match(stdout, /bar/);
|
||||||
assert.strictEqual(status, 0);
|
assert.strictEqual(code, 0);
|
||||||
}
|
});
|
||||||
|
|
||||||
{ // Verify multiple changes from hooks result in proper output
|
it('should result in proper output from multiple changes in resolve hooks', async () => {
|
||||||
const { status, stderr, stdout } = spawnSync(
|
const { code, stderr, stdout } = await spawnPromisified(
|
||||||
process.execPath,
|
execPath,
|
||||||
[
|
[
|
||||||
'--loader',
|
'--loader',
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-resolve-shortcircuit.mjs'),
|
fixtures.fileURL('es-module-loaders', 'loader-resolve-shortcircuit.mjs'),
|
||||||
'--loader',
|
'--loader',
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-resolve-42.mjs'),
|
fixtures.fileURL('es-module-loaders', 'loader-resolve-42.mjs'),
|
||||||
'--loader',
|
'--loader',
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-resolve-foo.mjs'),
|
fixtures.fileURL('es-module-loaders', 'loader-resolve-foo.mjs'),
|
||||||
'--loader',
|
'--loader',
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-load-foo-or-42.mjs'),
|
fixtures.fileURL('es-module-loaders', 'loader-load-foo-or-42.mjs'),
|
||||||
...commonArgs,
|
...commonArgs,
|
||||||
],
|
],
|
||||||
{ encoding: 'utf8' },
|
{ encoding: 'utf8' },
|
||||||
);
|
);
|
||||||
|
|
||||||
assert.strictEqual(stderr, '');
|
assert.strictEqual(stderr, '');
|
||||||
assert.match(stdout, /resolve foo/); // It did go thru resolve-foo
|
assert.match(stdout, /resolve foo/); // It did go thru resolve-foo
|
||||||
assert.match(stdout, /42/); // LIFO, so resolve-42 won
|
assert.match(stdout, /42/); // LIFO, so resolve-42 won
|
||||||
assert.strictEqual(status, 0);
|
assert.strictEqual(code, 0);
|
||||||
}
|
});
|
||||||
|
|
||||||
{ // Verify multiple calls to next within same loader receive correct "next" fn
|
it('should provide the correct "next" fn when multiple calls to next within same loader', async () => {
|
||||||
const { status, stderr, stdout } = spawnSync(
|
const { code, stderr, stdout } = await spawnPromisified(
|
||||||
process.execPath,
|
execPath,
|
||||||
[
|
[
|
||||||
'--loader',
|
'--loader',
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-resolve-shortcircuit.mjs'),
|
fixtures.fileURL('es-module-loaders', 'loader-resolve-shortcircuit.mjs'),
|
||||||
'--loader',
|
'--loader',
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-resolve-foo.mjs'),
|
fixtures.fileURL('es-module-loaders', 'loader-resolve-foo.mjs'),
|
||||||
'--loader',
|
'--loader',
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-resolve-multiple-next-calls.mjs'),
|
fixtures.fileURL('es-module-loaders', 'loader-resolve-multiple-next-calls.mjs'),
|
||||||
'--loader',
|
'--loader',
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-load-foo-or-42.mjs'),
|
fixtures.fileURL('es-module-loaders', 'loader-load-foo-or-42.mjs'),
|
||||||
...commonArgs,
|
...commonArgs,
|
||||||
],
|
],
|
||||||
{ encoding: 'utf8' },
|
{ encoding: 'utf8' },
|
||||||
);
|
);
|
||||||
|
|
||||||
const countFoos = stdout.match(/resolve foo/g)?.length;
|
const countFoos = stdout.match(/resolve foo/g)?.length;
|
||||||
|
|
||||||
assert.strictEqual(stderr, '');
|
assert.strictEqual(stderr, '');
|
||||||
assert.strictEqual(countFoos, 2);
|
assert.strictEqual(countFoos, 2);
|
||||||
assert.strictEqual(status, 0);
|
assert.strictEqual(code, 0);
|
||||||
}
|
});
|
||||||
|
|
||||||
{ // Verify next<HookName> function's `name` is correct
|
it('should use the correct `name` for next<HookName>\'s function', async () => {
|
||||||
const { status, stderr, stdout } = spawnSync(
|
const { code, stderr, stdout } = await spawnPromisified(
|
||||||
process.execPath,
|
execPath,
|
||||||
[
|
[
|
||||||
'--loader',
|
'--loader',
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-resolve-shortcircuit.mjs'),
|
fixtures.fileURL('es-module-loaders', 'loader-resolve-shortcircuit.mjs'),
|
||||||
'--loader',
|
'--loader',
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-resolve-42.mjs'),
|
fixtures.fileURL('es-module-loaders', 'loader-resolve-42.mjs'),
|
||||||
'--loader',
|
'--loader',
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-load-foo-or-42.mjs'),
|
fixtures.fileURL('es-module-loaders', 'loader-load-foo-or-42.mjs'),
|
||||||
...commonArgs,
|
...commonArgs,
|
||||||
],
|
],
|
||||||
{ encoding: 'utf8' },
|
{ encoding: 'utf8' },
|
||||||
);
|
);
|
||||||
|
|
||||||
assert.strictEqual(stderr, '');
|
assert.strictEqual(stderr, '');
|
||||||
assert.match(stdout, /next<HookName>: nextResolve/);
|
assert.match(stdout, /next<HookName>: nextResolve/);
|
||||||
assert.strictEqual(status, 0);
|
assert.strictEqual(code, 0);
|
||||||
}
|
});
|
||||||
|
|
||||||
{ // Verify error thrown for incomplete resolve chain, citing errant loader & hook
|
it('should throw for incomplete resolve chain, citing errant loader & hook', async () => {
|
||||||
const { status, stderr, stdout } = spawnSync(
|
const { code, stderr, stdout } = await spawnPromisified(
|
||||||
process.execPath,
|
execPath,
|
||||||
[
|
[
|
||||||
'--loader',
|
'--loader',
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-resolve-incomplete.mjs'),
|
fixtures.fileURL('es-module-loaders', 'loader-resolve-incomplete.mjs'),
|
||||||
'--loader',
|
'--loader',
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-resolve-passthru.mjs'),
|
fixtures.fileURL('es-module-loaders', 'loader-resolve-passthru.mjs'),
|
||||||
'--loader',
|
'--loader',
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-load-foo-or-42.mjs'),
|
fixtures.fileURL('es-module-loaders', 'loader-load-foo-or-42.mjs'),
|
||||||
...commonArgs,
|
...commonArgs,
|
||||||
],
|
],
|
||||||
{ encoding: 'utf8' },
|
{ 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);
|
||||||
|
});
|
||||||
|
|
||||||
assert.match(stdout, /resolve passthru/);
|
it('should NOT throw when nested resolve hook signaled a short circuit', async () => {
|
||||||
assert.match(stderr, /ERR_LOADER_CHAIN_INCOMPLETE/);
|
const { code, stderr, stdout } = await spawnPromisified(
|
||||||
assert.match(stderr, /loader-resolve-incomplete\.mjs/);
|
execPath,
|
||||||
assert.match(stderr, /'resolve'/);
|
[
|
||||||
assert.strictEqual(status, 1);
|
'--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' },
|
||||||
|
);
|
||||||
|
|
||||||
{ // Verify error NOT thrown when nested resolve hook signaled a short circuit
|
assert.strictEqual(stderr, '');
|
||||||
const { status, stderr, stdout } = spawnSync(
|
assert.strictEqual(stdout.trim(), 'foo');
|
||||||
process.execPath,
|
assert.strictEqual(code, 0);
|
||||||
[
|
});
|
||||||
'--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, '');
|
it('should NOT throw when nested load hook signaled a short circuit', async () => {
|
||||||
assert.strictEqual(stdout.trim(), 'foo');
|
const { code, stderr, stdout } = await spawnPromisified(
|
||||||
assert.strictEqual(status, 0);
|
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' },
|
||||||
|
);
|
||||||
|
|
||||||
{ // Verify error NOT thrown when nested load hook signaled a short circuit
|
assert.strictEqual(stderr, '');
|
||||||
const { status, stderr, stdout } = spawnSync(
|
assert.match(stdout, /421/);
|
||||||
process.execPath,
|
assert.strictEqual(code, 0);
|
||||||
[
|
});
|
||||||
'--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, '');
|
it('should throw when the resolve chain is broken', async () => {
|
||||||
assert.match(stdout, /421/);
|
const { code, stderr, stdout } = await spawnPromisified(
|
||||||
assert.strictEqual(status, 0);
|
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' },
|
||||||
|
);
|
||||||
|
|
||||||
{ // Verify resolve chain does break and throws appropriately
|
assert.doesNotMatch(stdout, /resolve passthru/);
|
||||||
const { status, stderr, stdout } = spawnSync(
|
assert.match(stderr, /ERR_LOADER_CHAIN_INCOMPLETE/);
|
||||||
process.execPath,
|
assert.match(stderr, /loader-resolve-incomplete\.mjs/);
|
||||||
[
|
assert.match(stderr, /'resolve'/);
|
||||||
'--loader',
|
assert.strictEqual(code, 1);
|
||||||
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/);
|
it('should throw for incomplete load chain, citing errant loader & hook', async () => {
|
||||||
assert.match(stderr, /ERR_LOADER_CHAIN_INCOMPLETE/);
|
const { code, stderr, stdout } = await spawnPromisified(
|
||||||
assert.match(stderr, /loader-resolve-incomplete\.mjs/);
|
execPath,
|
||||||
assert.match(stderr, /'resolve'/);
|
[
|
||||||
assert.strictEqual(status, 1);
|
'--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' },
|
||||||
|
);
|
||||||
|
|
||||||
{ // Verify error thrown for incomplete load chain, citing errant loader & hook
|
assert.match(stdout, /load passthru/);
|
||||||
const { status, stderr, stdout } = spawnSync(
|
assert.match(stderr, /ERR_LOADER_CHAIN_INCOMPLETE/);
|
||||||
process.execPath,
|
assert.match(stderr, /loader-load-incomplete\.mjs/);
|
||||||
[
|
assert.match(stderr, /'load'/);
|
||||||
'--loader',
|
assert.strictEqual(code, 1);
|
||||||
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/);
|
it('should throw when the load chain is broken', async () => {
|
||||||
assert.match(stderr, /ERR_LOADER_CHAIN_INCOMPLETE/);
|
const { code, stderr, stdout } = await spawnPromisified(
|
||||||
assert.match(stderr, /loader-load-incomplete\.mjs/);
|
execPath,
|
||||||
assert.match(stderr, /'load'/);
|
[
|
||||||
assert.strictEqual(status, 1);
|
'--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' },
|
||||||
|
);
|
||||||
|
|
||||||
{ // Verify load chain does break and throws appropriately
|
assert.doesNotMatch(stdout, /load passthru/);
|
||||||
const { status, stderr, stdout } = spawnSync(
|
assert.match(stderr, /ERR_LOADER_CHAIN_INCOMPLETE/);
|
||||||
process.execPath,
|
assert.match(stderr, /loader-load-incomplete\.mjs/);
|
||||||
[
|
assert.match(stderr, /'load'/);
|
||||||
'--loader',
|
assert.strictEqual(code, 1);
|
||||||
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/);
|
it('should throw when invalid `specifier` argument passed to `nextResolve`', async () => {
|
||||||
assert.match(stderr, /ERR_LOADER_CHAIN_INCOMPLETE/);
|
const { code, stderr } = await spawnPromisified(
|
||||||
assert.match(stderr, /loader-load-incomplete\.mjs/);
|
execPath,
|
||||||
assert.match(stderr, /'load'/);
|
[
|
||||||
assert.strictEqual(status, 1);
|
'--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' },
|
||||||
|
);
|
||||||
|
|
||||||
{ // Verify error thrown when invalid `specifier` argument passed to `nextResolve`
|
assert.strictEqual(code, 1);
|
||||||
const { status, stderr } = spawnSync(
|
assert.match(stderr, /ERR_INVALID_ARG_TYPE/);
|
||||||
process.execPath,
|
assert.match(stderr, /loader-resolve-bad-next-specifier\.mjs/);
|
||||||
[
|
assert.match(stderr, /'resolve' hook's nextResolve\(\) specifier/);
|
||||||
'--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);
|
it('should throw when resolve hook is invalid', async () => {
|
||||||
assert.match(stderr, /ERR_INVALID_ARG_TYPE/);
|
const { code, stderr } = await spawnPromisified(
|
||||||
assert.match(stderr, /loader-resolve-bad-next-specifier\.mjs/);
|
execPath,
|
||||||
assert.match(stderr, /'resolve' hook's nextResolve\(\) specifier/);
|
[
|
||||||
}
|
'--loader',
|
||||||
|
fixtures.fileURL('es-module-loaders', 'loader-resolve-passthru.mjs'),
|
||||||
|
'--loader',
|
||||||
|
fixtures.fileURL('es-module-loaders', 'loader-resolve-null-return.mjs'),
|
||||||
|
...commonArgs,
|
||||||
|
],
|
||||||
|
{ encoding: 'utf8' },
|
||||||
|
);
|
||||||
|
|
||||||
{ // Verify error thrown when resolve hook is invalid
|
assert.strictEqual(code, 1);
|
||||||
const { status, stderr } = spawnSync(
|
assert.match(stderr, /ERR_INVALID_RETURN_VALUE/);
|
||||||
process.execPath,
|
assert.match(stderr, /loader-resolve-null-return\.mjs/);
|
||||||
[
|
assert.match(stderr, /'resolve' hook's nextResolve\(\)/);
|
||||||
'--loader',
|
assert.match(stderr, /an object/);
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-resolve-passthru.mjs'),
|
assert.match(stderr, /got null/);
|
||||||
'--loader',
|
});
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-resolve-null-return.mjs'),
|
|
||||||
...commonArgs,
|
|
||||||
],
|
|
||||||
{ encoding: 'utf8' },
|
|
||||||
);
|
|
||||||
|
|
||||||
assert.strictEqual(status, 1);
|
it('should throw when invalid `context` argument passed to `nextResolve`', async () => {
|
||||||
assert.match(stderr, /ERR_INVALID_RETURN_VALUE/);
|
const { code, stderr } = await spawnPromisified(
|
||||||
assert.match(stderr, /loader-resolve-null-return\.mjs/);
|
execPath,
|
||||||
assert.match(stderr, /'resolve' hook's nextResolve\(\)/);
|
[
|
||||||
assert.match(stderr, /an object/);
|
'--loader',
|
||||||
assert.match(stderr, /got null/);
|
fixtures.fileURL('es-module-loaders', 'loader-resolve-passthru.mjs'),
|
||||||
}
|
'--loader',
|
||||||
|
fixtures.fileURL('es-module-loaders', 'loader-resolve-bad-next-context.mjs'),
|
||||||
|
...commonArgs,
|
||||||
|
],
|
||||||
|
{ encoding: 'utf8' },
|
||||||
|
);
|
||||||
|
|
||||||
{ // Verify error thrown when invalid `context` argument passed to `nextResolve`
|
assert.match(stderr, /ERR_INVALID_ARG_TYPE/);
|
||||||
const { status, stderr } = spawnSync(
|
assert.match(stderr, /loader-resolve-bad-next-context\.mjs/);
|
||||||
process.execPath,
|
assert.match(stderr, /'resolve' hook's nextResolve\(\) context/);
|
||||||
[
|
assert.strictEqual(code, 1);
|
||||||
'--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/);
|
it('should throw when load hook is invalid', async () => {
|
||||||
assert.match(stderr, /loader-resolve-bad-next-context\.mjs/);
|
const { code, stderr } = await spawnPromisified(
|
||||||
assert.match(stderr, /'resolve' hook's nextResolve\(\) context/);
|
execPath,
|
||||||
assert.strictEqual(status, 1);
|
[
|
||||||
}
|
'--loader',
|
||||||
|
fixtures.fileURL('es-module-loaders', 'loader-load-passthru.mjs'),
|
||||||
|
'--loader',
|
||||||
|
fixtures.fileURL('es-module-loaders', 'loader-load-null-return.mjs'),
|
||||||
|
...commonArgs,
|
||||||
|
],
|
||||||
|
{ encoding: 'utf8' },
|
||||||
|
);
|
||||||
|
|
||||||
{ // Verify error thrown when load hook is invalid
|
assert.strictEqual(code, 1);
|
||||||
const { status, stderr } = spawnSync(
|
assert.match(stderr, /ERR_INVALID_RETURN_VALUE/);
|
||||||
process.execPath,
|
assert.match(stderr, /loader-load-null-return\.mjs/);
|
||||||
[
|
assert.match(stderr, /'load' hook's nextLoad\(\)/);
|
||||||
'--loader',
|
assert.match(stderr, /an object/);
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-load-passthru.mjs'),
|
assert.match(stderr, /got null/);
|
||||||
'--loader',
|
});
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-load-null-return.mjs'),
|
|
||||||
...commonArgs,
|
|
||||||
],
|
|
||||||
{ encoding: 'utf8' },
|
|
||||||
);
|
|
||||||
|
|
||||||
assert.strictEqual(status, 1);
|
it('should throw when invalid `url` argument passed to `nextLoad`', async () => {
|
||||||
assert.match(stderr, /ERR_INVALID_RETURN_VALUE/);
|
const { code, stderr } = await spawnPromisified(
|
||||||
assert.match(stderr, /loader-load-null-return\.mjs/);
|
execPath,
|
||||||
assert.match(stderr, /'load' hook's nextLoad\(\)/);
|
[
|
||||||
assert.match(stderr, /an object/);
|
'--loader',
|
||||||
assert.match(stderr, /got null/);
|
fixtures.fileURL('es-module-loaders', 'loader-load-passthru.mjs'),
|
||||||
}
|
'--loader',
|
||||||
|
fixtures.fileURL('es-module-loaders', 'loader-load-bad-next-url.mjs'),
|
||||||
|
...commonArgs,
|
||||||
|
],
|
||||||
|
{ encoding: 'utf8' },
|
||||||
|
);
|
||||||
|
|
||||||
{ // Verify error thrown when invalid `url` argument passed to `nextLoad`
|
assert.match(stderr, /ERR_INVALID_ARG_TYPE/);
|
||||||
const { status, stderr } = spawnSync(
|
assert.match(stderr, /loader-load-bad-next-url\.mjs/);
|
||||||
process.execPath,
|
assert.match(stderr, /'load' hook's nextLoad\(\) url/);
|
||||||
[
|
assert.strictEqual(code, 1);
|
||||||
'--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/);
|
it('should throw when invalid `url` argument passed to `nextLoad`', async () => {
|
||||||
assert.match(stderr, /loader-load-bad-next-url\.mjs/);
|
const { code, stderr } = await spawnPromisified(
|
||||||
assert.match(stderr, /'load' hook's nextLoad\(\) url/);
|
execPath,
|
||||||
assert.strictEqual(status, 1);
|
[
|
||||||
}
|
'--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' },
|
||||||
|
);
|
||||||
|
|
||||||
{ // Verify error thrown when invalid `url` argument passed to `nextLoad`
|
assert.match(stderr, /ERR_INVALID_ARG_VALUE/);
|
||||||
const { status, stderr } = spawnSync(
|
assert.match(stderr, /loader-load-impersonating-next-url\.mjs/);
|
||||||
process.execPath,
|
assert.match(stderr, /'load' hook's nextLoad\(\) url/);
|
||||||
[
|
assert.strictEqual(code, 1);
|
||||||
'--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/);
|
it('should throw when invalid `context` argument passed to `nextLoad`', async () => {
|
||||||
assert.match(stderr, /loader-load-impersonating-next-url\.mjs/);
|
const { code, stderr } = await spawnPromisified(
|
||||||
assert.match(stderr, /'load' hook's nextLoad\(\) url/);
|
execPath,
|
||||||
assert.strictEqual(status, 1);
|
[
|
||||||
}
|
'--loader',
|
||||||
|
fixtures.fileURL('es-module-loaders', 'loader-load-passthru.mjs'),
|
||||||
{ // Verify error thrown when invalid `context` argument passed to `nextLoad`
|
'--loader',
|
||||||
const { status, stderr } = spawnSync(
|
fixtures.fileURL('es-module-loaders', 'loader-load-bad-next-context.mjs'),
|
||||||
process.execPath,
|
...commonArgs,
|
||||||
[
|
],
|
||||||
'--loader',
|
{ encoding: 'utf8' },
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-load-passthru.mjs'),
|
);
|
||||||
'--loader',
|
assert.match(stderr, /ERR_INVALID_ARG_TYPE/);
|
||||||
fixtures.fileURL('es-module-loaders', 'loader-load-bad-next-context.mjs'),
|
assert.match(stderr, /loader-load-bad-next-context\.mjs/);
|
||||||
...commonArgs,
|
assert.match(stderr, /'load' hook's nextLoad\(\) context/);
|
||||||
],
|
assert.strictEqual(code, 1);
|
||||||
{ 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);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import { mustCall } from '../common/index.mjs';
|
import { spawnPromisified } from '../common/index.mjs';
|
||||||
import fixtures from '../common/fixtures.js';
|
import fixtures from '../common/fixtures.js';
|
||||||
import { strictEqual } from 'node:assert';
|
import assert from 'node:assert';
|
||||||
import { spawn } from 'node:child_process';
|
|
||||||
import http from 'node:http';
|
import http from 'node:http';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
|
import { execPath } from 'node:process';
|
||||||
import { promisify } from 'node:util';
|
import { promisify } from 'node:util';
|
||||||
|
import { describe, it } from 'node:test';
|
||||||
|
|
||||||
|
|
||||||
const files = {
|
const files = {
|
||||||
|
|
@ -40,33 +41,31 @@ const {
|
||||||
port,
|
port,
|
||||||
} = server.address();
|
} = server.address();
|
||||||
|
|
||||||
{ // Verify nested HTTP imports work
|
/**
|
||||||
const child = spawn( // ! `spawn` MUST be used (vs `spawnSync`) to avoid blocking the event loop
|
* ! If more cases are added to this test, they cannot (yet) be concurrent because there is no
|
||||||
process.execPath,
|
* ! `afterAll` teardown in which to close the server.
|
||||||
[
|
*/
|
||||||
'--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)`,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
let stderr = '';
|
describe('ESM: http import via loader', { concurrency: false }, () => {
|
||||||
let stdout = '';
|
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');
|
assert.strictEqual(stderr, '');
|
||||||
child.stderr.on('data', (data) => stderr += data);
|
assert.strictEqual(stdout, '[Module: null prototype] { sum: [Function: sum] }\n');
|
||||||
child.stdout.setEncoding('utf8');
|
assert.strictEqual(code, 0);
|
||||||
child.stdout.on('data', (data) => stdout += data);
|
assert.strictEqual(signal, null);
|
||||||
|
|
||||||
child.on('close', mustCall((code, signal) => {
|
server.close(); // ! This MUST come after the final test, but inside the async `it` function
|
||||||
strictEqual(stderr, '');
|
});
|
||||||
strictEqual(stdout, '[Module: null prototype] { sum: [Function: sum] }\n');
|
});
|
||||||
strictEqual(code, 0);
|
|
||||||
strictEqual(signal, null);
|
|
||||||
|
|
||||||
server.close();
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,24 @@
|
||||||
import { mustCall } from '../common/index.mjs';
|
import { spawnPromisified } from '../common/index.mjs';
|
||||||
import { path } from '../common/fixtures.mjs';
|
import * as fixtures from '../common/fixtures.mjs';
|
||||||
import { match, ok, notStrictEqual } from 'assert';
|
import assert from 'node:assert';
|
||||||
import { spawn } from 'child_process';
|
import { execPath } from 'node:process';
|
||||||
import { execPath } from 'process';
|
import { describe, it } from 'node:test';
|
||||||
|
|
||||||
const child = spawn(execPath, [
|
|
||||||
'--experimental-loader',
|
|
||||||
'i-dont-exist',
|
|
||||||
path('print-error-message.js'),
|
|
||||||
]);
|
|
||||||
|
|
||||||
let stderr = '';
|
describe('ESM: nonexistent loader', () => {
|
||||||
child.stderr.setEncoding('utf8');
|
it('should throw', async () => {
|
||||||
child.stderr.on('data', (data) => {
|
const { code, stderr } = await spawnPromisified(execPath, [
|
||||||
stderr += data;
|
'--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
|
||||||
|
assert.match(stderr, /ERR_MODULE_NOT_FOUND/);
|
||||||
|
assert.match(stderr, /'i-dont-exist'/);
|
||||||
|
|
||||||
|
assert.ok(!stderr.includes('Bad command or file name'));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
child.on('close', mustCall((code, _signal) => {
|
|
||||||
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'/);
|
|
||||||
|
|
||||||
ok(!stderr.includes('Bad command or file name'));
|
|
||||||
}));
|
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,28 @@
|
||||||
import { mustCall } from '../common/index.mjs';
|
import { spawnPromisified } from '../common/index.mjs';
|
||||||
import { fileURL, path } from '../common/fixtures.mjs';
|
import { fileURL, path } from '../common/fixtures.mjs';
|
||||||
import { match, notStrictEqual } from 'assert';
|
import { match, notStrictEqual } from 'node:assert';
|
||||||
import { spawn } from 'child_process';
|
import { execPath } from 'node:process';
|
||||||
import { execPath } from '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 = '';
|
describe('ESM: deprecation warnings for obsolete hooks', { concurrency: true }, () => {
|
||||||
child.stderr.setEncoding('utf8');
|
it(async () => {
|
||||||
child.stderr.on('data', (data) => {
|
const { code, stderr } = await spawnPromisified(execPath, [
|
||||||
stderr += data;
|
'--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/);
|
||||||
|
|
||||||
|
notStrictEqual(code, 0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
child.on('close', mustCall((code, _signal) => {
|
|
||||||
notStrictEqual(code, 0);
|
|
||||||
|
|
||||||
// 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/);
|
|
||||||
}));
|
|
||||||
|
|
|
||||||
|
|
@ -1,65 +1,43 @@
|
||||||
import { mustCall } from '../common/index.mjs';
|
import { spawnPromisified } from '../common/index.mjs';
|
||||||
import { fileURL, path } from '../common/fixtures.mjs';
|
import { fileURL, path } from '../common/fixtures.mjs';
|
||||||
import { match, ok, notStrictEqual, strictEqual } from 'assert';
|
import { match, ok, notStrictEqual, strictEqual } from 'assert';
|
||||||
import { spawn } from 'child_process';
|
import { execPath } from 'node:process';
|
||||||
import { execPath } from '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 = '';
|
describe('ESM: thenable loader hooks', { concurrency: true }, () => {
|
||||||
child.stderr.setEncoding('utf8');
|
it('should behave as a normal promise resolution', async () => {
|
||||||
child.stderr.on('data', (data) => {
|
const { code, stderr } = await spawnPromisified(execPath, [
|
||||||
stderr += data;
|
'--experimental-loader',
|
||||||
});
|
fileURL('es-module-loaders', 'thenable-load-hook.mjs').href,
|
||||||
child.on('close', mustCall((code, _signal) => {
|
path('es-modules', 'test-esm-ok.mjs'),
|
||||||
|
]);
|
||||||
|
|
||||||
strictEqual(code, 0);
|
strictEqual(code, 0);
|
||||||
ok(!stderr.includes('must not call'));
|
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'),
|
|
||||||
]);
|
|
||||||
|
|
||||||
let stderr = '';
|
|
||||||
child.stderr.setEncoding('utf8');
|
|
||||||
child.stderr.on('data', (data) => {
|
|
||||||
stderr += data;
|
|
||||||
});
|
});
|
||||||
child.on('close', mustCall((code, _signal) => {
|
|
||||||
notStrictEqual(code, 0);
|
|
||||||
|
|
||||||
|
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'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
notStrictEqual(code, 0);
|
||||||
match(stderr, /\sError: must crash the process\r?\n/);
|
match(stderr, /\sError: must crash the process\r?\n/);
|
||||||
|
|
||||||
ok(!stderr.includes('must not call'));
|
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'),
|
|
||||||
]);
|
|
||||||
|
|
||||||
let stderr = '';
|
|
||||||
child.stderr.setEncoding('utf8');
|
|
||||||
child.stderr.on('data', (data) => {
|
|
||||||
stderr += data;
|
|
||||||
});
|
});
|
||||||
child.on('close', mustCall((code, _signal) => {
|
|
||||||
|
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'),
|
||||||
|
]);
|
||||||
|
|
||||||
notStrictEqual(code, 0);
|
notStrictEqual(code, 0);
|
||||||
|
|
||||||
match(stderr, /\sundefined\r?\n/);
|
match(stderr, /\sundefined\r?\n/);
|
||||||
|
|
||||||
ok(!stderr.includes('must not call'));
|
ok(!stderr.includes('must not call'));
|
||||||
}));
|
});
|
||||||
}
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,20 @@
|
||||||
import { mustCall } from '../common/index.mjs';
|
import { spawnPromisified } from '../common/index.mjs';
|
||||||
import { fileURL, path } from '../common/fixtures.mjs';
|
import { fileURL, path } from '../common/fixtures.mjs';
|
||||||
import { match, ok, notStrictEqual } from 'assert';
|
import { match, ok, notStrictEqual } from 'node:assert';
|
||||||
import { spawn } from 'child_process';
|
import { execPath } from 'node:process';
|
||||||
import { execPath } from '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 = '';
|
describe('ESM: loader with syntax error', { concurrency: true }, () => {
|
||||||
child.stderr.setEncoding('utf8');
|
it('should crash the node process', async () => {
|
||||||
child.stderr.on('data', (data) => {
|
const { code, stderr } = await spawnPromisified(execPath, [
|
||||||
stderr += data;
|
'--experimental-loader',
|
||||||
|
fileURL('es-module-loaders', 'syntax-error.mjs').href,
|
||||||
|
path('print-error-message.js'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
match(stderr, /SyntaxError:/);
|
||||||
|
ok(!stderr.includes('Bad command or file name'));
|
||||||
|
notStrictEqual(code, 0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
child.on('close', mustCall((code, _signal) => {
|
|
||||||
notStrictEqual(code, 0);
|
|
||||||
|
|
||||||
match(stderr, /SyntaxError:/);
|
|
||||||
|
|
||||||
ok(!stderr.includes('Bad command or file name'));
|
|
||||||
}));
|
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,34 @@
|
||||||
import { mustCall } from '../common/index.mjs';
|
import { spawnPromisified } from '../common/index.mjs';
|
||||||
import { fixturesDir } from '../common/fixtures.mjs';
|
import { fixturesDir } from '../common/fixtures.mjs';
|
||||||
import { match, notStrictEqual } from 'assert';
|
import { match, notStrictEqual } from 'node:assert';
|
||||||
import { spawn } from 'child_process';
|
import { execPath } from 'node:process';
|
||||||
import { execPath } from '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 = '';
|
describe('ESM: module not found hint', { concurrency: true }, () => {
|
||||||
child.stderr.setEncoding('utf8');
|
for (
|
||||||
child.stderr.on('data', (data) => {
|
const { input, expected }
|
||||||
stderr += data;
|
of [
|
||||||
});
|
{
|
||||||
child.on('close', mustCall((code, _signal) => {
|
input: 'import "./print-error-message"',
|
||||||
notStrictEqual(code, 0);
|
// 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);
|
match(stderr, expected);
|
||||||
}));
|
notStrictEqual(code, 0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,20 @@
|
||||||
import { mustCall } from '../common/index.mjs';
|
import { spawnPromisified } from '../common/index.mjs';
|
||||||
import { fileURL } from '../common/fixtures.mjs';
|
import { fileURL } from '../common/fixtures.mjs';
|
||||||
import { match, strictEqual } from 'assert';
|
import { match, strictEqual } from 'node:assert';
|
||||||
import { spawn } from 'child_process';
|
import { execPath } from 'node:process';
|
||||||
import { execPath } from '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 = '';
|
describe('ESM: non-js extensions fail', { concurrency: true }, () => {
|
||||||
child.stderr.setEncoding('utf8');
|
it(async () => {
|
||||||
child.stderr.on('data', (data) => {
|
const { code, stderr, signal } = await spawnPromisified(execPath, [
|
||||||
stderr += data;
|
'--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/);
|
|
||||||
}));
|
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,19 @@
|
||||||
import '../common/index.mjs';
|
import { spawnPromisified } from '../common/index.mjs';
|
||||||
import { path } from '../common/fixtures.mjs';
|
import { path } from '../common/fixtures.mjs';
|
||||||
import { strictEqual, ok } from 'assert';
|
import { strictEqual } from 'node:assert';
|
||||||
import { spawn } from 'child_process';
|
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 = '';
|
describe('ESM: experiemental warning for import.meta.resolve', { concurrency: true }, () => {
|
||||||
child.stderr.setEncoding('utf8');
|
it('should not warn when caught', async () => {
|
||||||
child.stderr.on('data', (data) => {
|
const { code, signal, stderr } = await spawnPromisified(execPath, [
|
||||||
stderr += data;
|
'--experimental-import-meta-resolve',
|
||||||
});
|
path('es-modules/import-resolve-exports.mjs'),
|
||||||
child.on('close', (code, signal) => {
|
]);
|
||||||
strictEqual(code, 0);
|
|
||||||
strictEqual(signal, null);
|
strictEqual(stderr, '');
|
||||||
ok(!stderr.toString().includes(
|
strictEqual(code, 0);
|
||||||
'ExperimentalWarning: The ESM module loader is experimental'
|
strictEqual(signal, null);
|
||||||
));
|
});
|
||||||
ok(!stderr.toString().includes(
|
|
||||||
'ExperimentalWarning: Conditional exports'
|
|
||||||
));
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -39,15 +39,15 @@ function doTest(flags, done) {
|
||||||
// dictates that it'll resolve relative imports in the main file relative to
|
// 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
|
// 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
|
// up above requires this to not crash when loading ./submodule_link.js
|
||||||
spawn(process.execPath,
|
spawn(process.execPath, [
|
||||||
flags.concat([
|
'--preserve-symlinks',
|
||||||
'--preserve-symlinks',
|
'--preserve-symlinks-main',
|
||||||
'--preserve-symlinks-main', entry_link_absolute_path,
|
entry_link_absolute_path,
|
||||||
]),
|
], { stdio: 'inherit' })
|
||||||
{ stdio: 'inherit' }).on('exit', (code) => {
|
.on('exit', (code) => {
|
||||||
assert.strictEqual(code, 0);
|
assert.strictEqual(code, 0);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// First test the commonjs module loader
|
// First test the commonjs module loader
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,28 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { mustCall } = require('../common');
|
const { mustCall } = require('../common');
|
||||||
const assert = require('assert');
|
|
||||||
const fixtures = require('../common/fixtures');
|
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',
|
describe('ESM: REPL runs', { concurrency: true }, () => {
|
||||||
], {
|
it((context, done) => {
|
||||||
cwd: fixtures.path('es-modules', 'pkgimports'),
|
const child = spawn(execPath, [
|
||||||
|
'--interactive',
|
||||||
|
], {
|
||||||
|
cwd: fixtures.path('es-modules', 'pkgimports'),
|
||||||
|
});
|
||||||
|
|
||||||
|
child.stdin.end(
|
||||||
|
'try{require("#test");await import("#test")}catch{process.exit(-1)}'
|
||||||
|
);
|
||||||
|
|
||||||
|
child.on('exit', mustCall((code) => {
|
||||||
|
assert.strictEqual(code, 0);
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
child.stdin.end(
|
|
||||||
'try{require("#test");await import("#test")}catch{process.exit(-1)}'
|
|
||||||
);
|
|
||||||
|
|
||||||
child.on('exit', mustCall((code) => {
|
|
||||||
assert.strictEqual(code, 0);
|
|
||||||
}));
|
|
||||||
|
|
|
||||||
|
|
@ -1,62 +1,79 @@
|
||||||
// Flags: --experimental-specifier-resolution=node
|
import { spawnPromisified } from '../common/index.mjs';
|
||||||
import { mustNotCall } from '../common/index.mjs';
|
import * as fixtures from '../common/fixtures.mjs';
|
||||||
import assert from 'assert';
|
import { match, strictEqual } from 'node:assert';
|
||||||
import path from 'path';
|
import { execPath } from 'node:process';
|
||||||
import { spawn } from 'child_process';
|
import { describe, it } from 'node:test';
|
||||||
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');
|
describe('ESM: specifier-resolution=node', { concurrency: true }, () => {
|
||||||
assert.strictEqual(module, 'module');
|
it(async () => {
|
||||||
assert.strictEqual(success, 'success');
|
const { code, stderr, stdout } = await spawnPromisified(execPath, [
|
||||||
assert.strictEqual(explicit, 'esm');
|
'--no-warnings',
|
||||||
assert.strictEqual(implicit, 'cjs');
|
'--experimental-specifier-resolution=node',
|
||||||
assert.strictEqual(implicitModule, 'cjs');
|
'--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'),
|
||||||
|
]);
|
||||||
|
|
||||||
async function main() {
|
strictEqual(stderr, '');
|
||||||
try {
|
strictEqual(stdout, '');
|
||||||
await import('../fixtures/es-module-specifiers/do-not-exist.js');
|
strictEqual(code, 0);
|
||||||
} 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);
|
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'),
|
||||||
|
]);
|
||||||
|
|
||||||
// Test path from command line arguments
|
match(stderr, /Cannot find module/);
|
||||||
[
|
strictEqual(stdout, '');
|
||||||
'package-type-commonjs',
|
strictEqual(code, 1);
|
||||||
'package-type-module',
|
});
|
||||||
'/',
|
|
||||||
'/index',
|
it('should throw when the omitted file extension is .mjs (legacy loader doesn\'t support it)', async () => {
|
||||||
].forEach((item) => {
|
const { code, stderr, stdout } = await spawnPromisified(execPath, [
|
||||||
const modulePath = path.join(
|
'--no-warnings',
|
||||||
fileURLToPath(import.meta.url),
|
'--experimental-specifier-resolution=node',
|
||||||
'../../fixtures/es-module-specifiers',
|
'--input-type=module',
|
||||||
item,
|
'--eval',
|
||||||
);
|
`import whatever from ${JSON.stringify(fixtures.fileURL('es-module-specifiers/implicit-main-type-commonjs'))};`,
|
||||||
[
|
]);
|
||||||
'--experimental-specifier-resolution',
|
|
||||||
'--es-module-specifier-resolution',
|
match(stderr, /ERR_MODULE_NOT_FOUND/);
|
||||||
].forEach((option) => {
|
strictEqual(stdout, '');
|
||||||
spawn(process.execPath,
|
strictEqual(code, 1);
|
||||||
[`${option}=node`, modulePath],
|
});
|
||||||
{ stdio: 'inherit' }).on('exit', (code) => {
|
|
||||||
assert.strictEqual(code, 0);
|
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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,16 @@
|
||||||
import { mustCall } from '../common/index.mjs';
|
import { spawnPromisified } from '../common/index.mjs';
|
||||||
import { path } from '../common/fixtures.mjs';
|
import { path } from '../common/fixtures.mjs';
|
||||||
import { match, notStrictEqual } from 'assert';
|
import { match, notStrictEqual } from 'node:assert';
|
||||||
import { spawn } from 'child_process';
|
import { execPath } from 'node:process';
|
||||||
import { execPath } from 'process';
|
import { describe, it } from 'node:test';
|
||||||
|
|
||||||
const child = spawn(execPath, [
|
|
||||||
path('es-module-loaders', 'syntax-error.mjs'),
|
|
||||||
]);
|
|
||||||
|
|
||||||
let stderr = '';
|
describe('ESM: importing a module with syntax error(s)', { concurrency: true }, () => {
|
||||||
child.stderr.setEncoding('utf8');
|
it('should throw', async () => {
|
||||||
child.stderr.on('data', (data) => {
|
const { code, stderr } = await spawnPromisified(execPath, [
|
||||||
stderr += data;
|
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:/);
|
|
||||||
}));
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
import '../common/index.mjs';
|
import { spawnPromisified } from '../common/index.mjs';
|
||||||
import assert from 'assert';
|
|
||||||
import child_process from 'child_process';
|
|
||||||
import fixtures from '../common/fixtures.js';
|
import fixtures from '../common/fixtures.js';
|
||||||
|
import assert from 'node:assert';
|
||||||
|
import { execPath } from 'node:process';
|
||||||
|
import { describe, it } from 'node:test';
|
||||||
|
|
||||||
|
|
||||||
const commonArgs = [
|
const commonArgs = [
|
||||||
'--no-warnings',
|
'--no-warnings',
|
||||||
|
|
@ -9,102 +11,117 @@ const commonArgs = [
|
||||||
'--eval',
|
'--eval',
|
||||||
];
|
];
|
||||||
|
|
||||||
{
|
describe('ESM: unsettled and rejected promises', { concurrency: true }, () => {
|
||||||
// Unresolved TLA promise, --eval
|
it('should exit for an unsettled TLA promise via --eval', async () => {
|
||||||
const { status, stdout, stderr } = child_process.spawnSync(
|
const { code, stderr, stdout } = await spawnPromisified(execPath, [
|
||||||
process.execPath,
|
...commonArgs,
|
||||||
[...commonArgs, 'await new Promise(() => {})'],
|
'await new Promise(() => {})',
|
||||||
{ encoding: 'utf8' });
|
]);
|
||||||
assert.deepStrictEqual([status, stdout, stderr], [13, '', '']);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
assert.strictEqual(stderr, '');
|
||||||
// Rejected TLA promise, --eval
|
assert.strictEqual(stdout, '');
|
||||||
const { status, stdout, stderr } = child_process.spawnSync(
|
assert.strictEqual(code, 13);
|
||||||
process.execPath,
|
});
|
||||||
[...commonArgs, 'await Promise.reject(new Error("Xyz"))'],
|
|
||||||
{ encoding: 'utf8' });
|
|
||||||
assert.deepStrictEqual([status, stdout], [1, '']);
|
|
||||||
assert.match(stderr, /Error: Xyz/);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
it('should throw for a rejected TLA promise via --eval', async () => {
|
||||||
// Unresolved TLA promise with explicit exit code, --eval
|
// Rejected TLA promise, --eval
|
||||||
const { status, stdout, stderr } = child_process.spawnSync(
|
const { code, stderr, stdout } = await spawnPromisified(execPath, [
|
||||||
process.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,
|
...commonArgs,
|
||||||
'process.exitCode = 42;await new Promise(() => {})',
|
'process.exitCode = 42;await new Promise(() => {})',
|
||||||
],
|
]);
|
||||||
{ encoding: 'utf8' });
|
|
||||||
assert.deepStrictEqual([status, stdout, stderr], [42, '', '']);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
assert.strictEqual(stderr, '');
|
||||||
// Rejected TLA promise with explicit exit code, --eval
|
assert.strictEqual(stdout, '');
|
||||||
const { status, stdout, stderr } = child_process.spawnSync(
|
assert.strictEqual(code, 42);
|
||||||
process.execPath,
|
});
|
||||||
[
|
|
||||||
|
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,
|
...commonArgs,
|
||||||
'process.exitCode = 42;await Promise.reject(new Error("Xyz"))',
|
'process.exitCode = 42;await Promise.reject(new Error("Xyz"))',
|
||||||
],
|
]);
|
||||||
{ encoding: 'utf8' });
|
|
||||||
assert.deepStrictEqual([status, stdout], [1, '']);
|
|
||||||
assert.match(stderr, /Error: Xyz/);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
assert.match(stderr, /Error: Xyz/);
|
||||||
// Unresolved TLA promise, module file
|
assert.strictEqual(stdout, '');
|
||||||
const { status, stdout, stderr } = child_process.spawnSync(
|
assert.strictEqual(code, 1);
|
||||||
process.execPath,
|
});
|
||||||
['--no-warnings', fixtures.path('es-modules/tla/unresolved.mjs')],
|
|
||||||
{ encoding: 'utf8' });
|
|
||||||
assert.deepStrictEqual([status, stdout, stderr], [13, '', '']);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
it('should exit for an unsettled TLA promise via stdin', async () => {
|
||||||
// Rejected TLA promise, module file
|
const { code, stderr, stdout } = await spawnPromisified(execPath, [
|
||||||
const { status, stdout, stderr } = child_process.spawnSync(
|
'--no-warnings',
|
||||||
process.execPath,
|
fixtures.path('es-modules/tla/unresolved.mjs'),
|
||||||
['--no-warnings', fixtures.path('es-modules/tla/rejected.mjs')],
|
]);
|
||||||
{ encoding: 'utf8' });
|
|
||||||
assert.deepStrictEqual([status, stdout], [1, '']);
|
|
||||||
assert.match(stderr, /Error: Xyz/);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
assert.strictEqual(stderr, '');
|
||||||
// Unresolved TLA promise, module file
|
assert.strictEqual(stdout, '');
|
||||||
const { status, stdout, stderr } = child_process.spawnSync(
|
assert.strictEqual(code, 13);
|
||||||
process.execPath,
|
});
|
||||||
['--no-warnings', fixtures.path('es-modules/tla/unresolved-withexitcode.mjs')],
|
|
||||||
{ encoding: 'utf8' });
|
|
||||||
assert.deepStrictEqual([status, stdout, stderr], [42, '', '']);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
it('should throw for a rejected TLA promise via stdin', async () => {
|
||||||
// Rejected TLA promise, module file
|
const { code, stderr, stdout } = await spawnPromisified(execPath, [
|
||||||
const { status, stdout, stderr } = child_process.spawnSync(
|
'--no-warnings',
|
||||||
process.execPath,
|
fixtures.path('es-modules/tla/rejected.mjs'),
|
||||||
['--no-warnings', fixtures.path('es-modules/tla/rejected-withexitcode.mjs')],
|
]);
|
||||||
{ encoding: 'utf8' });
|
|
||||||
assert.deepStrictEqual([status, stdout], [1, '']);
|
|
||||||
assert.match(stderr, /Error: Xyz/);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
assert.match(stderr, /Error: Xyz/);
|
||||||
// Calling process.exit() in .mjs should return status 0
|
assert.strictEqual(stdout, '');
|
||||||
const { status, stdout, stderr } = child_process.spawnSync(
|
assert.strictEqual(code, 1);
|
||||||
process.execPath,
|
});
|
||||||
['--no-warnings', fixtures.path('es-modules/tla/process-exit.mjs')],
|
|
||||||
{ encoding: 'utf8' });
|
|
||||||
assert.deepStrictEqual([status, stdout, stderr], [0, '', '']);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
it('should exit for an unsettled TLA promise and respect explicit exit code via stdin', async () => {
|
||||||
// Calling process.exit() in worker thread shouldn't influence main thread
|
const { code, stderr, stdout } = await spawnPromisified(execPath, [
|
||||||
const { status, stdout, stderr } = child_process.spawnSync(
|
'--no-warnings',
|
||||||
process.execPath,
|
fixtures.path('es-modules/tla/unresolved-withexitcode.mjs'),
|
||||||
['--no-warnings', fixtures.path('es-modules/tla/unresolved-with-worker-process-exit.mjs')],
|
]);
|
||||||
{ encoding: 'utf8' });
|
|
||||||
assert.deepStrictEqual([status, stdout, stderr], [13, '', '']);
|
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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,40 +1,36 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const common = require('../common');
|
const { spawnPromisified } = require('../common');
|
||||||
const fixtures = require('../common/fixtures');
|
const fixtures = require('../common/fixtures.js');
|
||||||
const { spawn } = require('child_process');
|
const assert = require('node:assert');
|
||||||
const assert = require('assert');
|
const { execPath } = require('node:process');
|
||||||
|
const { describe, it } = require('node:test');
|
||||||
|
|
||||||
|
|
||||||
// In a "type": "module" package scope, files with unknown extensions or no
|
// 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
|
// extensions should throw; both when used as a main entry point and also when
|
||||||
// referenced via `import`.
|
// 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]);
|
||||||
|
|
||||||
[
|
assert.strictEqual(code, 1);
|
||||||
'/es-modules/package-type-module/noext-esm',
|
assert.strictEqual(signal, null);
|
||||||
'/es-modules/package-type-module/imports-noext.mjs',
|
assert.strictEqual(stdout, '');
|
||||||
'/es-modules/package-type-module/extension.unknown',
|
assert.ok(stderr.includes('ERR_UNKNOWN_FILE_EXTENSION'));
|
||||||
'/es-modules/package-type-module/imports-unknownext.mjs',
|
if (fixturePath.includes('noext')) {
|
||||||
].forEach((fixturePath) => {
|
// Check for explanation to users
|
||||||
const entry = fixtures.path(fixturePath);
|
assert.ok(stderr.includes('extensionless'));
|
||||||
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'));
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,37 +1,43 @@
|
||||||
// Flags: --experimental-wasm-modules
|
import { spawnPromisified } from '../common/index.mjs';
|
||||||
import '../common/index.mjs';
|
import * as fixtures from '../common/fixtures.mjs';
|
||||||
import { path } from '../common/fixtures.mjs';
|
import { strictEqual, match } from 'node:assert';
|
||||||
import { add, addImported } from '../fixtures/es-modules/simple.wasm';
|
import { execPath } from 'node:process';
|
||||||
import { state } from '../fixtures/es-modules/wasm-dep.mjs';
|
import { describe, it } from 'node:test';
|
||||||
import { strictEqual, ok } from 'assert';
|
|
||||||
import { spawn } from 'child_process';
|
|
||||||
|
|
||||||
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);
|
strictEqual(code, 0);
|
||||||
|
strictEqual(signal, null);
|
||||||
// Test warning message
|
match(stderr, /ExperimentalWarning/);
|
||||||
const child = spawn(process.execPath, [
|
match(stderr, /WebAssembly/);
|
||||||
'--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'
|
|
||||||
));
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,48 +1,48 @@
|
||||||
import { mustCall } from '../common/index.mjs';
|
import { mustCall, spawnPromisified } from '../common/index.mjs';
|
||||||
import { match, notStrictEqual } from 'assert';
|
import { ok, match, notStrictEqual } from 'node:assert';
|
||||||
import { spawn } from 'child_process';
|
import { spawn as spawnAsync } from 'node:child_process';
|
||||||
import { execPath } from 'process';
|
import { execPath } from 'node:process';
|
||||||
|
import { describe, it } from 'node:test';
|
||||||
|
|
||||||
{
|
|
||||||
const child = spawn(execPath, [
|
|
||||||
'--experimental-network-imports',
|
|
||||||
'--input-type=module',
|
|
||||||
'-e',
|
|
||||||
'import "http://example.com"',
|
|
||||||
]);
|
|
||||||
|
|
||||||
let stderr = '';
|
describe('ESM: http import via CLI', { concurrency: true }, () => {
|
||||||
child.stderr.setEncoding('utf8');
|
const disallowedSpecifier = 'http://example.com';
|
||||||
child.stderr.on('data', (data) => {
|
|
||||||
stderr += data;
|
it('should throw disallowed error for insecure protocol', async () => {
|
||||||
});
|
const { code, stderr } = await spawnPromisified(execPath, [
|
||||||
child.on('close', mustCall((code, _signal) => {
|
'--experimental-network-imports',
|
||||||
|
'--input-type=module',
|
||||||
|
'--eval',
|
||||||
|
`import ${JSON.stringify(disallowedSpecifier)}`,
|
||||||
|
]);
|
||||||
|
|
||||||
notStrictEqual(code, 0);
|
notStrictEqual(code, 0);
|
||||||
|
|
||||||
// [ERR_NETWORK_IMPORT_DISALLOWED]: import of 'http://example.com/' by
|
// [ERR_NETWORK_IMPORT_DISALLOWED]: import of 'http://example.com/' by
|
||||||
// …/[eval1] is not supported: http can only be used to load local
|
// …/[eval1] is not supported: http can only be used to load local
|
||||||
// resources (use https instead).
|
// resources (use https instead).
|
||||||
match(stderr, /[ERR_NETWORK_IMPORT_DISALLOWED]/);
|
match(stderr, /ERR_NETWORK_IMPORT_DISALLOWED/);
|
||||||
}));
|
ok(stderr.includes(disallowedSpecifier));
|
||||||
}
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
});
|
});
|
||||||
child.on('close', mustCall((code, _signal) => {
|
|
||||||
notStrictEqual(code, 0);
|
|
||||||
|
|
||||||
// [ERR_NETWORK_IMPORT_DISALLOWED]: import of 'http://example.com/' by
|
it('should throw disallowed error for insecure protocol in REPL', () => {
|
||||||
// …/[stdin] is not supported: http can only be used to load local
|
const child = spawnAsync(execPath, [
|
||||||
// resources (use https instead).
|
'--experimental-network-imports',
|
||||||
match(stderr, /[ERR_NETWORK_IMPORT_DISALLOWED]/);
|
'--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));
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,14 @@ const JSON_URL_PATTERN = /\.json(\?[^#]*)?(#.*)?$/;
|
||||||
export function resolve(url, context, next) {
|
export function resolve(url, context, next) {
|
||||||
// Mutation from resolve hook should be discarded.
|
// Mutation from resolve hook should be discarded.
|
||||||
context.importAssertions.type = 'whatever';
|
context.importAssertions.type = 'whatever';
|
||||||
return next(url, context);
|
return next(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function load(url, context, next) {
|
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))) {
|
(DATA_URL_PATTERN.test(url) || JSON_URL_PATTERN.test(url))) {
|
||||||
const { importAssertions } = context;
|
const { importAssertions } = context;
|
||||||
importAssertions.type = 'json';
|
importAssertions.type = 'json';
|
||||||
}
|
}
|
||||||
return next(url, context);
|
return next(url);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ export function load(url, context, next) {
|
||||||
format: 'module',
|
format: 'module',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return next(url, context);
|
return next(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateBuiltinModule(builtinName) {
|
function generateBuiltinModule(builtinName) {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ const JS_EXTENSIONS = new Set(['.js', '.mjs']);
|
||||||
const baseURL = new URL('file://');
|
const baseURL = new URL('file://');
|
||||||
baseURL.pathname = process.cwd() + '/';
|
baseURL.pathname = process.cwd() + '/';
|
||||||
|
|
||||||
export function resolve(specifier, { parentURL = baseURL }, defaultResolve) {
|
export function resolve(specifier, { parentURL = baseURL }, next) {
|
||||||
if (builtinModules.includes(specifier)) {
|
if (builtinModules.includes(specifier)) {
|
||||||
return {
|
return {
|
||||||
shortCircuit: true,
|
shortCircuit: true,
|
||||||
|
|
@ -17,7 +17,7 @@ export function resolve(specifier, { parentURL = baseURL }, defaultResolve) {
|
||||||
}
|
}
|
||||||
if (/^\.{1,2}[/]/.test(specifier) !== true && !specifier.startsWith('file:')) {
|
if (/^\.{1,2}[/]/.test(specifier) !== true && !specifier.startsWith('file:')) {
|
||||||
// For node_modules support:
|
// For node_modules support:
|
||||||
// return defaultResolve(specifier, {parentURL}, defaultResolve);
|
// return next(specifier);
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`imports must be URLs or begin with './', or '../'; '${specifier}' does not`);
|
`imports must be URLs or begin with './', or '../'; '${specifier}' does not`);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ let importedCJS = 0;
|
||||||
global.getModuleTypeStats = () => { return {importedESM, importedCJS} };
|
global.getModuleTypeStats = () => { return {importedESM, importedCJS} };
|
||||||
|
|
||||||
export async function load(url, context, next) {
|
export async function load(url, context, next) {
|
||||||
return next(url, context, next);
|
return next(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function resolve(specifier, context, next) {
|
export async function resolve(specifier, context, next) {
|
||||||
|
|
|
||||||
|
|
@ -56,10 +56,10 @@ export function load(url, context, next) {
|
||||||
source: `export const message = 'Woohoo!'.toUpperCase();`,
|
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 = '';
|
let format = '';
|
||||||
|
|
||||||
if (specifier === 'esmHook/format.false') format = false;
|
if (specifier === 'esmHook/format.false') format = false;
|
||||||
|
|
@ -70,8 +70,8 @@ export function resolve(specifier, context, next) {
|
||||||
format,
|
format,
|
||||||
shortCircuit: true,
|
shortCircuit: true,
|
||||||
url: pathToFileURL(specifier).href,
|
url: pathToFileURL(specifier).href,
|
||||||
importAssertions: context.importAssertions,
|
importAssertions,
|
||||||
};
|
};
|
||||||
|
|
||||||
return next(specifier, context, next);
|
return next(specifier);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,19 +4,19 @@ export function getSource() {}
|
||||||
export function transformSource() {}
|
export function transformSource() {}
|
||||||
|
|
||||||
|
|
||||||
|
export function resolve(specifier, context, next) {
|
||||||
|
if (specifier === 'whatever') return {
|
||||||
|
url: specifier,
|
||||||
|
};
|
||||||
|
|
||||||
|
return next(specifier);
|
||||||
|
}
|
||||||
|
|
||||||
export function load(url, context, next) {
|
export function load(url, context, next) {
|
||||||
if (url === 'whatever') return {
|
if (url === 'whatever') return {
|
||||||
format: 'module',
|
format: 'module',
|
||||||
source: '',
|
source: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
return next(url, context, next);
|
return next(url);
|
||||||
}
|
|
||||||
|
|
||||||
export function resolve(specifier, context, next) {
|
|
||||||
if (specifier === 'whatever') return {
|
|
||||||
url: specifier,
|
|
||||||
};
|
|
||||||
|
|
||||||
return next(specifier, context, next);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ export function resolve(specifier, context, nextResolve) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return nextResolve(specifier, context);
|
return nextResolve(specifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function load(url, context, nextLoad) {
|
export function load(url, context, nextLoad) {
|
||||||
|
|
@ -36,5 +36,5 @@ export function load(url, context, nextLoad) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return nextLoad(url, context);
|
return nextLoad(url);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
@ -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') {
|
if (parentURL && specifier === '../fixtures/es-modules/test-esm-ok.mjs') {
|
||||||
return {
|
return {
|
||||||
shortCircuit: true,
|
shortCircuit: true,
|
||||||
url: 'file:///asdf',
|
url: 'file:///asdf',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return defaultResolve(specifier, {parentURL, importAssertions}, defaultResolve);
|
return next(specifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function load(url, context, next) {
|
export async function load(url, context, next) {
|
||||||
|
|
@ -16,5 +16,5 @@ export async function load(url, context, next) {
|
||||||
source: '',
|
source: '',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return next(url, context, next);
|
return next(url);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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') {
|
if (parentURL && specifier === '../fixtures/es-modules/test-esm-ok.mjs') {
|
||||||
return {
|
return {
|
||||||
shortCircuit: true,
|
shortCircuit: true,
|
||||||
|
|
@ -6,5 +6,5 @@ export async function resolve(specifier, { parentURL, importAssertions }, defaul
|
||||||
importAssertions,
|
importAssertions,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return defaultResolve(specifier, {parentURL, importAssertions}, defaultResolve);
|
return next(specifier);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
export async function load(url, context, next) {
|
export async function load(url, context, next) {
|
||||||
return next([], context);
|
return next([]);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
export async function load(url, context, next) {
|
export async function load(url, context, next) {
|
||||||
return next('not/a/url', context);
|
return next('not/a/url');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ export async function load(url, context, next) {
|
||||||
const {
|
const {
|
||||||
format,
|
format,
|
||||||
source,
|
source,
|
||||||
} = await next(url, context);
|
} = await next(url);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
format,
|
format,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
export async function load(url, context, next) {
|
export async function load(url, context, next) {
|
||||||
console.log('load passthru'); // This log is deliberate
|
console.log('load passthru'); // This log is deliberate
|
||||||
return next(url, context);
|
return next(url);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
export async function resolve(specifier, context, next) {
|
export async function resolve(specifier, context, next) {
|
||||||
return next([], context);
|
return next([]);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
export async function resolve(specifier, context, next) {
|
export async function resolve(specifier, context, next) {
|
||||||
console.log('resolve foo'); // This log is deliberate
|
console.log('resolve foo'); // This log is deliberate
|
||||||
return next('file:///foo.mjs', context);
|
return next('file:///foo.mjs');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
export async function resolve(specifier, context, next) {
|
export async function resolve(specifier, context, next) {
|
||||||
const { url: first } = await next(specifier, context);
|
const { url: first } = await next(specifier);
|
||||||
const { url: second } = await next(specifier, context);
|
const { url: second } = await next(specifier);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
format: 'module',
|
format: 'module',
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
export async function resolve(specifier, context, next) {
|
export async function resolve(specifier, context, next) {
|
||||||
console.log('resolve passthru'); // This log is deliberate
|
console.log('resolve passthru'); // This log is deliberate
|
||||||
return next(specifier, context);
|
return next(specifier);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import { createRequire } from '../../common/index.mjs';
|
||||||
const require = createRequire(import.meta.url);
|
const require = createRequire(import.meta.url);
|
||||||
const dep = require('./loader-dep.js');
|
const dep = require('./loader-dep.js');
|
||||||
|
|
||||||
export function resolve(specifier, { parentURL, importAssertions }, defaultResolve) {
|
export function resolve(specifier, context, next) {
|
||||||
assert.strictEqual(dep.format, 'module');
|
assert.strictEqual(dep.format, 'module');
|
||||||
return defaultResolve(specifier, { parentURL, importAssertions }, defaultResolve);
|
return next(specifier);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,5 +3,5 @@ export function resolve(specifier, context, next) {
|
||||||
url: 'node:unknown-builtin-module'
|
url: 'node:unknown-builtin-module'
|
||||||
};
|
};
|
||||||
|
|
||||||
return next(specifier, context, next);
|
return next(specifier);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
export function resolve(specifier, { parentURL }, defaultResolve) {
|
export function resolve(specifier, context, next) {
|
||||||
if (specifier === 'test') {
|
if (specifier === 'test') {
|
||||||
return {
|
return {
|
||||||
url: 'file://'
|
url: 'file://'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return defaultResolve(specifier, {parentURL}, defaultResolve);
|
return next(specifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFormat(url, context, defaultGetFormat) {
|
export function getFormat(url, context, defaultGetFormat) {
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
import assert from 'assert';
|
import assert from 'node:assert';
|
||||||
|
|
||||||
// a loader that asserts that the defaultResolve will throw "not found"
|
// a loader that asserts that the defaultResolve will throw "not found"
|
||||||
// (skipping the top-level main of course)
|
// (skipping the top-level main of course)
|
||||||
let mainLoad = true;
|
let mainLoad = true;
|
||||||
export async function resolve(specifier, { parentURL, importAssertions }, defaultResolve) {
|
export async function resolve(specifier, { importAssertions }, next) {
|
||||||
if (mainLoad) {
|
if (mainLoad) {
|
||||||
mainLoad = false;
|
mainLoad = false;
|
||||||
return defaultResolve(specifier, {parentURL, importAssertions}, defaultResolve);
|
return next(specifier);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await defaultResolve(specifier, {parentURL, importAssertions}, defaultResolve);
|
await next(specifier);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
assert.strictEqual(e.code, 'ERR_MODULE_NOT_FOUND');
|
assert.strictEqual(e.code, 'ERR_MODULE_NOT_FOUND');
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ export function resolve(specifier, context, next) {
|
||||||
url: specifier,
|
url: specifier,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return next(specifier, context);
|
return next(specifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function load(href, context, next) {
|
export function load(href, context, next) {
|
||||||
|
|
@ -39,5 +39,5 @@ export function load(href, context, next) {
|
||||||
source: SOURCES[href],
|
source: SOURCES[href],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return next(href, context);
|
return next(href);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user