4.6 KiB
4.6 KiB
testing — createInMemoryBrokerHarness
(no submodules)
Purpose
This module exposes a small, opinionated test harness around the
in-memory broker. It removes the boilerplate of wiring an observer
subscription and a teardown helper, so most tests collapse to "build
harness, publish, assert on received, dispose". The harness deliberately
shares the production broker — there is no separate "fake" broker hiding
underneath — which means every assertion exercises the real fan-out
pipeline and every regression caught in tests is one that would also
manifest in production single-host deployments.
The harness lives under ./testing (not the main entry) so consumer
production bundles never pay for the helper machinery; only test bundles
import this subpath.
Features
createInMemoryBrokerHarness(opts?)factory that returns a ready-to-use bundle of{ broker, received, observerSubscription, publishOne, dispose }.- A pre-registered observer subscription on the harness's default topic
(
"test.events") plus an extensibleextraTopicslist so tests that probe the registry shape don't need to subscribe manually. publishOne(payload, opts?)convenience that materialises a fullBrokerEnvelopefrom a payload, defaultingtopicandtenantfrom the harness configuration.dispose()is idempotent and tolerant of partial teardown — it can be called fromafterEacheven if the test itself disposed the broker directly.
Usage: Basic
import { describe, expect, it } from "@suaveplan/testing/runner";
import { createInMemoryBrokerHarness } from "@suaveplan/api-ws-broker-in-memory/testing";
describe("broker harness", () => {
it("captures every published envelope", { timeout: 5000 }, async () => {
const harness = createInMemoryBrokerHarness<{ id: number }>();
try {
await harness.publishOne({ id: 1 });
await harness.publishOne({ id: 2 });
expect(harness.received.map((e) => e.payload.id)).toEqual([1, 2]);
} finally {
harness.dispose();
}
});
});
Usage: Advanced
import { describe, expect, it } from "@suaveplan/testing/runner";
import type { TenantId } from "@suaveplan/api-types/tenant";
import { createInMemoryBrokerHarness } from "@suaveplan/api-ws-broker-in-memory/testing";
describe("broker harness — await-all + multi-topic", () => {
it("delivers across additional topics", { timeout: 5000 }, async () => {
const harness = createInMemoryBrokerHarness<string>({
broker: { deliveryMode: "await-all" },
topic: "orders",
tenant: "t1" as unknown as TenantId,
extraTopics: ["audit", "billing"],
});
try {
await harness.publishOne("ok", { topic: "orders" });
// The probe subscribers on audit/billing keep them
// registered for `subscriberCount` introspection.
expect(harness.broker.subscriberCount("orders")).toBe(1);
expect(harness.broker.subscriberCount("audit")).toBe(1);
expect(harness.received).toHaveLength(1);
expect(harness.received[0]?.payload).toBe("ok");
} finally {
harness.dispose();
}
});
});
API Reference
createInMemoryBrokerHarness<Payload>(opts?): InMemoryBrokerHarness<Payload>interface CreateInMemoryBrokerHarnessOptions<Payload>—{ broker?, topic?, tenant?, extraTopics?, initialPayload? }.interface InMemoryBrokerHarness<Payload>—{ broker, received, observerSubscription, publishOne, dispose }.
Implementation Notes
- The harness is deliberately tiny — it intentionally does NOT
attempt to drive the
runWsEngineConformanceharness, because that one expects a full(bus, registry, broker, makeConnection)tuple while this package only owns the broker leg. The package's conformance test intests/conformance/runs broker-shaped type assertions instead, which is the right scope for a broker-only package. extraTopicsregister a no-op subscriber so the topic survives in the registry for introspection (subscriberCount(topic) === 1). Without a probe subscriber the in-memory broker reaps zero-size topic entries from itsMapandsubscriberCountwould report 0, which is the correct production behaviour but inconvenient when a test wants to assert "this topic exists right now".- The harness wraps the observer unsubscribe and broker dispose in
separate
try/catchblocks so an out-of-order teardown (test disposes the broker, thenafterEachcallsharness.dispose()) does not surface staleBROKER_DISPOSEDerrors.