Skip to content

@repo/datadata/test

Test helpers: a mock live client, a recording logger, and a collector for write errors.

Functions

collectWriteErrors

export declare function collectWriteErrors(client: {
    onWriteError: (cb: (error: WriteError) => void) => () => void;
}): WriteError[];

Register an onWriteError listener and return the array it accumulates into. A rejected fire-and-forget write surfaces here (awaited writes reject their promise instead), so tests assert on this rather than a status-doc error.

createMockLiveClient

export declare function createMockLiveClient<Live>(live: Live): MockLiveClient<Live>;

Wraps a faked live-session object as a MockLiveClient, so a unit mock can hand the result anywhere a client.live-shaped value is expected without writing the { live: … } wrapper (or the cast) inline. Live is inferred from the argument:

const client = createMockLiveClient({
  createDocument: vi.fn(),
  updateDocument: vi.fn(),
});
client.live.createDocument(...);

For a full in-memory fake instead of a hand-rolled one, reach for createInMemoryClient from @repo/datadata/in-memory.

createMockLogger

export declare function createMockLogger(): MockLogger;

A MockLogger that discards output and records every call. child() returns the same logger, so calls made through a child are recorded on it too.

getMockedLogs

export declare function getMockedLogs(logger: MockLogger): Record<string, unknown[]>;

The first argument of every recorded call, grouped by level (info, warn, error, debug), for snapshotting. Levels with no calls are left out.

Types

MockLiveClient

export type MockLiveClient<Live = Partial<LiveSession>> = {
    live: Live;
};

Shape of a hand-rolled client double for code that only touches the live editing surface.

Since editing/reading moved off the bare client onto the ambient live session, every mock that fakes createDocument / updateDocument / getDocument must nest them under .live, exactly where the real client keeps them. This type captures that one bit of structure so consumers don't re-derive the nesting (and the as unknown as … cast) by hand. Pick the subset you actually call from LiveSession:

import type { LiveSession } from "@repo/datadata/session";
import type { MockLiveClient } from "@repo/datadata/test";
type Bridge = MockLiveClient<Pick<LiveSession, "createDocument" | "updateDocument">>;

MockLogger

export type MockLogger = Logger & {
    info: RecordedFn<Parameters<Logger["info"]>, void>;
    warn: RecordedFn<Parameters<Logger["warn"]>, void>;
    error: RecordedFn<Parameters<Logger["error"]>, void>;
    debug: RecordedFn<Parameters<Logger["debug"]>, void>;
    child: RecordedFn<Parameters<Logger["child"]>, Logger>;
};

A Logger whose methods record their calls; see createMockLogger.

RecordedFn

export type RecordedFn<Args extends unknown[], Return> = ((...args: Args) => Return) & {
    calls: Args[];
};

A function that records the arguments of every call in calls. Not a vitest mock, so it works outside vitest too.