# `createInMemoryEventsBusHarness` _(no submodules)_ ## Purpose The testing harness packages an {@link InMemoryEventsBus} with a `waitFor` helper for tests that publish asynchronously and need to assert on history once the publish has settled. It is the standard shape downstream plugin tests will import to avoid hand-rolling a poll-with-timeout loop for every assertion. Importing `@suaveplan/api-events-in-memory/testing` returns a tightly-scoped surface that won't leak production-only construction details into test code. ## Features - Fresh bus per harness — call `createInMemoryEventsBusHarness()` once per test, `dispose()` at teardown; no shared state across cases. - `waitFor(predicate, { timeoutMs, intervalMs })` polls until the predicate holds or the timeout elapses. The default timeout (1 s) and interval (5 ms) work for the overwhelming majority of unit tests; override only when integrating with slower infra. - Fast path: if the predicate already holds at call time the function resolves on the next microtask without sleeping. - Reject-on-timeout includes the requested `timeoutMs` in the message so test failures are easy to triage. - All options forwarded verbatim to {@link createInMemoryEventsBus}, so the harness inherits the strict-throw history-overflow policy and the Zod-validated options boundary. ## Usage: Basic ```ts import { createInMemoryEventsBusHarness } from "@suaveplan/api-events-in-memory/testing"; const harness = createInMemoryEventsBusHarness(); const { bus, waitFor } = harness; bus.on("user.signup", async () => { await Promise.resolve(); bus.publish("welcome.email.queued", { to: "u@example.com" }); }); await bus.publishAsync("user.signup", { userId: "u1" }); await waitFor((b) => b.published("welcome.email.queued").length === 1); console.log(bus.published("welcome.email.queued")); harness.dispose(); ``` ## Usage: Advanced Tighten the deadline for a fast unit test, or extend it for an integration test that sits behind a real database: ```ts import { createInMemoryEventsBusHarness } from "@suaveplan/api-events-in-memory/testing"; const harness = createInMemoryEventsBusHarness({ maxHistoryPerTopic: 50 }); try { await harness.waitFor( (bus) => bus.published("payment.captured").length >= 3, { timeoutMs: 5000, intervalMs: 25 } ); } catch (error) { console.error("payment.captured fan-out stalled:", error); throw error; } finally { harness.dispose(); } ``` `dispose()` is idempotent — calling it twice in `afterEach` after a mid-test failure is safe. ## API Reference - `createInMemoryEventsBusHarness(options?): InMemoryEventsBusHarness` — factory. - `InMemoryEventsBusHarness.bus: InMemoryEventsBus` — the wrapped bus. - `InMemoryEventsBusHarness.waitFor(predicate, options?): Promise` — poll-with-timeout. - `InMemoryEventsBusHarness.dispose(): void` — tear down the bus. - `WaitForPredicate = (bus: InMemoryEventsBus) => boolean`. - `WaitForOptions = { timeoutMs?: number; intervalMs?: number }`. ## Implementation Notes `waitFor` uses `setTimeout` rather than `setImmediate`/`queueMicrotask` because real tests need to interleave with timers managed by the runtime; busy-looping on microtasks starves them. The harness owns `dispose` rather than asking the caller to call `bus.dispose()` directly so that future versions can add additional resources (meter providers, span recorders) without breaking the test surface.