Skip to content

@btravstack/testing


@btravstack/testing / index

index ​

Classes ​

TestRuntimePort ​

Defined in: testing/src/test-runtime.ts:25

The in-memory runtime's port: what TestRuntime.module provides, and what a test composition exports.

Extends ​

Constructors ​

Constructor ​
ts
new TestRuntimePort(): TestRuntimePort;

Defined in: di/dist/index.d.mts:15

Returns ​

TestRuntimePort

Inherited from ​

RuntimePort<Runtime<never, TestRuntimeInfo>>.constructor

Properties ​

PropertyModifierTypeInherited fromDefined in
[ID]readonly"Runtime"RuntimePort.[ID]di/dist/index.d.mts:11
[SERVICE]readonlyRuntimeRuntimePort.[SERVICE]di/dist/index.d.mts:12
portIdstatic readonly"Runtime"RuntimePort.portIddi/dist/index.d.mts:16

Type Aliases ​

Boot ​

ts
type Boot = <X, E, N>(module, options?) => RunningApp<E, RuntimeInfoOf<X>>;

Defined in: testing/src/boot-fixture.ts:17

start, as a test hands it out: the same signature and the same phantom gate, minus signals (always off) — every application it starts is stopped when the test ends.

Type Parameters ​

Type Parameter
X
E
N

Parameters ​

ParameterType
moduleModule<X, E, N> & StartGate<X, N>
options?Omit<StartOptions<EnvironmentFor<N> & KernelEnvironment>, "signals">

Returns ​

RunningApp<E, RuntimeInfoOf<X>>


BootDefaults ​

ts
type BootDefaults = Omit<StartOptions, "signals">;

Defined in: testing/src/boot-fixture.ts:23

What every boot in the fixture starts with; a call's own options win.


FakeClock ​

ts
type FakeClock = Clock & object;

Defined in: testing/src/fake-clock.ts:11

Type Declaration ​

NameTypeDescriptionDefined in
advance()(ms) => AsyncResult<void, never>Move the clock forward, resolving every sleep whose deadline has passed. The returned AsyncResult settles once the code under test has had a chance to react — so await clock.advance(5_000) leaves the application where the elapsed time takes it, with no extra flushing at the call site.testing/src/fake-clock.ts:19

ServicesOf ​

ts
type ServicesOf<P> = { readonly [K in keyof P]: ServiceOf<InstanceType<P[K]>> };

Defined in: testing/src/tapped.ts:4

The services behind ports, in order — what tapped(...).services() answers once the graph is built.

Type Parameters ​

Type Parameter
P extends readonly AnyPort[]

SubmittedUnit ​

ts
type SubmittedUnit<T, E> = object;

Defined in: testing/src/test-runtime.ts:12

Type Parameters ​

Type Parameter
T
E

Properties ​

PropertyModifierTypeDefined in
resultreadonlyAsyncResult<T, E>testing/src/test-runtime.ts:14
settlereadonly(result) => voidtesting/src/test-runtime.ts:13
signalreadonlyAbortSignaltesting/src/test-runtime.ts:15

TestRuntime ​

ts
type TestRuntime<Unit> = Runtime<never, TestRuntimeInfo> & object;

Defined in: testing/src/test-runtime.ts:32

Type Parameters ​

Type ParameterDefault type
Unit extends AnyUnitModule | undefinedundefined

Type Declaration ​

NameTypeDescriptionDefined in
accepting()() => booleanWhether the runtime would still take new work — false once drain or stop has been called, so a test can observe WHEN the kernel told it to stop accepting.testing/src/test-runtime.ts:59
host()() => RuntimeHost<never>The RuntimeHost the kernel last called start with. Throws if the runtime was never started — the same misuse guard as serving().testing/src/test-runtime.ts:63
moduleModule<TestRuntimePort, never, UnitNeedsOf<Unit>>A module providing this very runtime on TestRuntimePort: import it next to the module under test, export the port, and start finds it. It provides THIS object, so a wrapper built by spreading copies the module too and that module still boots the inner runtime — a wrapper needs a module of its own. Its Needs channel carries a bound unit module's own unmet needs, though nothing here reads them: the module is forked over the application context per unit, so what it needs is exactly what the test composition must supply — and this is what makes start's UNSATISFIED DEPENDENCIES say so at boot instead of leaving a WiringDefect for the first submit().testing/src/test-runtime.ts:50
serving()() => Serving<TestRuntimeInfo>-testing/src/test-runtime.ts:60
started()() => boolean-testing/src/test-runtime.ts:51
submit()<T, E>() => SubmittedUnit<T, E>-testing/src/test-runtime.ts:61
untilStarted()() => AsyncResult<void, never>Resolves the first time the kernel calls start — start itself stays pending until shutdown.testing/src/test-runtime.ts:53

TestRuntimeInfo ​

ts
type TestRuntimeInfo = object;

Defined in: testing/src/test-runtime.ts:22

What testRuntime publishes on Serving.info — its own name, the one thing an in-memory runtime genuinely knows about itself.

