From 65201ab36ba4009d94c4cca458b0883991421972 Mon Sep 17 00:00:00 2001 From: Geoffrey Booth Date: Sat, 9 Sep 2023 16:02:21 -0700 Subject: [PATCH] test: isolate `globalPreload` tests PR-URL: https://github.com/nodejs/node/pull/49545 Backport-PR-URL: https://github.com/nodejs/node/pull/50669 Reviewed-By: Antoine du Hamel Reviewed-By: Jacob Smith --- .../test-esm-loader-globalpreload-hook.mjs | 149 ++++++++++++++++++ test/es-module/test-esm-loader-hooks.mjs | 126 +-------------- ...oader-this-value-inside-hook-functions.mjs | 21 ++- 3 files changed, 164 insertions(+), 132 deletions(-) create mode 100644 test/es-module/test-esm-loader-globalpreload-hook.mjs diff --git a/test/es-module/test-esm-loader-globalpreload-hook.mjs b/test/es-module/test-esm-loader-globalpreload-hook.mjs new file mode 100644 index 00000000000000..87def31fb3d0ea --- /dev/null +++ b/test/es-module/test-esm-loader-globalpreload-hook.mjs @@ -0,0 +1,149 @@ +import { spawnPromisified } from '../common/index.mjs'; +import * as fixtures from '../common/fixtures.mjs'; +import assert from 'node:assert'; +import os from 'node:os'; +import { execPath } from 'node:process'; +import { describe, it } from 'node:test'; + +describe('globalPreload hook', () => { + it('should not emit deprecation warning when initialize is supplied', async () => { + const { stderr } = await spawnPromisified(execPath, [ + '--experimental-loader', + 'data:text/javascript,export function globalPreload(){}export function initialize(){}', + fixtures.path('empty.js'), + ]); + + assert.doesNotMatch(stderr, /`globalPreload` is an experimental feature/); + }); + + it('should handle globalPreload returning undefined', async () => { + const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [ + '--no-warnings', + '--experimental-loader', + 'data:text/javascript,export function globalPreload(){}', + fixtures.path('empty.js'), + ]); + + assert.strictEqual(stderr, ''); + assert.strictEqual(stdout, ''); + assert.strictEqual(code, 0); + assert.strictEqual(signal, null); + }); + + it('should handle loading node:test', async () => { + const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [ + '--no-warnings', + '--experimental-loader', + 'data:text/javascript,export function globalPreload(){return `getBuiltin("node:test")()`}', + fixtures.path('empty.js'), + ]); + + assert.strictEqual(stderr, ''); + assert.match(stdout, /\n# pass 1\r?\n/); + assert.strictEqual(code, 0); + assert.strictEqual(signal, null); + }); + + it('should handle loading node:os with node: prefix', async () => { + const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [ + '--no-warnings', + '--experimental-loader', + 'data:text/javascript,export function globalPreload(){return `console.log(getBuiltin("node:os").arch())`}', + fixtures.path('empty.js'), + ]); + + assert.strictEqual(stderr, ''); + assert.strictEqual(stdout.trim(), os.arch()); + assert.strictEqual(code, 0); + assert.strictEqual(signal, null); + }); + + // `os` is used here because it's simple and not mocked (the builtin module otherwise doesn't matter). + it('should handle loading builtin module without node: prefix', async () => { + const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [ + '--no-warnings', + '--experimental-loader', + 'data:text/javascript,export function globalPreload(){return `console.log(getBuiltin("os").arch())`}', + fixtures.path('empty.js'), + ]); + + assert.strictEqual(stderr, ''); + assert.strictEqual(stdout.trim(), os.arch()); + assert.strictEqual(code, 0); + assert.strictEqual(signal, null); + }); + + it('should throw when loading node:test without node: prefix', async () => { + const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [ + '--no-warnings', + '--experimental-loader', + 'data:text/javascript,export function globalPreload(){return `getBuiltin("test")()`}', + fixtures.path('empty.js'), + ]); + + assert.match(stderr, /ERR_UNKNOWN_BUILTIN_MODULE/); + assert.strictEqual(stdout, ''); + assert.strictEqual(code, 1); + assert.strictEqual(signal, null); + }); + + it('should register globals set from globalPreload', async () => { + const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [ + '--no-warnings', + '--experimental-loader', + 'data:text/javascript,export function globalPreload(){return "this.myGlobal=4"}', + '--print', 'myGlobal', + ]); + + assert.strictEqual(stderr, ''); + assert.strictEqual(stdout.trim(), '4'); + assert.strictEqual(code, 0); + assert.strictEqual(signal, null); + }); + + it('should log console.log calls returned from globalPreload', async () => { + const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [ + '--no-warnings', + '--experimental-loader', + 'data:text/javascript,export function globalPreload(){return `console.log("Hello from globalPreload")`}', + fixtures.path('empty.js'), + ]); + + assert.strictEqual(stderr, ''); + assert.strictEqual(stdout.trim(), 'Hello from globalPreload'); + assert.strictEqual(code, 0); + assert.strictEqual(signal, null); + }); + + it('should crash if globalPreload returns code that throws', async () => { + const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [ + '--no-warnings', + '--experimental-loader', + 'data:text/javascript,export function globalPreload(){return `throw new Error("error from globalPreload")`}', + fixtures.path('empty.js'), + ]); + + assert.match(stderr, /error from globalPreload/); + assert.strictEqual(stdout, ''); + assert.strictEqual(code, 1); + assert.strictEqual(signal, null); + }); + + it('should have a `this` value that is not bound to the loader instance', async () => { + const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [ + '--no-warnings', + '--experimental-loader', + `data:text/javascript,export ${function globalPreload() { + if (this != null) { + throw new Error('hook function must not be bound to ESMLoader instance'); + } + }}`, + fixtures.path('empty.js'), + ]); + + assert.strictEqual(stderr, ''); + assert.strictEqual(stdout, ''); + assert.strictEqual(code, 0); + assert.strictEqual(signal, null); + }); +}); diff --git a/test/es-module/test-esm-loader-hooks.mjs b/test/es-module/test-esm-loader-hooks.mjs index 1db6903ed368cf..455c90ddf73507 100644 --- a/test/es-module/test-esm-loader-hooks.mjs +++ b/test/es-module/test-esm-loader-hooks.mjs @@ -1,7 +1,6 @@ import { spawnPromisified } from '../common/index.mjs'; import * as fixtures from '../common/fixtures.mjs'; import assert from 'node:assert'; -import os from 'node:os'; import { execPath } from 'node:process'; import { describe, it } from 'node:test'; @@ -371,7 +370,7 @@ describe('Loader hooks', { concurrency: true }, () => { }); describe('globalPreload', () => { - it('should emit deprecation warning', async () => { + it('should emit warning', async () => { const { stderr } = await spawnPromisified(execPath, [ '--experimental-loader', 'data:text/javascript,export function globalPreload(){}', @@ -382,129 +381,6 @@ describe('Loader hooks', { concurrency: true }, () => { assert.strictEqual(stderr.match(/`globalPreload` is an experimental feature/g).length, 1); }); - - it('should not emit deprecation warning when initialize is supplied', async () => { - const { stderr } = await spawnPromisified(execPath, [ - '--experimental-loader', - 'data:text/javascript,export function globalPreload(){}export function initialize(){}', - fixtures.path('empty.js'), - ]); - - assert.doesNotMatch(stderr, /`globalPreload` is an experimental feature/); - }); - - it('should handle globalPreload returning undefined', async () => { - const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [ - '--no-warnings', - '--experimental-loader', - 'data:text/javascript,export function globalPreload(){}', - fixtures.path('empty.js'), - ]); - - assert.strictEqual(stderr, ''); - assert.strictEqual(stdout, ''); - assert.strictEqual(code, 0); - assert.strictEqual(signal, null); - }); - - it('should handle loading node:test', async () => { - const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [ - '--no-warnings', - '--experimental-loader', - 'data:text/javascript,export function globalPreload(){return `getBuiltin("node:test")()`}', - fixtures.path('empty.js'), - ]); - - assert.strictEqual(stderr, ''); - assert.match(stdout, /\n# pass 1\r?\n/); - assert.strictEqual(code, 0); - assert.strictEqual(signal, null); - }); - - it('should handle loading node:os with node: prefix', async () => { - const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [ - '--no-warnings', - '--experimental-loader', - 'data:text/javascript,export function globalPreload(){return `console.log(getBuiltin("node:os").arch())`}', - fixtures.path('empty.js'), - ]); - - assert.strictEqual(stderr, ''); - assert.strictEqual(stdout.trim(), os.arch()); - assert.strictEqual(code, 0); - assert.strictEqual(signal, null); - }); - - // `os` is used here because it's simple and not mocked (the builtin module otherwise doesn't matter). - it('should handle loading builtin module without node: prefix', async () => { - const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [ - '--no-warnings', - '--experimental-loader', - 'data:text/javascript,export function globalPreload(){return `console.log(getBuiltin("os").arch())`}', - fixtures.path('empty.js'), - ]); - - assert.strictEqual(stderr, ''); - assert.strictEqual(stdout.trim(), os.arch()); - assert.strictEqual(code, 0); - assert.strictEqual(signal, null); - }); - - it('should throw when loading node:test without node: prefix', async () => { - const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [ - '--no-warnings', - '--experimental-loader', - 'data:text/javascript,export function globalPreload(){return `getBuiltin("test")()`}', - fixtures.path('empty.js'), - ]); - - assert.match(stderr, /ERR_UNKNOWN_BUILTIN_MODULE/); - assert.strictEqual(stdout, ''); - assert.strictEqual(code, 1); - assert.strictEqual(signal, null); - }); - - it('should register globals set from globalPreload', async () => { - const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [ - '--no-warnings', - '--experimental-loader', - 'data:text/javascript,export function globalPreload(){return "this.myGlobal=4"}', - '--print', 'myGlobal', - ]); - - assert.strictEqual(stderr, ''); - assert.strictEqual(stdout.trim(), '4'); - assert.strictEqual(code, 0); - assert.strictEqual(signal, null); - }); - - it('should log console.log calls returned from globalPreload', async () => { - const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [ - '--no-warnings', - '--experimental-loader', - 'data:text/javascript,export function globalPreload(){return `console.log("Hello from globalPreload")`}', - fixtures.path('empty.js'), - ]); - - assert.strictEqual(stderr, ''); - assert.strictEqual(stdout.trim(), 'Hello from globalPreload'); - assert.strictEqual(code, 0); - assert.strictEqual(signal, null); - }); - - it('should crash if globalPreload returns code that throws', async () => { - const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [ - '--no-warnings', - '--experimental-loader', - 'data:text/javascript,export function globalPreload(){return `throw new Error("error from globalPreload")`}', - fixtures.path('empty.js'), - ]); - - assert.match(stderr, /error from globalPreload/); - assert.strictEqual(stdout, ''); - assert.strictEqual(code, 1); - assert.strictEqual(signal, null); - }); }); it('should be fine to call `process.removeAllListeners("beforeExit")` from the main thread', async () => { diff --git a/test/fixtures/es-module-loaders/loader-this-value-inside-hook-functions.mjs b/test/fixtures/es-module-loaders/loader-this-value-inside-hook-functions.mjs index c1c80622feea66..2be18c4969ef80 100644 --- a/test/fixtures/es-module-loaders/loader-this-value-inside-hook-functions.mjs +++ b/test/fixtures/es-module-loaders/loader-this-value-inside-hook-functions.mjs @@ -1,14 +1,21 @@ +export function initialize() { + if (this != null) { + throw new Error('hook function must not be bound to loader instance'); + } +} + export function resolve(url, _, next) { - if (this != null) throw new Error('hook function must not be bound to ESMLoader instance'); + if (this != null) { + throw new Error('hook function must not be bound to loader instance'); + } + return next(url); } export function load(url, _, next) { - if (this != null) throw new Error('hook function must not be bound to ESMLoader instance'); - return next(url); -} + if (this != null) { + throw new Error('hook function must not be bound to loader instance'); + } -export function globalPreload() { - if (this != null) throw new Error('hook function must not be bound to ESMLoader instance'); - return ""; + return next(url); }