feat(core-testing): RecordingRealtimeBroadcaster (local-type-alias pattern)

This commit is contained in:
2026-05-08 21:56:18 +02:00
parent 228cfb57c0
commit 928357f221
3 changed files with 57 additions and 0 deletions

View File

@@ -2,3 +2,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";
export { RecordingRealtimeBroadcaster } from "./recording-realtime-broadcaster";

View File

@@ -0,0 +1,27 @@
import { describe, it, expect } from "vitest";
import { z } from "zod";
import { RecordingRealtimeBroadcaster } from "@/instrumentation/recording-realtime-broadcaster";
const ch = {
name: "test.ch" as const,
schema: z.object({ x: z.number() }).strict(),
scope: "public" as const,
};
describe("RecordingRealtimeBroadcaster", () => {
it("records every broadcast call after schema validation", async () => {
const b = new RecordingRealtimeBroadcaster();
await b.broadcast(ch, { x: 1 });
await b.broadcast(ch, { x: 2 });
expect(b.broadcasts).toEqual([
{ channel: "test.ch", payload: { x: 1 } },
{ channel: "test.ch", payload: { x: 2 } },
]);
});
it("rejects payloads that fail schema validation", async () => {
const b = new RecordingRealtimeBroadcaster();
await expect(b.broadcast(ch, { x: "wrong" } as never)).rejects.toThrow();
expect(b.broadcasts).toHaveLength(0);
});
});

View File

@@ -0,0 +1,29 @@
// Local type aliases mirroring @repo/core-realtime's contracts. Kept inline to
// avoid a build-graph cycle between core-testing (tooling) and core-realtime (core).
// Same pattern recording-event-bus + recording-job-queue use.
import type { z } from "zod";
type RealtimeChannelDescriptor<TName extends string, TSchema extends z.ZodType> = {
readonly name: TName;
readonly schema: TSchema;
readonly scope?: string;
};
interface IRealtimeBroadcaster {
broadcast<T>(
descriptor: RealtimeChannelDescriptor<string, z.ZodType<T>>,
payload: T,
): Promise<void>;
}
export class RecordingRealtimeBroadcaster implements IRealtimeBroadcaster {
readonly broadcasts: { channel: string; payload: unknown }[] = [];
async broadcast<T>(
descriptor: RealtimeChannelDescriptor<string, z.ZodType<T>>,
payload: T,
): Promise<void> {
descriptor.schema.parse(payload);
this.broadcasts.push({ channel: descriptor.name, payload });
}
}