Reference index · a development dependency; nothing here ships
Mounting, cleanup and leak probes. Guide: Testing.
function mount(view: () => View, parent?: ParentNode): Mounted;
interface Mounted {
readonly container: HTMLElement;
/** Disposes the view and removes its container. Idempotent. */
readonly unmount: Dispose;
text(): string;
/** `querySelector` that throws instead of returning null. */
get<E extends Element = HTMLElement>(selector: string): E;
/** `querySelectorAll` as a real array. */
all<E extends Element = HTMLElement>(selector: string): E[];
}
const view = mount(() => <Counter start={2} />);
view.get<HTMLButtonElement>('button').click();
expect(view.text()).toBe('3'); // no await: writes are synchronous
Rendered into a container attached to the document, not a detached tree:
layout, focus, events and :hover all behave differently detached, and a test
that only passes detached is a test of something else.
get throws rather than returning null so that a selector typo fails as a
selector typo, and so no call site needs a non-null assertion.
function cleanup(): void;
function autoCleanup(): boolean;
cleanup() unmounts everything mount created. autoCleanup() registers it
with the surrounding test framework’s afterEach, if there is one, and returns
whether it found one — call it once in a setup file:
// vitest.setup.ts
import { autoCleanup } from '@firsthandjs/testing';
autoCleanup();
A test that forgets to unmount then cannot leak into the next one, which is the failure mode that makes a suite mysteriously order-dependent.
function withRoot<T>(fn: () => T): { value: T; dispose: Dispose };
Runs fn in its own reactive root, for testing reactivity with no DOM at all —
signals, computeds, effects and context work in plain Node, because the core
has no DOM dependency.
function subscriberCount(source: object): number;
How many live subscribers a signal or computed has. This is the number a leak test wants: after disposing whatever was watching it, a source that still has subscribers is still reachable from the graph, and nothing it references can be collected.
const view = mount(() => <Thing value={count} />);
view.unmount();
expect(subscriberCount(count)).toBe(0);
It reads the graph rather than guessing from the heap, so it is deterministic in every engine.
function tick(ms?: number): Promise<void>;
Waits for pending microtasks and, optionally, a timer. Firsthand updates the DOM
synchronously (ADR-0006), so this is not
needed after a signal write. It is here for the ordinary reason any test needs
it: an await in application code, a fetch, a queueMicrotask.