feat(core-testing): RecordingEventBus
Adds RecordingEventBus implementing IEventBus for use in unit tests. Validates payloads via the descriptor schema, records all publish calls, and delivers events to subscribed handlers synchronously in subscription order. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
export { RecordingTracer, type RecordedSpan } from "./recording-tracer";
|
||||
export { RecordingLogger, type RecordedCapture } from "./recording-logger";
|
||||
export { RecordingJobQueue } from "./recording-job-queue";
|
||||
export { RecordingEventBus } from "./recording-event-bus";
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { z } from "zod";
|
||||
import { defineEvent } from "@repo/core-events";
|
||||
import { RecordingEventBus } from "@/instrumentation/recording-event-bus";
|
||||
|
||||
const evt = defineEvent("test.evt", z.object({ id: z.string() }).strict());
|
||||
|
||||
describe("RecordingEventBus", () => {
|
||||
it("records every publish call after schema validation", async () => {
|
||||
const bus = new RecordingEventBus();
|
||||
await bus.publish(evt, { id: "a" });
|
||||
await bus.publish(evt, { id: "b" });
|
||||
expect(bus.published).toEqual([
|
||||
{ name: "test.evt", payload: { id: "a" } },
|
||||
{ name: "test.evt", payload: { id: "b" } },
|
||||
]);
|
||||
});
|
||||
|
||||
it("rejects invalid payloads", async () => {
|
||||
const bus = new RecordingEventBus();
|
||||
await expect(
|
||||
bus.publish(evt, { id: 1 } as unknown as { id: string }),
|
||||
).rejects.toThrow();
|
||||
expect(bus.published).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("invokes registered handlers sequentially in subscription order", async () => {
|
||||
const bus = new RecordingEventBus();
|
||||
const order: string[] = [];
|
||||
bus.subscribe(evt, "consumer-a", async () => {
|
||||
order.push("a");
|
||||
});
|
||||
bus.subscribe(evt, "consumer-b", async () => {
|
||||
order.push("b");
|
||||
});
|
||||
await bus.publish(evt, { id: "x" });
|
||||
expect(order).toEqual(["a", "b"]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
import type { z } from "zod";
|
||||
import type { EventDescriptor, EventHandler, IEventBus } from "@repo/core-events";
|
||||
|
||||
export class RecordingEventBus implements IEventBus {
|
||||
readonly published: { name: string; payload: unknown }[] = [];
|
||||
private readonly handlers = new Map<string, EventHandler<unknown>[]>();
|
||||
|
||||
async publish<T>(
|
||||
descriptor: EventDescriptor<string, z.ZodType<T>>,
|
||||
payload: T,
|
||||
): Promise<void> {
|
||||
descriptor.schema.parse(payload);
|
||||
this.published.push({ name: descriptor.name, payload });
|
||||
for (const h of this.handlers.get(descriptor.name) ?? []) await h(payload);
|
||||
}
|
||||
|
||||
subscribe<T>(
|
||||
descriptor: EventDescriptor<string, z.ZodType<T>>,
|
||||
_consumerFeature: string,
|
||||
handler: EventHandler<T>,
|
||||
): void {
|
||||
const arr = this.handlers.get(descriptor.name) ?? [];
|
||||
arr.push(handler as EventHandler<unknown>);
|
||||
this.handlers.set(descriptor.name, arr);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user