// Derived from Node.js v24.16.0 (MIT; Copyright Node.js contributors, and Joyent, Inc. and // other Node contributors). See LICENSE-node. // node:test, after Node's lib/test.js: `module.exports = test` (test itself is also // `test.test`), plus describe/it aliases, before/after/beforeEach/afterEach, and the // lazy `mock`/`snapshot`/`assert`/`run` getters. `test_runner/` mirrors Node's // lib/internal/test_runner/ the way src/runtime/readline/ mirrors Node's lib/readline.js // + lib/internal/readline/. Registered scheme-only in builtins.ts (SCHEME_ONLY_BUILTINS): // `require("node:test")` works, bare `require("test")` fails, matching Node. import type { GuestProcess } from "./process"; import { bindProcess, test as runTest, suite, before, after, beforeEach, afterEach } from "./test_runner/harness"; import { createMockTracker } from "./test_runner/mock/mock"; import { bindTimerHooks, type TimerHooks } from "./test_runner/mock/mock_timers"; import { getAssertionMap, register } from "./test_runner/assert"; import { bindSnapshotFs, setDefaultSnapshotSerializers, setResolveSnapshotPath, type SnapshotFsHooks } from "./test_runner/snapshot"; import { run as runTests, type RunnerDeps } from "./test_runner/runner"; import type { TestsStream } from "./test_runner/tests_stream"; export interface TestHooks { timers: TimerHooks; fs: SnapshotFsHooks; run: RunnerDeps; } export interface TestModule { (name?: unknown, options?: unknown, fn?: unknown): Promise; test: TestModule; describe: typeof suite; it: TestModule; suite: typeof suite; before: typeof before; after: typeof after; beforeEach: typeof beforeEach; afterEach: typeof afterEach; run: (options?: unknown) => TestsStream; mock: ReturnType; snapshot: { setDefaultSnapshotSerializers: unknown; setResolveSnapshotPath: unknown }; assert: { register: typeof register }; } /** One instance per worker: node:test needs the real guest `process` (its exit code, * its argv[1] for the root test's location, its uncaughtException/unhandledRejection * events) before any test()/describe() call can lazily bootstrap the root, plus the * timer and fs hooks mock.timers and t.assert.snapshot/fileSnapshot need to reach * past this module into builtins.ts's loadBuiltin without a circular import. */ export function makeTest(process: GuestProcess, hooks: TestHooks): TestModule { bindProcess(process); bindTimerHooks(hooks.timers); bindSnapshotFs(hooks.fs); const test = runTest as unknown as TestModule; Object.assign(test, { after, afterEach, before, beforeEach, describe: suite, it: test, suite, test, // run({ isolation: "none" }) loads test files in this process (test_runner/ // runner.ts); run({ isolation: "process" }, the default) refuses there — see its // header comment — once option validation has already run. run: (options?: unknown) => runTests(options, hooks.run), }); let lazyMock: ReturnType | undefined; Object.defineProperty(test, "mock", { configurable: true, enumerable: true, get() { lazyMock ??= createMockTracker(); return lazyMock; }, }); Object.defineProperty(test, "snapshot", { configurable: true, enumerable: true, value: { setDefaultSnapshotSerializers, setResolveSnapshotPath }, }); Object.defineProperty(test, "assert", { configurable: true, enumerable: true, value: { register }, }); void getAssertionMap; return test; }