Skip to content

Commit

Permalink
esm: rewrite loader hooks test
Browse files Browse the repository at this point in the history
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: #46016
Reviewed-By: Antoine du Hamel <[email protected]>
Reviewed-By: Jacob Smith <[email protected]>
  • Loading branch information
GeoffreyBooth authored and juanarbol committed Jan 31, 2023
1 parent c1cc1f9 commit 0bdf2db
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 81 deletions.
105 changes: 24 additions & 81 deletions test/es-module/test-esm-loader-hooks.mjs
Original file line number Diff line number Diff line change
@@ -1,83 +1,26 @@
// Flags: --expose-internals
import { mustCall } from '../common/index.mjs';
import esmLoaderModule from 'internal/modules/esm/loader';
import assert from 'assert';

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',
]);
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,
};
}

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',
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', () => {
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(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;
}
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}/);
});
});
91 changes: 91 additions & 0 deletions test/fixtures/es-module-loaders/hooks-input.mjs
Original file line number Diff line number Diff line change
@@ -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;
}

0 comments on commit 0bdf2db

Please sign in to comment.