Properties ​

PropertyModifierTypeDefined in
namereadonlystringtesting/src/test-runtime.ts:22

TestRuntimeOptions ​

ts
type TestRuntimeOptions<Unit> = object;

Defined in: testing/src/test-runtime.ts:27

Type Parameters ​

Type ParameterDefault type
Unit extends AnyUnitModule | undefinedundefined

Properties ​

PropertyModifierTypeDescriptionDefined in
unit?readonlyUnitA module every submitted unit forks, with no seed, before its work runs.testing/src/test-runtime.ts:29

Functions ​

bootFixture() ​

ts
function bootFixture(defaults?): (__namedParameters, use) => Promise<void>;

Defined in: testing/src/boot-fixture.ts:51

A test.extend fixture that hands the test a Boot and stops every application it started once the test is over — on every exit path, a failing assertion included, which is what test.extend's teardown is for.

ts
export const it = test.extend<{ boot: Boot }>({
  boot: bootFixture({ env: { PORT: "0", HOST: "127.0.0.1" } }),
});

it("answers", async ({ boot }) => {
  const app = boot(OrderApi);
  …
});

The defaults are a test's: signals: false always (process-wide handlers would fight across a file), probes: false, preDrainDelayMs: 0, a stopTimeoutMs far out of reach and a silent onEvent — each overridable by defaults and again per call.

Teardown is stop(), then exited is examined: a Defect fails the test even when the test never looked at exited, while a modeled Err passes through, since a startup failure is an outcome a test may be asserting.

Parameters ​

ParameterType
defaults?BootDefaults

Returns ​

(__namedParameters, use) => Promise<void>


createFakeClock() ​

ts
function createFakeClock(start?): FakeClock;

Defined in: testing/src/fake-clock.ts:44

A Clock whose time only moves when a test says so.

Pass it as StartOptions.clock to drive the drain's pre-drain delay and deadline explicitly, instead of waiting out the real 5s/20s defaults.

Parameters ​

ParameterTypeDefault value
start?number0

Returns ​

FakeClock

Example ​

ts
const clock = createFakeClock();
const app = start(AppModule, { runtime, clock });

app.requestDrain();
await clock.advance(5_000); // the pre-drain delay
await clock.advance(20_000); // the drain deadline

overridden() ​

ts
function overridden<X, E, N, O>(
   module, 
   overrides, 
   options?
): Module<X, E | ErrorsOf<O>, N>;

Defined in: testing/src/overridden.ts:46

The real composition root, with named providers substituted — the testing half of "swapping an adapter is composing a different module", for the seam composition cannot reach: nothing can be layered over a graph that already provides a port, so the alternative was a parallel root that drifted silently.

Each override is an ordinary Provider(Port)(...), so the service type is checked against the port at that call. At run time an override REPLACES the base provider — the base is never constructed — and an override for a port the tree no longer provides is a WiringDefect ("nothing to override"), which is what turns fixture drift into a loud failure.

options.unit reaches inside the unit modules the root binds, keyed by the kind the root binds them under ({ user: [...] }, { message: [...] }): a unit module is forked per unit, after the root is built, so a root-level override cannot see its providers. The kernel applies these at boot, and a kind the runtime binds no module for, a port that kind's module does not provide, or two overrides for one port in one kind is a defect there — the same drift gate, at the same moment.

It replaces ONE provider, never a subsystem: the replaced provider's siblings still construct, so swapping a whole adapter stack remains a different module composed in its place.

An override's own deps deliberately do NOT widen the returned Needs: they resolve from the graph's INTERNALS, and typing them into N would force a root to re-export internals to be overridable. They are checked at build instead, by plan's missing-provider defect.

Type Parameters ​

Type Parameter
X
E
N
O extends readonly AnyProviderFor[]

Parameters ​

ParameterType
moduleModule<X, E, N>
overridesO
options?{ unit?: Readonly<Record<string, readonly UnitProviderFor[]>>; }
options.unit?Readonly<Record<string, readonly UnitProviderFor[]>>

Returns ​

Module<X, E | ErrorsOf<O>, N>


tapped() ​

ts
function tapped<X, E, N, P>(module, ports): object;

Defined in: testing/src/tapped.ts:42

Type Parameters ​

Type Parameter
X
E
N
P extends readonly AnyPort[]

Parameters ​

ParameterType
moduleModule<X, E, N>
portsP & TapGate<P, X>

Returns ​

object

NameTypeDefined in
moduleModule<X, E, N>testing/src/tapped.ts:45
services()() => ServicesOf<P>testing/src/tapped.ts:45

testRuntime() ​

ts
function testRuntime<Unit>(name?, options?): TestRuntime<Unit>;

Defined in: testing/src/test-runtime.ts:66

Type Parameters ​

Type ParameterDefault type
Unit extends AnyUnitModule | undefinedundefined

Parameters ​

ParameterTypeDefault value
name?string"test"
options?TestRuntimeOptions<Unit>{}

Returns ​

TestRuntime<Unit>

Released under the MIT License.