mirror of
https://github.com/zebrajr/node.git
synced 2026-01-15 12:15:26 +00:00
esm: rewrite loader hooks test
Rewrite the test that validates that custom loader hooks are called from being a test that depends on internals to one that spawns a child process and checks its output to confirm expected behavior. PR-URL: https://github.com/nodejs/node/pull/46016 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Jacob Smith <jacob@frende.me>
This commit is contained in:
@@ -1,83 +1,26 @@
|
||||
// Flags: --expose-internals
|
||||
import { mustCall } from '../common/index.mjs';
|
||||
import esmLoaderModule from 'internal/modules/esm/loader';
|
||||
import assert from 'assert';
|
||||
import { spawnPromisified } from '../common/index.mjs';
|
||||
import * as fixtures from '../common/fixtures.mjs';
|
||||
import assert from 'node:assert';
|
||||
import { execPath } from 'node:process';
|
||||
import { describe, it } from 'node:test';
|
||||
|
||||
const { ESMLoader } = esmLoaderModule;
|
||||
|
||||
/**
|
||||
* Verify custom hooks are called with appropriate arguments.
|
||||
*/
|
||||
{
|
||||
const esmLoader = new ESMLoader();
|
||||
|
||||
const originalSpecifier = 'foo/bar';
|
||||
const importAssertions = {
|
||||
__proto__: null,
|
||||
type: 'json',
|
||||
};
|
||||
const parentURL = 'file:///entrypoint.js';
|
||||
const resolvedURL = 'file:///foo/bar.js';
|
||||
const suggestedFormat = 'test';
|
||||
|
||||
function resolve(specifier, context, defaultResolve) {
|
||||
assert.strictEqual(specifier, originalSpecifier);
|
||||
// Ensure `context` has all and only the properties it's supposed to
|
||||
assert.deepStrictEqual(Object.keys(context), [
|
||||
'conditions',
|
||||
'importAssertions',
|
||||
'parentURL',
|
||||
describe('Loader hooks', () => {
|
||||
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.ok(Array.isArray(context.conditions));
|
||||
assert.deepStrictEqual(context.importAssertions, importAssertions);
|
||||
assert.strictEqual(context.parentURL, parentURL);
|
||||
assert.strictEqual(typeof defaultResolve, 'function');
|
||||
|
||||
return {
|
||||
format: suggestedFormat,
|
||||
shortCircuit: true,
|
||||
url: resolvedURL,
|
||||
};
|
||||
}
|
||||
assert.strictEqual(stderr, '');
|
||||
assert.strictEqual(code, 0);
|
||||
assert.strictEqual(signal, null);
|
||||
|
||||
function load(resolvedURL, context, defaultLoad) {
|
||||
assert.strictEqual(resolvedURL, resolvedURL);
|
||||
assert.ok(new URL(resolvedURL));
|
||||
// Ensure `context` has all and only the properties it's supposed to
|
||||
assert.deepStrictEqual(Object.keys(context), [
|
||||
'format',
|
||||
'importAssertions',
|
||||
]);
|
||||
assert.strictEqual(context.format, suggestedFormat);
|
||||
assert.deepStrictEqual(context.importAssertions, importAssertions);
|
||||
assert.strictEqual(typeof defaultLoad, 'function');
|
||||
|
||||
// This doesn't matter (just to avoid errors)
|
||||
return {
|
||||
format: 'module',
|
||||
shortCircuit: true,
|
||||
source: '',
|
||||
};
|
||||
}
|
||||
|
||||
const customLoader = [
|
||||
{
|
||||
exports: {
|
||||
// Ensure ESMLoader actually calls the custom hooks
|
||||
resolve: mustCall(resolve),
|
||||
load: mustCall(load),
|
||||
},
|
||||
url: import.meta.url,
|
||||
},
|
||||
];
|
||||
|
||||
esmLoader.addCustomLoaders(customLoader);
|
||||
|
||||
// Manually trigger hooks (since ESMLoader is not actually running)
|
||||
const job = await esmLoader.getModuleJob(
|
||||
originalSpecifier,
|
||||
parentURL,
|
||||
importAssertions,
|
||||
);
|
||||
await job.modulePromise;
|
||||
}
|
||||
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}/);
|
||||
});
|
||||
});
|
||||
|
||||
91
test/fixtures/es-module-loaders/hooks-input.mjs
vendored
Normal file
91
test/fixtures/es-module-loaders/hooks-input.mjs
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
// This is expected to be used by test-esm-loader-hooks.mjs via:
|
||||
// node --loader ./test/fixtures/es-module-loaders/hooks-input.mjs ./test/fixtures/es-modules/json-modules.mjs
|
||||
|
||||
import assert from 'assert';
|
||||
import { readFile } from 'fs/promises';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
|
||||
let resolveCalls = 0;
|
||||
let loadCalls = 0;
|
||||
|
||||
export async function resolve(specifier, context, next) {
|
||||
resolveCalls++;
|
||||
let url;
|
||||
|
||||
if (resolveCalls === 1) {
|
||||
url = new URL(specifier).href;
|
||||
assert.match(specifier, /json-modules\.mjs$/);
|
||||
assert.strictEqual(context.parentURL, undefined);
|
||||
assert.deepStrictEqual(context.importAssertions, {
|
||||
__proto__: null,
|
||||
});
|
||||
} else if (resolveCalls === 2) {
|
||||
url = new URL(specifier, context.parentURL).href;
|
||||
assert.match(specifier, /experimental\.json$/);
|
||||
assert.match(context.parentURL, /json-modules\.mjs$/);
|
||||
assert.deepStrictEqual(context.importAssertions, {
|
||||
__proto__: null,
|
||||
type: 'json',
|
||||
});
|
||||
}
|
||||
|
||||
// Ensure `context` has all and only the properties it's supposed to
|
||||
assert.deepStrictEqual(Reflect.ownKeys(context), [
|
||||
'conditions',
|
||||
'importAssertions',
|
||||
'parentURL',
|
||||
]);
|
||||
assert.ok(Array.isArray(context.conditions));
|
||||
assert.strictEqual(typeof next, 'function');
|
||||
|
||||
const returnValue = {
|
||||
url,
|
||||
format: 'test',
|
||||
shortCircuit: true,
|
||||
}
|
||||
|
||||
console.log(JSON.stringify(returnValue)); // For the test to validate when it parses stdout
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
export async function load(url, context, next) {
|
||||
loadCalls++;
|
||||
const source = await readFile(fileURLToPath(url));
|
||||
let format;
|
||||
|
||||
if (loadCalls === 1) {
|
||||
assert.match(url, /json-modules\.mjs$/);
|
||||
assert.deepStrictEqual(context.importAssertions, {
|
||||
__proto__: null,
|
||||
});
|
||||
format = 'module';
|
||||
} else if (loadCalls === 2) {
|
||||
assert.match(url, /experimental\.json$/);
|
||||
assert.deepStrictEqual(context.importAssertions, {
|
||||
__proto__: null,
|
||||
type: 'json',
|
||||
});
|
||||
format = 'json';
|
||||
}
|
||||
|
||||
assert.ok(new URL(url));
|
||||
// Ensure `context` has all and only the properties it's supposed to
|
||||
assert.deepStrictEqual(Object.keys(context), [
|
||||
'format',
|
||||
'importAssertions',
|
||||
]);
|
||||
assert.strictEqual(context.format, 'test');
|
||||
assert.strictEqual(typeof next, 'function');
|
||||
|
||||
const returnValue = {
|
||||
source,
|
||||
format,
|
||||
shortCircuit: true,
|
||||
};
|
||||
|
||||
console.log(JSON.stringify(returnValue)); // For the test to validate when it parses stdout
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
Reference in New Issue
Block a user