11cb0ef41Sopenharmony_ciimport { spawnPromisified } from '../common/index.mjs';
21cb0ef41Sopenharmony_ciimport * as fixtures from '../common/fixtures.js';
31cb0ef41Sopenharmony_ciimport assert from 'node:assert';
41cb0ef41Sopenharmony_ciimport { execPath } from 'node:process';
51cb0ef41Sopenharmony_ciimport { describe, it } from 'node:test';
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci// This test ensures that the register function can register loaders
81cb0ef41Sopenharmony_ci// programmatically.
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ciconst commonArgs = [
111cb0ef41Sopenharmony_ci  '--no-warnings',
121cb0ef41Sopenharmony_ci  '--input-type=module',
131cb0ef41Sopenharmony_ci  '--loader=data:text/javascript,',
141cb0ef41Sopenharmony_ci];
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_ciconst commonEvals = {
171cb0ef41Sopenharmony_ci  import: (module) => `await import(${JSON.stringify(module)});`,
181cb0ef41Sopenharmony_ci  register: (loader, parentURL = 'file:///') => `register(${JSON.stringify(loader)}, ${JSON.stringify(parentURL)});`,
191cb0ef41Sopenharmony_ci  dynamicImport: (module) => `await import(${JSON.stringify(`data:text/javascript,${encodeURIComponent(module)}`)});`,
201cb0ef41Sopenharmony_ci  staticImport: (module) => `import ${JSON.stringify(`data:text/javascript,${encodeURIComponent(module)}`)};`,
211cb0ef41Sopenharmony_ci};
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_cidescribe('ESM: programmatically register loaders', { concurrency: true }, () => {
241cb0ef41Sopenharmony_ci  it('works with only a dummy CLI argument', async () => {
251cb0ef41Sopenharmony_ci    const parentURL = fixtures.fileURL('es-module-loaders', 'loader-resolve-passthru.mjs');
261cb0ef41Sopenharmony_ci    const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
271cb0ef41Sopenharmony_ci      ...commonArgs,
281cb0ef41Sopenharmony_ci      '--eval',
291cb0ef41Sopenharmony_ci      "import { register } from 'node:module';" +
301cb0ef41Sopenharmony_ci      commonEvals.register(fixtures.fileURL('es-module-loaders', 'loader-resolve-passthru.mjs')) +
311cb0ef41Sopenharmony_ci      commonEvals.register(fixtures.fileURL('es-module-loaders', 'loader-load-passthru.mjs')) +
321cb0ef41Sopenharmony_ci      `register(${JSON.stringify('./loader-resolve-passthru.mjs')}, ${JSON.stringify({ parentURL })});` +
331cb0ef41Sopenharmony_ci      `register(${JSON.stringify('./loader-load-passthru.mjs')}, ${JSON.stringify({ parentURL })});` +
341cb0ef41Sopenharmony_ci      commonEvals.dynamicImport('console.log("Hello from dynamic import");'),
351cb0ef41Sopenharmony_ci    ]);
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ci    assert.strictEqual(stderr, '');
381cb0ef41Sopenharmony_ci    assert.strictEqual(code, 0);
391cb0ef41Sopenharmony_ci    assert.strictEqual(signal, null);
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_ci    const lines = stdout.split('\n');
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ci    assert.match(lines[0], /resolve passthru/);
441cb0ef41Sopenharmony_ci    assert.match(lines[1], /resolve passthru/);
451cb0ef41Sopenharmony_ci    assert.match(lines[2], /load passthru/);
461cb0ef41Sopenharmony_ci    assert.match(lines[3], /load passthru/);
471cb0ef41Sopenharmony_ci    assert.match(lines[4], /Hello from dynamic import/);
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_ci    assert.strictEqual(lines[5], '');
501cb0ef41Sopenharmony_ci  });
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ci  describe('registering via --import', { concurrency: true }, () => {
531cb0ef41Sopenharmony_ci    for (const moduleType of ['mjs', 'cjs']) {
541cb0ef41Sopenharmony_ci      it(`should programmatically register a loader from a ${moduleType.toUpperCase()} file`, async () => {
551cb0ef41Sopenharmony_ci        const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
561cb0ef41Sopenharmony_ci          ...commonArgs,
571cb0ef41Sopenharmony_ci          '--import', fixtures.fileURL('es-module-loaders', `register-loader.${moduleType}`).href,
581cb0ef41Sopenharmony_ci          '--eval', commonEvals.staticImport('console.log("entry point")'),
591cb0ef41Sopenharmony_ci        ]);
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci        assert.strictEqual(stderr, '');
621cb0ef41Sopenharmony_ci        assert.strictEqual(code, 0);
631cb0ef41Sopenharmony_ci        assert.strictEqual(signal, null);
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ci        const [
661cb0ef41Sopenharmony_ci          passthruStdout,
671cb0ef41Sopenharmony_ci          entryPointStdout,
681cb0ef41Sopenharmony_ci        ] = stdout.split('\n');
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_ci        assert.match(passthruStdout, /resolve passthru/);
711cb0ef41Sopenharmony_ci        assert.match(entryPointStdout, /entry point/);
721cb0ef41Sopenharmony_ci      });
731cb0ef41Sopenharmony_ci    }
741cb0ef41Sopenharmony_ci  });
751cb0ef41Sopenharmony_ci
761cb0ef41Sopenharmony_ci  it('programmatically registered loaders are appended to an existing chaining', async () => {
771cb0ef41Sopenharmony_ci    const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
781cb0ef41Sopenharmony_ci      ...commonArgs,
791cb0ef41Sopenharmony_ci      '--loader',
801cb0ef41Sopenharmony_ci      fixtures.fileURL('es-module-loaders', 'loader-resolve-passthru.mjs'),
811cb0ef41Sopenharmony_ci      '--eval',
821cb0ef41Sopenharmony_ci      "import { register } from 'node:module';" +
831cb0ef41Sopenharmony_ci      commonEvals.register(fixtures.fileURL('es-module-loaders', 'loader-load-passthru.mjs')) +
841cb0ef41Sopenharmony_ci      commonEvals.dynamicImport('console.log("Hello from dynamic import");'),
851cb0ef41Sopenharmony_ci    ]);
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci    assert.strictEqual(stderr, '');
881cb0ef41Sopenharmony_ci    assert.strictEqual(code, 0);
891cb0ef41Sopenharmony_ci    assert.strictEqual(signal, null);
901cb0ef41Sopenharmony_ci
911cb0ef41Sopenharmony_ci    const lines = stdout.split('\n');
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_ci    assert.match(lines[0], /resolve passthru/);
941cb0ef41Sopenharmony_ci    assert.match(lines[1], /resolve passthru/);
951cb0ef41Sopenharmony_ci    assert.match(lines[2], /load passthru/);
961cb0ef41Sopenharmony_ci    assert.match(lines[3], /Hello from dynamic import/);
971cb0ef41Sopenharmony_ci
981cb0ef41Sopenharmony_ci    assert.strictEqual(lines[4], '');
991cb0ef41Sopenharmony_ci  });
1001cb0ef41Sopenharmony_ci
1011cb0ef41Sopenharmony_ci  it('works registering loaders across files', async () => {
1021cb0ef41Sopenharmony_ci    const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
1031cb0ef41Sopenharmony_ci      ...commonArgs,
1041cb0ef41Sopenharmony_ci      '--eval',
1051cb0ef41Sopenharmony_ci      commonEvals.import(fixtures.fileURL('es-module-loaders', 'register-programmatically-loader-load.mjs')) +
1061cb0ef41Sopenharmony_ci      commonEvals.import(fixtures.fileURL('es-module-loaders', 'register-programmatically-loader-resolve.mjs')) +
1071cb0ef41Sopenharmony_ci      commonEvals.dynamicImport('console.log("Hello from dynamic import");'),
1081cb0ef41Sopenharmony_ci    ]);
1091cb0ef41Sopenharmony_ci
1101cb0ef41Sopenharmony_ci    assert.strictEqual(stderr, '');
1111cb0ef41Sopenharmony_ci    assert.strictEqual(code, 0);
1121cb0ef41Sopenharmony_ci    assert.strictEqual(signal, null);
1131cb0ef41Sopenharmony_ci
1141cb0ef41Sopenharmony_ci    const lines = stdout.split('\n');
1151cb0ef41Sopenharmony_ci
1161cb0ef41Sopenharmony_ci    assert.match(lines[0], /resolve passthru/);
1171cb0ef41Sopenharmony_ci    assert.match(lines[1], /load passthru/);
1181cb0ef41Sopenharmony_ci    assert.match(lines[2], /Hello from dynamic import/);
1191cb0ef41Sopenharmony_ci
1201cb0ef41Sopenharmony_ci    assert.strictEqual(lines[3], '');
1211cb0ef41Sopenharmony_ci  });
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci  it('works registering loaders across virtual files', async () => {
1241cb0ef41Sopenharmony_ci    const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
1251cb0ef41Sopenharmony_ci      ...commonArgs,
1261cb0ef41Sopenharmony_ci      '--eval',
1271cb0ef41Sopenharmony_ci      commonEvals.import(fixtures.fileURL('es-module-loaders', 'register-programmatically-loader-load.mjs')) +
1281cb0ef41Sopenharmony_ci      commonEvals.dynamicImport(
1291cb0ef41Sopenharmony_ci        commonEvals.import(fixtures.fileURL('es-module-loaders', 'register-programmatically-loader-resolve.mjs')) +
1301cb0ef41Sopenharmony_ci        commonEvals.dynamicImport('console.log("Hello from dynamic import");'),
1311cb0ef41Sopenharmony_ci      ),
1321cb0ef41Sopenharmony_ci    ]);
1331cb0ef41Sopenharmony_ci
1341cb0ef41Sopenharmony_ci    assert.strictEqual(stderr, '');
1351cb0ef41Sopenharmony_ci    assert.strictEqual(code, 0);
1361cb0ef41Sopenharmony_ci    assert.strictEqual(signal, null);
1371cb0ef41Sopenharmony_ci
1381cb0ef41Sopenharmony_ci    const lines = stdout.split('\n');
1391cb0ef41Sopenharmony_ci
1401cb0ef41Sopenharmony_ci    assert.match(lines[0], /resolve passthru/);
1411cb0ef41Sopenharmony_ci    assert.match(lines[1], /load passthru/);
1421cb0ef41Sopenharmony_ci    assert.match(lines[2], /Hello from dynamic import/);
1431cb0ef41Sopenharmony_ci
1441cb0ef41Sopenharmony_ci    assert.strictEqual(lines[3], '');
1451cb0ef41Sopenharmony_ci  });
1461cb0ef41Sopenharmony_ci
1471cb0ef41Sopenharmony_ci  it('works registering the same loaders more them once', async () => {
1481cb0ef41Sopenharmony_ci    const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
1491cb0ef41Sopenharmony_ci      ...commonArgs,
1501cb0ef41Sopenharmony_ci      '--eval',
1511cb0ef41Sopenharmony_ci      "import { register } from 'node:module';" +
1521cb0ef41Sopenharmony_ci      commonEvals.register(fixtures.fileURL('es-module-loaders', 'loader-resolve-passthru.mjs')) +
1531cb0ef41Sopenharmony_ci      commonEvals.register(fixtures.fileURL('es-module-loaders', 'loader-load-passthru.mjs')) +
1541cb0ef41Sopenharmony_ci      commonEvals.register(fixtures.fileURL('es-module-loaders', 'loader-resolve-passthru.mjs')) +
1551cb0ef41Sopenharmony_ci      commonEvals.register(fixtures.fileURL('es-module-loaders', 'loader-load-passthru.mjs')) +
1561cb0ef41Sopenharmony_ci      commonEvals.dynamicImport('console.log("Hello from dynamic import");'),
1571cb0ef41Sopenharmony_ci    ]);
1581cb0ef41Sopenharmony_ci
1591cb0ef41Sopenharmony_ci    assert.strictEqual(stderr, '');
1601cb0ef41Sopenharmony_ci    assert.strictEqual(code, 0);
1611cb0ef41Sopenharmony_ci    assert.strictEqual(signal, null);
1621cb0ef41Sopenharmony_ci
1631cb0ef41Sopenharmony_ci    const lines = stdout.split('\n');
1641cb0ef41Sopenharmony_ci
1651cb0ef41Sopenharmony_ci    assert.match(lines[0], /resolve passthru/);
1661cb0ef41Sopenharmony_ci    assert.match(lines[1], /resolve passthru/);
1671cb0ef41Sopenharmony_ci    assert.match(lines[2], /load passthru/);
1681cb0ef41Sopenharmony_ci    assert.match(lines[3], /load passthru/);
1691cb0ef41Sopenharmony_ci    assert.match(lines[4], /Hello from dynamic import/);
1701cb0ef41Sopenharmony_ci
1711cb0ef41Sopenharmony_ci    assert.strictEqual(lines[5], '');
1721cb0ef41Sopenharmony_ci  });
1731cb0ef41Sopenharmony_ci
1741cb0ef41Sopenharmony_ci  it('works registering loaders as package name', async () => {
1751cb0ef41Sopenharmony_ci    const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
1761cb0ef41Sopenharmony_ci      ...commonArgs,
1771cb0ef41Sopenharmony_ci      '--eval',
1781cb0ef41Sopenharmony_ci      "import { register } from 'node:module';" +
1791cb0ef41Sopenharmony_ci      commonEvals.register('resolve', fixtures.fileURL('es-module-loaders', 'package.json')) +
1801cb0ef41Sopenharmony_ci      commonEvals.register('load', fixtures.fileURL('es-module-loaders', 'package.json')) +
1811cb0ef41Sopenharmony_ci      commonEvals.dynamicImport('console.log("Hello from dynamic import");'),
1821cb0ef41Sopenharmony_ci    ]);
1831cb0ef41Sopenharmony_ci
1841cb0ef41Sopenharmony_ci    assert.strictEqual(stderr, '');
1851cb0ef41Sopenharmony_ci    assert.strictEqual(code, 0);
1861cb0ef41Sopenharmony_ci    assert.strictEqual(signal, null);
1871cb0ef41Sopenharmony_ci
1881cb0ef41Sopenharmony_ci    const lines = stdout.split('\n');
1891cb0ef41Sopenharmony_ci
1901cb0ef41Sopenharmony_ci    // Resolve occurs twice because it is first used to resolve the `load` loader
1911cb0ef41Sopenharmony_ci    // _AND THEN_ the `register` module.
1921cb0ef41Sopenharmony_ci    assert.match(lines[0], /resolve passthru/);
1931cb0ef41Sopenharmony_ci    assert.match(lines[1], /resolve passthru/);
1941cb0ef41Sopenharmony_ci    assert.match(lines[2], /load passthru/);
1951cb0ef41Sopenharmony_ci    assert.match(lines[3], /Hello from dynamic import/);
1961cb0ef41Sopenharmony_ci
1971cb0ef41Sopenharmony_ci    assert.strictEqual(lines[4], '');
1981cb0ef41Sopenharmony_ci  });
1991cb0ef41Sopenharmony_ci
2001cb0ef41Sopenharmony_ci  it('works without a CLI flag', async () => {
2011cb0ef41Sopenharmony_ci    const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
2021cb0ef41Sopenharmony_ci      '--no-warnings',
2031cb0ef41Sopenharmony_ci      '--input-type=module',
2041cb0ef41Sopenharmony_ci      '--eval',
2051cb0ef41Sopenharmony_ci      "import { register } from 'node:module';" +
2061cb0ef41Sopenharmony_ci      commonEvals.register(fixtures.fileURL('es-module-loaders', 'loader-load-passthru.mjs')) +
2071cb0ef41Sopenharmony_ci      commonEvals.dynamicImport('console.log("Hello from dynamic import");'),
2081cb0ef41Sopenharmony_ci    ]);
2091cb0ef41Sopenharmony_ci
2101cb0ef41Sopenharmony_ci    assert.strictEqual(stderr, '');
2111cb0ef41Sopenharmony_ci    assert.strictEqual(code, 0);
2121cb0ef41Sopenharmony_ci    assert.strictEqual(signal, null);
2131cb0ef41Sopenharmony_ci
2141cb0ef41Sopenharmony_ci    const lines = stdout.split('\n');
2151cb0ef41Sopenharmony_ci
2161cb0ef41Sopenharmony_ci    assert.match(lines[0], /load passthru/);
2171cb0ef41Sopenharmony_ci    assert.match(lines[1], /Hello from dynamic import/);
2181cb0ef41Sopenharmony_ci
2191cb0ef41Sopenharmony_ci    assert.strictEqual(lines[2], '');
2201cb0ef41Sopenharmony_ci  });
2211cb0ef41Sopenharmony_ci
2221cb0ef41Sopenharmony_ci  it('does not work with a loader specifier that does not exist', async () => {
2231cb0ef41Sopenharmony_ci    const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
2241cb0ef41Sopenharmony_ci      ...commonArgs,
2251cb0ef41Sopenharmony_ci      '--eval',
2261cb0ef41Sopenharmony_ci      "import { register } from 'node:module';" +
2271cb0ef41Sopenharmony_ci      commonEvals.register('./not-found.mjs', import.meta.url) +
2281cb0ef41Sopenharmony_ci      commonEvals.dynamicImport('console.log("Hello from dynamic import");'),
2291cb0ef41Sopenharmony_ci    ]);
2301cb0ef41Sopenharmony_ci
2311cb0ef41Sopenharmony_ci    assert.strictEqual(stdout, '');
2321cb0ef41Sopenharmony_ci    assert.strictEqual(code, 1);
2331cb0ef41Sopenharmony_ci    assert.strictEqual(signal, null);
2341cb0ef41Sopenharmony_ci    assert.match(stderr, /ERR_MODULE_NOT_FOUND/);
2351cb0ef41Sopenharmony_ci  });
2361cb0ef41Sopenharmony_ci
2371cb0ef41Sopenharmony_ci  it('does not work with a loader that got syntax errors', async () => {
2381cb0ef41Sopenharmony_ci    const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
2391cb0ef41Sopenharmony_ci      ...commonArgs,
2401cb0ef41Sopenharmony_ci      '--eval',
2411cb0ef41Sopenharmony_ci      "import { register } from 'node:module';" +
2421cb0ef41Sopenharmony_ci      commonEvals.register(fixtures.fileURL('es-module-loaders', 'syntax-error.mjs')) +
2431cb0ef41Sopenharmony_ci      commonEvals.dynamicImport('console.log("Hello from dynamic import");'),
2441cb0ef41Sopenharmony_ci    ]);
2451cb0ef41Sopenharmony_ci
2461cb0ef41Sopenharmony_ci    assert.strictEqual(stdout, '');
2471cb0ef41Sopenharmony_ci    assert.strictEqual(code, 1);
2481cb0ef41Sopenharmony_ci    assert.strictEqual(signal, null);
2491cb0ef41Sopenharmony_ci    assert.match(stderr, /SyntaxError/);
2501cb0ef41Sopenharmony_ci  });
2511cb0ef41Sopenharmony_ci});
252