Files
suaveplan/packages/api-stack/api/api-db-worker-proxy/src/testing/testing.md
2026-05-27 23:29:53 +01:00

3.1 KiB

testing

(no submodules)

Purpose

This module provides the in-memory test harness for @suaveplan/api-db-worker-proxy. It exposes createInMemoryAdminDb — a deterministic AdminDatabaseLike backed by a Map — and createDbProxyHarness, which pairs that adapter with a real MessageChannel, a createDbProxyServer on one port, and a createDbProxyClient on the other. Tests can drive the full client-port-server-adapter chain end-to-end without a real DB and without any mocking framework.

The harness exists in src/testing/ (rather than tests/) so it can be imported by downstream Stage-4 adapter packages from the package's "./testing" subpath export.

Features

  • createInMemoryAdminDb({ engine?, seed?, cursorDelayMs? }) — a full AdminDatabaseLike implementation including prepare, transaction, and a synthetic SELECT-CURSOR * that returns an AsyncIterable<MemoryRow> for cursor streaming tests.
  • createDbProxyHarness(opts) — bundles adapter + ports + server + client into one disposable handle.
  • Tiny command DSL (INSERT <id>, DELETE <id>, SELECT *, SELECT-CURSOR *, COUNT, SELECT-SCALAR, THROW) chosen so every code path in the proxy can be exercised without parsing real SQL.

Usage: Basic

import { createDbProxyHarness } from "@suaveplan/api-db-worker-proxy/testing";

const h = createDbProxyHarness({ seed: [["a", { v: 1 }]] });
try {
    expect(await h.client.query("SELECT *")).toEqual([{ v: 1 }]);
} finally {
    await h.client.close();
    h.close();
}

Usage: Advanced

To assert that cursor cancellation propagates, set a per-row delay on the in-memory cursor and abort partway through:

const h = createDbProxyHarness({
    seed: Array.from({ length: 100 }, (_, i) => [String(i), { i }]),
    cursorDelayMs: 5,
});
try {
    const ac = new AbortController();
    let n = 0;
    for await (const _row of h.client.cursor("SELECT-CURSOR *", undefined, {
        signal: ac.signal,
    })) {
        if (++n >= 3) {
            ac.abort();
            break;
        }
    }
    expect(n).toBe(3);
} finally {
    await h.client.close();
    h.close();
}

API Reference

  • createInMemoryAdminDb(opts?): InMemoryAdminDb — AdminDatabaseLike plus rows: ReadonlyMap<string, MemoryRow> and closed(): boolean for assertions.
  • createDbProxyHarness(opts?): DbProxyHarness — { db, server, client, ports, close() }.
  • InMemoryAdminDbOptions — { engine?, seed?, cursorDelayMs? }.

Implementation Notes

The in-memory adapter ignores parameter placeholders for INSERT / DELETE and instead encodes the row key in the SQL string. This is intentional — the harness exists to exercise the proxy plumbing, not to validate a real query language. Concrete adapters (Stage 4) ship their own conformance suites under their own engine semantics.

The harness's close() does NOT call client.close() so tests can choose between observing graceful close (await client.close()) and abrupt disconnect (client.dispose(), then harness.close()). Both paths are first-class.