@samveys/testing
createTestApp, in-process HTTP test client, fake time, events fake, hook recording
This list was read from version 1.0.2; run pnpm sync to refresh it.
import { captureLogs, createTestApp, createTestClient, fakeEvents, fakeTime, recordHooks } from '@samveys/testing'
Function (6)
captureLogs
Function
A logger that records each JSON line it writes, parsed, instead of printing it. Default level `debug`.
function captureLogs(level?: LogLevel | 'silent'): LogCapture;
Exported from packages/testing/src/logs.ts
createTestApp
Function
Boots an app for a test: captured logs, recorded hooks and events, `container.swap()` that is undone on `close()`, and (with `@samveys/http`) an in-process HTTP client. Use `await using` or call `close()`. If startup throws, the app is shut down and the original error is rethrown.
function createTestApp(options?: TestAppOptions): Promise<TestApp>;
Exported from packages/testing/src/app.ts
createTestClient
Function
An in-process test client over any `(Request) => Promise<Response>`, typically `kernel.fetch`. Responses are read once, so assertions are synchronous.
function createTestClient(fetchLike: (request: Request, options?: {
Exported from packages/testing/src/client.ts
fakeEvents
Function
Records every `emitter.emit` call. Listeners still run unless `options.swallow` is true. Wraps `emit` on this emitter instance; `stop()` puts it back.
function fakeEvents(emitter: Emitter, options?: {
Exported from packages/testing/src/events.ts
fakeTime
Function
Fakes timers and the clock on `node:test` `mock.timers` (or `options.mock.timers`, e.g. `t.mock.timers`). Starts at `2026-01-01T00:00:00.000Z` unless `now` is given. Use `using` or call `restore()`.
function fakeTime(options?: FakeTimeOptions): FakeTime;
Exported from packages/testing/src/time.ts
recordHooks
Function
Records the arguments of every `on` emission (`registry.emit`) of any hook name, including hooks augmented by other packages. Wraps `emit` on this registry instance; `stop()` puts it back.
function recordHooks(registry: HookRegistry): HookRecorder & {
Exported from packages/testing/src/hooks.ts
Interface (11)
EventsFake
Interface
No documentation comment.
interface EventsFake {
/** Payloads emitted for `event`, in order. Listeners still run unless `swallow` was set. */
emitted<K extends EventName>(event: K): readonly Events[K][];
/** Throws an `AssertionError` naming the event when it was not emitted (or not with a matching payload). */
assertEmitted<K extends EventName>(event: K, match?: (payload: Events[K]) => boolean): void;
Exported from packages/testing/src/contracts.ts
FakeTime
Interface
No documentation comment.
interface FakeTime extends Disposable {
/** Current fake time. */
now(): Date;
/** Advance by milliseconds or a duration string: `'500ms'`, `'30s'`, `'15m'`, `'2h'`, `'1d'`. Runs due timers. */
advance(by: number | string): void;
/** Jump to an absolute time without running timers in between. */
set(to: Date | number | string): void;
/** Run every pending timer. */
runAll(): void;
/** Restore the real timers and clock. Also runs on `using` disposal. */
restore(): void;
}
Exported from packages/testing/src/contracts.ts
FakeTimeOptions
Interface
No documentation comment.
interface FakeTimeOptions {
/** Defaults to `2026-01-01T00:00:00.000Z`, so tests never depend on the real clock. */
readonly now?: Date | number | string;
/** Defaults to `setTimeout`, `setInterval`, `setImmediate`, `Date`. */
readonly apis?: readonly ('setTimeout' | 'setInterval' | 'setImmediate' | 'Date' | 'scheduler.wait')[];
/** Defaults to the global `mock` from `node:test`; pass `t.mock` to tie the fake to one test. */
readonly mock?: {
readonly timers: MockTimersLike;
};
}
Exported from packages/testing/src/contracts.ts
HookRecorder
Interface
Arguments of every `on` emission of `name` since recording started.
interface HookRecorder {
calls<K extends HookName>(name: K): readonly HookArgs<K>[];
count(name: HookName): number;
clear(): void;
}
Exported from packages/testing/src/contracts.ts
LogCapture
Interface
No documentation comment.
interface LogCapture {
/** Every line written so far, parsed. */
readonly records: readonly LogRecord[];
/** The logger that writes into `records`. */
readonly logger: Logger;
/** Records at `level`, optionally only those whose `msg` contains `text`. */
find(level: LogLevel, text?: string): readonly LogRecord[];
clear(): void;
}
Exported from packages/testing/src/contracts.ts
MockTimersLike
Interface
The `node:test` context's `mock.timers`, or the global `mock.timers`.
interface MockTimersLike {
enable(options?: {
readonly apis?: readonly string[];
readonly now?: number | Date;
}): void;
tick(milliseconds?: number): void;
setTime(milliseconds: number): void;
runAll(): void;
reset(): void;
}
Exported from packages/testing/src/contracts.ts
TestApp
Interface
No documentation comment.
interface TestApp extends AsyncDisposable {
readonly app: Application;
readonly logs: LogCapture;
/** Recording of every hook emission since the app was created. */
readonly hooks: HookRecorder;
/** Records `app.events` emissions. */
readonly events: EventsFake;
/** In-process client on `kernel.fetch`; created on first use. Needs `@samveys/http` installed. */
readonly http: TestClient;
/** The kernel behind `http`; created on first use. */
…
Show the whole declaration (18 lines)
interface TestApp extends AsyncDisposable {
readonly app: Application;
readonly logs: LogCapture;
/** Recording of every hook emission since the app was created. */
readonly hooks: HookRecorder;
/** Records `app.events` emissions. */
readonly events: EventsFake;
/** In-process client on `kernel.fetch`; created on first use. Needs `@samveys/http` installed. */
readonly http: TestClient;
/** The kernel behind `http`; created on first use. */
…interface TestApp extends AsyncDisposable {
readonly app: Application;
readonly logs: LogCapture;
/** Recording of every hook emission since the app was created. */
readonly hooks: HookRecorder;
/** Records `app.events` emissions. */
readonly events: EventsFake;
/** In-process client on `kernel.fetch`; created on first use. Needs `@samveys/http` installed. */
readonly http: TestClient;
/** The kernel behind `http`; created on first use. */
kernel(): Promise<HttpKernel>;
/** `container.swap` scoped to this test app; undone by `close()`. */
swap: Application['container']['swap'];
/** Fire a hook as the framework would (listeners run, results discarded). */
emit<K extends HookName>(name: K, ...args: HookArgs<K>): Promise<void>;
/** Shut the app down; returns the shutdown result. Idempotent. Also runs on `await using`. */
close(): ReturnType<Application['shutdown']>;
}
Exported from packages/testing/src/contracts.ts
TestAppOptions
Interface
No documentation comment.
interface TestAppOptions extends Omit<CreateAppOptions, 'loggerInstance'> {
/** Plugins to install, exactly as in `samveys.config.ts`. */
readonly plugins?: readonly PluginEntry[];
/** Routes for the in-process HTTP kernel; added to the `http.router` binding before the kernel is built. */
readonly routes?: (router: Router) => void;
Exported from packages/testing/src/contracts.ts
TestClient
Interface
No documentation comment.
interface TestClient {
get(path: string, options?: TestRequestOptions): Promise<TestResponse>;
post(path: string, options?: TestRequestOptions): Promise<TestResponse>;
put(path: string, options?: TestRequestOptions): Promise<TestResponse>;
patch(path: string, options?: TestRequestOptions): Promise<TestResponse>;
delete(path: string, options?: TestRequestOptions): Promise<TestResponse>;
request(method: string, path: string, options?: TestRequestOptions): Promise<TestResponse>;
/** Default headers for every later request from this client (e.g. an auth token). */
withHeaders(headers: HeadersInput): TestClient;
}
Exported from packages/testing/src/contracts.ts
TestRequestOptions
Interface
No documentation comment.
interface TestRequestOptions {
readonly headers?: HeadersInput;
readonly query?: Readonly<Record<string, string | number | boolean | readonly (string | number)[]>>;
/** Sent as JSON with `content-type: application/json`. */
readonly json?: unknown;
/** Sent as `application/x-www-form-urlencoded`. */
readonly form?: Readonly<Record<string, string>>;
/** Raw body; set `content-type` yourself. */
readonly body?: BodyInput;
readonly signal?: AbortSignal;
…
Show the whole declaration (16 lines)
interface TestRequestOptions {
readonly headers?: HeadersInput;
readonly query?: Readonly<Record<string, string | number | boolean | readonly (string | number)[]>>;
/** Sent as JSON with `content-type: application/json`. */
readonly json?: unknown;
/** Sent as `application/x-www-form-urlencoded`. */
readonly form?: Readonly<Record<string, string>>;
/** Raw body; set `content-type` yourself. */
readonly body?: BodyInput;
readonly signal?: AbortSignal;
…interface TestRequestOptions {
readonly headers?: HeadersInput;
readonly query?: Readonly<Record<string, string | number | boolean | readonly (string | number)[]>>;
/** Sent as JSON with `content-type: application/json`. */
readonly json?: unknown;
/** Sent as `application/x-www-form-urlencoded`. */
readonly form?: Readonly<Record<string, string>>;
/** Raw body; set `content-type` yourself. */
readonly body?: BodyInput;
readonly signal?: AbortSignal;
/**
* The client address the kernel sees (`ctx.clientIp`, trusted-proxy checks), as if the request came
* from that socket peer. Default: none, like an in-process request.
*/
readonly remoteAddress?: string;
}
Exported from packages/testing/src/contracts.ts
TestResponse
Interface
A response with its body already read, so assertions are synchronous.
interface TestResponse {
readonly status: number;
readonly headers: Headers;
readonly text: string;
/** `JSON.parse(text)`; `undefined` when the body is empty. Throws when the body is not JSON. */
json<T = unknown>(): T;
/** The response as sent by the kernel (body already consumed). */
readonly raw: Response;
/** Throws an `AssertionError` with the status and body when `status` differs. */
assertStatus(status: number): this;
…
Show the whole declaration (16 lines)
interface TestResponse {
readonly status: number;
readonly headers: Headers;
readonly text: string;
/** `JSON.parse(text)`; `undefined` when the body is empty. Throws when the body is not JSON. */
json<T = unknown>(): T;
/** The response as sent by the kernel (body already consumed). */
readonly raw: Response;
/** Throws an `AssertionError` with the status and body when `status` differs. */
assertStatus(status: number): this;
…interface TestResponse {
readonly status: number;
readonly headers: Headers;
readonly text: string;
/** `JSON.parse(text)`; `undefined` when the body is empty. Throws when the body is not JSON. */
json<T = unknown>(): T;
/** The response as sent by the kernel (body already consumed). */
readonly raw: Response;
/** Throws an `AssertionError` with the status and body when `status` differs. */
assertStatus(status: number): this;
/** Asserts `application/problem+json` with the given status and, when given, `SVS_E*` code. */
assertProblem(status: number, code?: string): this;
assertHeader(name: string, value?: string | RegExp): this;
/** Deep-strict subset match of the JSON body. */
assertJson(expected: unknown): this;
}
Exported from packages/testing/src/contracts.ts
Type (3)
BodyInput
Type
The `body` field of `RequestInit`.
type BodyInput = NonNullable<RequestInit['body']>;
Exported from packages/testing/src/contracts.ts
HeadersInput
Type
The `headers` argument of `new Headers()` (the DOM `HeadersInit` alias is not in `lib: esnext`).
type HeadersInput = ConstructorParameters<typeof Headers>[0];
Exported from packages/testing/src/contracts.ts
LogRecord
Type
One parsed JSON log line.
type LogRecord = Readonly<Record<string, unknown>> & {
readonly level: LogLevel;
readonly msg: string;
};
Exported from packages/testing/src/contracts.ts