-
Notifications
You must be signed in to change notification settings - Fork 30.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 <duhamelantoine1995@gmail.com> Reviewed-By: Jacob Smith <jacob@frende.me>
- Loading branch information
1 parent
c1cc1f9
commit 0bdf2db
Showing
2 changed files
with
115 additions
and
81 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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}/); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |