Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
test: isolate globalPreload tests
  • Loading branch information
GeoffreyBooth authored and aduh95 committed Sep 8, 2023
commit a1d13f27c037a1b6d84774f53e92a6f906cae91e
145 changes: 145 additions & 0 deletions test/es-module/test-esm-loader-globalpreload-hook.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
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);
});
});
125 changes: 1 addition & 124 deletions test/es-module/test-esm-loader-hooks.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,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(){}',
Expand All @@ -434,129 +434,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 () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}