11cb0ef41Sopenharmony_ciimport { spawnPromisified } from '../common/index.mjs';
21cb0ef41Sopenharmony_ciimport * as fixtures from '../common/fixtures.mjs';
31cb0ef41Sopenharmony_ciimport assert from 'node:assert';
41cb0ef41Sopenharmony_ciimport { execPath } from 'node:process';
51cb0ef41Sopenharmony_ciimport { describe, it } from 'node:test';
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_cidescribe('Loader hooks throwing errors', { concurrency: true }, () => {
81cb0ef41Sopenharmony_ci  it('throws on nonexistent modules', async () => {
91cb0ef41Sopenharmony_ci    const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
101cb0ef41Sopenharmony_ci      '--no-warnings',
111cb0ef41Sopenharmony_ci      '--experimental-loader',
121cb0ef41Sopenharmony_ci      fixtures.fileURL('/es-module-loaders/hooks-custom.mjs'),
131cb0ef41Sopenharmony_ci      '--input-type=module',
141cb0ef41Sopenharmony_ci      '--eval',
151cb0ef41Sopenharmony_ci      'import "nonexistent/file.mjs"',
161cb0ef41Sopenharmony_ci    ]);
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_ci    assert.match(stderr, /ERR_MODULE_NOT_FOUND/);
191cb0ef41Sopenharmony_ci    assert.strictEqual(stdout, '');
201cb0ef41Sopenharmony_ci    assert.strictEqual(code, 1);
211cb0ef41Sopenharmony_ci    assert.strictEqual(signal, null);
221cb0ef41Sopenharmony_ci  });
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_ci  it('throws on unknown extensions', async () => {
251cb0ef41Sopenharmony_ci    const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
261cb0ef41Sopenharmony_ci      '--no-warnings',
271cb0ef41Sopenharmony_ci      '--experimental-loader',
281cb0ef41Sopenharmony_ci      fixtures.fileURL('/es-module-loaders/hooks-custom.mjs'),
291cb0ef41Sopenharmony_ci      '--input-type=module',
301cb0ef41Sopenharmony_ci      '--eval',
311cb0ef41Sopenharmony_ci      `import ${JSON.stringify(fixtures.fileURL('/es-modules/file.unknown'))}`,
321cb0ef41Sopenharmony_ci    ]);
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_ci    assert.match(stderr, /ERR_UNKNOWN_FILE_EXTENSION/);
351cb0ef41Sopenharmony_ci    assert.strictEqual(stdout, '');
361cb0ef41Sopenharmony_ci    assert.strictEqual(code, 1);
371cb0ef41Sopenharmony_ci    assert.strictEqual(signal, null);
381cb0ef41Sopenharmony_ci  });
391cb0ef41Sopenharmony_ci
401cb0ef41Sopenharmony_ci  it('throws on invalid return values', async () => {
411cb0ef41Sopenharmony_ci    const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
421cb0ef41Sopenharmony_ci      '--no-warnings',
431cb0ef41Sopenharmony_ci      '--experimental-loader',
441cb0ef41Sopenharmony_ci      fixtures.fileURL('/es-module-loaders/hooks-custom.mjs'),
451cb0ef41Sopenharmony_ci      '--input-type=module',
461cb0ef41Sopenharmony_ci      '--eval',
471cb0ef41Sopenharmony_ci      'import "esmHook/badReturnVal.mjs"',
481cb0ef41Sopenharmony_ci    ]);
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_ci    assert.match(stderr, /ERR_INVALID_RETURN_VALUE/);
511cb0ef41Sopenharmony_ci    assert.strictEqual(stdout, '');
521cb0ef41Sopenharmony_ci    assert.strictEqual(code, 1);
531cb0ef41Sopenharmony_ci    assert.strictEqual(signal, null);
541cb0ef41Sopenharmony_ci  });
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ci  it('throws on boolean false', async () => {
571cb0ef41Sopenharmony_ci    const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
581cb0ef41Sopenharmony_ci      '--no-warnings',
591cb0ef41Sopenharmony_ci      '--experimental-loader',
601cb0ef41Sopenharmony_ci      fixtures.fileURL('/es-module-loaders/hooks-custom.mjs'),
611cb0ef41Sopenharmony_ci      '--input-type=module',
621cb0ef41Sopenharmony_ci      '--eval',
631cb0ef41Sopenharmony_ci      'import "esmHook/format.false"',
641cb0ef41Sopenharmony_ci    ]);
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ci    assert.match(stderr, /ERR_INVALID_RETURN_PROPERTY_VALUE/);
671cb0ef41Sopenharmony_ci    assert.strictEqual(stdout, '');
681cb0ef41Sopenharmony_ci    assert.strictEqual(code, 1);
691cb0ef41Sopenharmony_ci    assert.strictEqual(signal, null);
701cb0ef41Sopenharmony_ci  });
711cb0ef41Sopenharmony_ci  it('throws on boolean true', async () => {
721cb0ef41Sopenharmony_ci    const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
731cb0ef41Sopenharmony_ci      '--no-warnings',
741cb0ef41Sopenharmony_ci      '--experimental-loader',
751cb0ef41Sopenharmony_ci      fixtures.fileURL('/es-module-loaders/hooks-custom.mjs'),
761cb0ef41Sopenharmony_ci      '--input-type=module',
771cb0ef41Sopenharmony_ci      '--eval',
781cb0ef41Sopenharmony_ci      'import "esmHook/format.true"',
791cb0ef41Sopenharmony_ci    ]);
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ci    assert.match(stderr, /ERR_INVALID_RETURN_PROPERTY_VALUE/);
821cb0ef41Sopenharmony_ci    assert.strictEqual(stdout, '');
831cb0ef41Sopenharmony_ci    assert.strictEqual(code, 1);
841cb0ef41Sopenharmony_ci    assert.strictEqual(signal, null);
851cb0ef41Sopenharmony_ci  });
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci  it('throws on invalid returned object', async () => {
881cb0ef41Sopenharmony_ci    const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
891cb0ef41Sopenharmony_ci      '--no-warnings',
901cb0ef41Sopenharmony_ci      '--experimental-loader',
911cb0ef41Sopenharmony_ci      fixtures.fileURL('/es-module-loaders/hooks-custom.mjs'),
921cb0ef41Sopenharmony_ci      '--input-type=module',
931cb0ef41Sopenharmony_ci      '--eval',
941cb0ef41Sopenharmony_ci      'import "esmHook/badReturnFormatVal.mjs"',
951cb0ef41Sopenharmony_ci    ]);
961cb0ef41Sopenharmony_ci
971cb0ef41Sopenharmony_ci    assert.match(stderr, /ERR_INVALID_RETURN_PROPERTY_VALUE/);
981cb0ef41Sopenharmony_ci    assert.strictEqual(stdout, '');
991cb0ef41Sopenharmony_ci    assert.strictEqual(code, 1);
1001cb0ef41Sopenharmony_ci    assert.strictEqual(signal, null);
1011cb0ef41Sopenharmony_ci  });
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ci  it('throws on unsupported format', async () => {
1041cb0ef41Sopenharmony_ci    const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
1051cb0ef41Sopenharmony_ci      '--no-warnings',
1061cb0ef41Sopenharmony_ci      '--experimental-loader',
1071cb0ef41Sopenharmony_ci      fixtures.fileURL('/es-module-loaders/hooks-custom.mjs'),
1081cb0ef41Sopenharmony_ci      '--input-type=module',
1091cb0ef41Sopenharmony_ci      '--eval',
1101cb0ef41Sopenharmony_ci      'import "esmHook/unsupportedReturnFormatVal.mjs"',
1111cb0ef41Sopenharmony_ci    ]);
1121cb0ef41Sopenharmony_ci
1131cb0ef41Sopenharmony_ci    assert.match(stderr, /ERR_UNKNOWN_MODULE_FORMAT/);
1141cb0ef41Sopenharmony_ci    assert.strictEqual(stdout, '');
1151cb0ef41Sopenharmony_ci    assert.strictEqual(code, 1);
1161cb0ef41Sopenharmony_ci    assert.strictEqual(signal, null);
1171cb0ef41Sopenharmony_ci  });
1181cb0ef41Sopenharmony_ci
1191cb0ef41Sopenharmony_ci  it('throws on invalid format property type', async () => {
1201cb0ef41Sopenharmony_ci    const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
1211cb0ef41Sopenharmony_ci      '--no-warnings',
1221cb0ef41Sopenharmony_ci      '--experimental-loader',
1231cb0ef41Sopenharmony_ci      fixtures.fileURL('/es-module-loaders/hooks-custom.mjs'),
1241cb0ef41Sopenharmony_ci      '--input-type=module',
1251cb0ef41Sopenharmony_ci      '--eval',
1261cb0ef41Sopenharmony_ci      'import "esmHook/badReturnSourceVal.mjs"',
1271cb0ef41Sopenharmony_ci    ]);
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_ci    assert.match(stderr, /ERR_INVALID_RETURN_PROPERTY_VALUE/);
1301cb0ef41Sopenharmony_ci    assert.strictEqual(stdout, '');
1311cb0ef41Sopenharmony_ci    assert.strictEqual(code, 1);
1321cb0ef41Sopenharmony_ci    assert.strictEqual(signal, null);
1331cb0ef41Sopenharmony_ci  });
1341cb0ef41Sopenharmony_ci
1351cb0ef41Sopenharmony_ci  it('rejects dynamic imports for all of the error cases checked above', async () => {
1361cb0ef41Sopenharmony_ci    const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
1371cb0ef41Sopenharmony_ci      '--no-warnings',
1381cb0ef41Sopenharmony_ci      '--experimental-loader',
1391cb0ef41Sopenharmony_ci      fixtures.fileURL('/es-module-loaders/hooks-custom.mjs'),
1401cb0ef41Sopenharmony_ci      '--input-type=module',
1411cb0ef41Sopenharmony_ci      '--eval',
1421cb0ef41Sopenharmony_ci      `import assert from 'node:assert';
1431cb0ef41Sopenharmony_ci      await Promise.allSettled([
1441cb0ef41Sopenharmony_ci        import('nonexistent/file.mjs'),
1451cb0ef41Sopenharmony_ci        import(${JSON.stringify(fixtures.fileURL('/es-modules/file.unknown'))}),
1461cb0ef41Sopenharmony_ci        import('esmHook/badReturnVal.mjs'),
1471cb0ef41Sopenharmony_ci        import('esmHook/format.false'),
1481cb0ef41Sopenharmony_ci        import('esmHook/format.true'),
1491cb0ef41Sopenharmony_ci        import('esmHook/badReturnFormatVal.mjs'),
1501cb0ef41Sopenharmony_ci        import('esmHook/unsupportedReturnFormatVal.mjs'),
1511cb0ef41Sopenharmony_ci        import('esmHook/badReturnSourceVal.mjs'),
1521cb0ef41Sopenharmony_ci      ]).then((results) => {
1531cb0ef41Sopenharmony_ci        assert.strictEqual(results.every((result) => result.status === 'rejected'), true);
1541cb0ef41Sopenharmony_ci      })`,
1551cb0ef41Sopenharmony_ci    ]);
1561cb0ef41Sopenharmony_ci
1571cb0ef41Sopenharmony_ci    assert.strictEqual(stderr, '');
1581cb0ef41Sopenharmony_ci    assert.strictEqual(stdout, '');
1591cb0ef41Sopenharmony_ci    assert.strictEqual(code, 0);
1601cb0ef41Sopenharmony_ci    assert.strictEqual(signal, null);
1611cb0ef41Sopenharmony_ci  });
1621cb0ef41Sopenharmony_ci});
1631cb0ef41Sopenharmony_ci
1641cb0ef41Sopenharmony_cidescribe('Loader hooks parsing modules', { concurrency: true }, () => {
1651cb0ef41Sopenharmony_ci  it('can parse .js files as ESM', async () => {
1661cb0ef41Sopenharmony_ci    const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
1671cb0ef41Sopenharmony_ci      '--no-warnings',
1681cb0ef41Sopenharmony_ci      '--experimental-loader',
1691cb0ef41Sopenharmony_ci      fixtures.fileURL('/es-module-loaders/hooks-custom.mjs'),
1701cb0ef41Sopenharmony_ci      '--input-type=module',
1711cb0ef41Sopenharmony_ci      '--eval',
1721cb0ef41Sopenharmony_ci      `import assert from 'node:assert';
1731cb0ef41Sopenharmony_ci      await import(${JSON.stringify(fixtures.fileURL('/es-module-loaders/js-as-esm.js'))})
1741cb0ef41Sopenharmony_ci      .then((parsedModule) => {
1751cb0ef41Sopenharmony_ci        assert.strictEqual(typeof parsedModule, 'object');
1761cb0ef41Sopenharmony_ci        assert.strictEqual(parsedModule.namedExport, 'named-export');
1771cb0ef41Sopenharmony_ci      })`,
1781cb0ef41Sopenharmony_ci    ]);
1791cb0ef41Sopenharmony_ci
1801cb0ef41Sopenharmony_ci    assert.strictEqual(stderr, '');
1811cb0ef41Sopenharmony_ci    assert.strictEqual(stdout, '');
1821cb0ef41Sopenharmony_ci    assert.strictEqual(code, 0);
1831cb0ef41Sopenharmony_ci    assert.strictEqual(signal, null);
1841cb0ef41Sopenharmony_ci  });
1851cb0ef41Sopenharmony_ci
1861cb0ef41Sopenharmony_ci  it('can define .ext files as ESM', async () => {
1871cb0ef41Sopenharmony_ci    const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
1881cb0ef41Sopenharmony_ci      '--no-warnings',
1891cb0ef41Sopenharmony_ci      '--experimental-loader',
1901cb0ef41Sopenharmony_ci      fixtures.fileURL('/es-module-loaders/hooks-custom.mjs'),
1911cb0ef41Sopenharmony_ci      '--input-type=module',
1921cb0ef41Sopenharmony_ci      '--eval',
1931cb0ef41Sopenharmony_ci      `import assert from 'node:assert';
1941cb0ef41Sopenharmony_ci      await import(${JSON.stringify(fixtures.fileURL('/es-modules/file.ext'))})
1951cb0ef41Sopenharmony_ci      .then((parsedModule) => {
1961cb0ef41Sopenharmony_ci        assert.strictEqual(typeof parsedModule, 'object');
1971cb0ef41Sopenharmony_ci        const { default: defaultExport } = parsedModule;
1981cb0ef41Sopenharmony_ci        assert.strictEqual(typeof defaultExport, 'function');
1991cb0ef41Sopenharmony_ci        assert.strictEqual(defaultExport.name, 'iAmReal');
2001cb0ef41Sopenharmony_ci        assert.strictEqual(defaultExport(), true);
2011cb0ef41Sopenharmony_ci      })`,
2021cb0ef41Sopenharmony_ci    ]);
2031cb0ef41Sopenharmony_ci
2041cb0ef41Sopenharmony_ci    assert.strictEqual(stderr, '');
2051cb0ef41Sopenharmony_ci    assert.strictEqual(stdout, '');
2061cb0ef41Sopenharmony_ci    assert.strictEqual(code, 0);
2071cb0ef41Sopenharmony_ci    assert.strictEqual(signal, null);
2081cb0ef41Sopenharmony_ci  });
2091cb0ef41Sopenharmony_ci
2101cb0ef41Sopenharmony_ci  it('can predetermine the format in the custom loader resolve hook', async () => {
2111cb0ef41Sopenharmony_ci    const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
2121cb0ef41Sopenharmony_ci      '--no-warnings',
2131cb0ef41Sopenharmony_ci      '--experimental-loader',
2141cb0ef41Sopenharmony_ci      fixtures.fileURL('/es-module-loaders/hooks-custom.mjs'),
2151cb0ef41Sopenharmony_ci      '--input-type=module',
2161cb0ef41Sopenharmony_ci      '--eval',
2171cb0ef41Sopenharmony_ci      `import assert from 'node:assert';
2181cb0ef41Sopenharmony_ci      await import('esmHook/preknownFormat.pre')
2191cb0ef41Sopenharmony_ci      .then((parsedModule) => {
2201cb0ef41Sopenharmony_ci        assert.strictEqual(typeof parsedModule, 'object');
2211cb0ef41Sopenharmony_ci        assert.strictEqual(parsedModule.default, 'hello world');
2221cb0ef41Sopenharmony_ci      })`,
2231cb0ef41Sopenharmony_ci    ]);
2241cb0ef41Sopenharmony_ci
2251cb0ef41Sopenharmony_ci    assert.strictEqual(stderr, '');
2261cb0ef41Sopenharmony_ci    assert.strictEqual(stdout, '');
2271cb0ef41Sopenharmony_ci    assert.strictEqual(code, 0);
2281cb0ef41Sopenharmony_ci    assert.strictEqual(signal, null);
2291cb0ef41Sopenharmony_ci  });
2301cb0ef41Sopenharmony_ci
2311cb0ef41Sopenharmony_ci  it('can provide source for a nonexistent file', async () => {
2321cb0ef41Sopenharmony_ci    const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
2331cb0ef41Sopenharmony_ci      '--no-warnings',
2341cb0ef41Sopenharmony_ci      '--experimental-loader',
2351cb0ef41Sopenharmony_ci      fixtures.fileURL('/es-module-loaders/hooks-custom.mjs'),
2361cb0ef41Sopenharmony_ci      '--input-type=module',
2371cb0ef41Sopenharmony_ci      '--eval',
2381cb0ef41Sopenharmony_ci      `import assert from 'node:assert';
2391cb0ef41Sopenharmony_ci      await import('esmHook/virtual.mjs')
2401cb0ef41Sopenharmony_ci      .then((parsedModule) => {
2411cb0ef41Sopenharmony_ci        assert.strictEqual(typeof parsedModule, 'object');
2421cb0ef41Sopenharmony_ci        assert.strictEqual(typeof parsedModule.default, 'undefined');
2431cb0ef41Sopenharmony_ci        assert.strictEqual(parsedModule.message, 'WOOHOO!');
2441cb0ef41Sopenharmony_ci      })`,
2451cb0ef41Sopenharmony_ci    ]);
2461cb0ef41Sopenharmony_ci
2471cb0ef41Sopenharmony_ci    assert.strictEqual(stderr, '');
2481cb0ef41Sopenharmony_ci    assert.strictEqual(stdout, '');
2491cb0ef41Sopenharmony_ci    assert.strictEqual(code, 0);
2501cb0ef41Sopenharmony_ci    assert.strictEqual(signal, null);
2511cb0ef41Sopenharmony_ci  });
2521cb0ef41Sopenharmony_ci
2531cb0ef41Sopenharmony_ci  it('ensures that loaders have a separate context from userland', async () => {
2541cb0ef41Sopenharmony_ci    const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
2551cb0ef41Sopenharmony_ci      '--no-warnings',
2561cb0ef41Sopenharmony_ci      '--experimental-loader',
2571cb0ef41Sopenharmony_ci      fixtures.fileURL('/es-module-loaders/hooks-custom.mjs'),
2581cb0ef41Sopenharmony_ci      '--input-type=module',
2591cb0ef41Sopenharmony_ci      '--eval',
2601cb0ef41Sopenharmony_ci      `import assert from 'node:assert';
2611cb0ef41Sopenharmony_ci      await import(${JSON.stringify(fixtures.fileURL('/es-modules/stateful.mjs'))})
2621cb0ef41Sopenharmony_ci      .then(({ default: count }) => {
2631cb0ef41Sopenharmony_ci        assert.strictEqual(count(), 1);
2641cb0ef41Sopenharmony_ci      });`,
2651cb0ef41Sopenharmony_ci    ]);
2661cb0ef41Sopenharmony_ci
2671cb0ef41Sopenharmony_ci    assert.strictEqual(stderr, '');
2681cb0ef41Sopenharmony_ci    assert.strictEqual(stdout, '');
2691cb0ef41Sopenharmony_ci    assert.strictEqual(code, 0);
2701cb0ef41Sopenharmony_ci    assert.strictEqual(signal, null);
2711cb0ef41Sopenharmony_ci  });
2721cb0ef41Sopenharmony_ci
2731cb0ef41Sopenharmony_ci  it('ensures that user loaders are not bound to the internal loader', async () => {
2741cb0ef41Sopenharmony_ci    const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
2751cb0ef41Sopenharmony_ci      '--no-warnings',
2761cb0ef41Sopenharmony_ci      '--experimental-loader',
2771cb0ef41Sopenharmony_ci      fixtures.fileURL('/es-module-loaders/loader-this-value-inside-hook-functions.mjs'),
2781cb0ef41Sopenharmony_ci      '--input-type=module',
2791cb0ef41Sopenharmony_ci      '--eval',
2801cb0ef41Sopenharmony_ci      ';', // Actual test is inside the loader module.
2811cb0ef41Sopenharmony_ci    ]);
2821cb0ef41Sopenharmony_ci
2831cb0ef41Sopenharmony_ci    assert.strictEqual(stderr, '');
2841cb0ef41Sopenharmony_ci    assert.strictEqual(stdout, '');
2851cb0ef41Sopenharmony_ci    assert.strictEqual(code, 0);
2861cb0ef41Sopenharmony_ci    assert.strictEqual(signal, null);
2871cb0ef41Sopenharmony_ci  });
2881cb0ef41Sopenharmony_ci});
289