node/test/es-module/test-esm-loader-hooks.mjs
Antoine du Hamel 841f6b3abf
esm: increase test coverage of edge cases
PR-URL: https://github.com/nodejs/node/pull/47033
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
Reviewed-By: Jacob Smith <jacob@frende.me>
2023-03-31 16:27:43 +00:00

199 lines
7.6 KiB
JavaScript

import { spawnPromisified } from '../common/index.mjs';
import * as fixtures from '../common/fixtures.mjs';
import assert from 'node:assert';
import { execPath } from 'node:process';
import { describe, it } from 'node:test';
describe('Loader hooks', { concurrency: true }, () => {
it('are called with all expected arguments', async () => {
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-loader',
fixtures.fileURL('/es-module-loaders/hooks-input.mjs'),
fixtures.path('/es-modules/json-modules.mjs'),
]);
assert.strictEqual(stderr, '');
assert.strictEqual(code, 0);
assert.strictEqual(signal, null);
const lines = stdout.split('\n');
assert.match(lines[0], /{"url":"file:\/\/\/.*\/json-modules\.mjs","format":"test","shortCircuit":true}/);
assert.match(lines[1], /{"source":{"type":"Buffer","data":\[.*\]},"format":"module","shortCircuit":true}/);
assert.match(lines[2], /{"url":"file:\/\/\/.*\/experimental\.json","format":"test","shortCircuit":true}/);
assert.match(lines[3], /{"source":{"type":"Buffer","data":\[.*\]},"format":"json","shortCircuit":true}/);
});
describe('should handle never-settling hooks in ESM files', { concurrency: true }, () => {
it('top-level await of a never-settling resolve', async () => {
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-loader',
fixtures.fileURL('es-module-loaders/never-settling-resolve-step/loader.mjs'),
fixtures.path('es-module-loaders/never-settling-resolve-step/never-resolve.mjs'),
]);
assert.strictEqual(stderr, '');
assert.match(stdout, /^should be output\r?\n$/);
assert.strictEqual(code, 13);
assert.strictEqual(signal, null);
});
it('top-level await of a never-settling load', async () => {
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-loader',
fixtures.fileURL('es-module-loaders/never-settling-resolve-step/loader.mjs'),
fixtures.path('es-module-loaders/never-settling-resolve-step/never-load.mjs'),
]);
assert.strictEqual(stderr, '');
assert.match(stdout, /^should be output\r?\n$/);
assert.strictEqual(code, 13);
assert.strictEqual(signal, null);
});
it('top-level await of a race of never-settling hooks', async () => {
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-loader',
fixtures.fileURL('es-module-loaders/never-settling-resolve-step/loader.mjs'),
fixtures.path('es-module-loaders/never-settling-resolve-step/race.mjs'),
]);
assert.strictEqual(stderr, '');
assert.match(stdout, /^true\r?\n$/);
assert.strictEqual(code, 0);
assert.strictEqual(signal, null);
});
it('import.meta.resolve of a never-settling resolve', async () => {
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-import-meta-resolve',
'--experimental-loader',
fixtures.fileURL('es-module-loaders/never-settling-resolve-step/loader.mjs'),
fixtures.path('es-module-loaders/never-settling-resolve-step/import.meta.never-resolve.mjs'),
]);
assert.strictEqual(stderr, '');
assert.match(stdout, /^should be output\r?\n$/);
assert.strictEqual(code, 13);
assert.strictEqual(signal, null);
});
});
describe('should handle never-settling hooks in CJS files', { concurrency: true }, () => {
it('never-settling resolve', async () => {
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-loader',
fixtures.fileURL('es-module-loaders/never-settling-resolve-step/loader.mjs'),
fixtures.path('es-module-loaders/never-settling-resolve-step/never-resolve.cjs'),
]);
assert.strictEqual(stderr, '');
assert.match(stdout, /^should be output\r?\n$/);
assert.strictEqual(code, 0);
assert.strictEqual(signal, null);
});
it('never-settling load', async () => {
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-loader',
fixtures.fileURL('es-module-loaders/never-settling-resolve-step/loader.mjs'),
fixtures.path('es-module-loaders/never-settling-resolve-step/never-load.cjs'),
]);
assert.strictEqual(stderr, '');
assert.match(stdout, /^should be output\r?\n$/);
assert.strictEqual(code, 0);
assert.strictEqual(signal, null);
});
it('race of never-settling hooks', async () => {
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-loader',
fixtures.fileURL('es-module-loaders/never-settling-resolve-step/loader.mjs'),
fixtures.path('es-module-loaders/never-settling-resolve-step/race.cjs'),
]);
assert.strictEqual(stderr, '');
assert.match(stdout, /^true\r?\n$/);
assert.strictEqual(code, 0);
assert.strictEqual(signal, null);
});
});
it('should work without worker permission', async () => {
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-permission',
'--allow-fs-read',
'*',
'--experimental-loader',
fixtures.fileURL('empty.js'),
fixtures.path('es-modules/esm-top-level-await.mjs'),
]);
assert.strictEqual(stderr, '');
assert.match(stdout, /^1\r?\n2\r?\n$/);
assert.strictEqual(code, 0);
assert.strictEqual(signal, null);
});
it('should allow loader hooks to spawn workers when allowed by the CLI flags', async () => {
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-permission',
'--allow-worker',
'--allow-fs-read',
'*',
'--experimental-loader',
`data:text/javascript,import{Worker}from"worker_threads";new Worker(${encodeURIComponent(JSON.stringify(fixtures.path('empty.js')))}).unref()`,
fixtures.path('es-modules/esm-top-level-await.mjs'),
]);
assert.strictEqual(stderr, '');
assert.match(stdout, /^1\r?\n2\r?\n$/);
assert.strictEqual(code, 0);
assert.strictEqual(signal, null);
});
it('should not allow loader hooks to spawn workers if restricted by the CLI flags', async () => {
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-permission',
'--allow-fs-read',
'*',
'--experimental-loader',
`data:text/javascript,import{Worker}from"worker_threads";new Worker(${encodeURIComponent(JSON.stringify(fixtures.path('empty.js')))}).unref()`,
fixtures.path('es-modules/esm-top-level-await.mjs'),
]);
assert.match(stderr, /code: 'ERR_ACCESS_DENIED'/);
assert.strictEqual(stdout, '');
assert.strictEqual(code, 1);
assert.strictEqual(signal, null);
});
it('should not leak internals or expose import.meta.resolve', async () => {
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-import-meta-resolve',
'--experimental-loader',
fixtures.fileURL('es-module-loaders/loader-edge-cases.mjs'),
fixtures.path('empty.js'),
]);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, '');
assert.strictEqual(code, 0);
assert.strictEqual(signal, null);
});
});