import { describe, it, expect } from "vitest"; import type { z } from "zod"; import { RUNNER_STAGES, RUNNER_ERROR_CAUSES, helloMessageSchema, readyMessageSchema, cloneMessageSchema, installMessageSchema, scanMessageSchema, adapterStartMessageSchema, renderFrameMessageSchema, statusMessageSchema, errorMessageSchema, runnerMessageSchema, type RunnerMessage, } from "@/messages"; /** Serialize → deserialize → parse: the honest wire round-trip. */ function wireRoundTrip(schema: z.ZodTypeAny, value: unknown): unknown { return schema.parse(JSON.parse(JSON.stringify(value))); } describe("helloMessageSchema", () => { it("accepts a wire round-trip", () => { const msg = { type: "hello" }; expect(wireRoundTrip(helloMessageSchema, msg)).toEqual(msg); }); it("rejects unknown fields", () => { expect(() => helloMessageSchema.parse({ type: "hello", extra: true }), ).toThrow(); }); it("rejects a wrong type literal", () => { expect(() => helloMessageSchema.parse({ type: "ready" })).toThrow(); }); }); describe("readyMessageSchema", () => { it("accepts a wire round-trip", () => { const msg = { type: "ready" }; expect(wireRoundTrip(readyMessageSchema, msg)).toEqual(msg); }); it("rejects unknown fields", () => { expect(() => readyMessageSchema.parse({ type: "ready", capabilities: [] }), ).toThrow(); }); }); describe("cloneMessageSchema", () => { it("accepts a wire round-trip with a PAT", () => { const msg = { type: "clone", gitUrl: "https://git.example.com/acme/design-system.git", pat: "ghp_workspace-scoped", }; expect(wireRoundTrip(cloneMessageSchema, msg)).toEqual(msg); }); it("accepts a public clone without a PAT", () => { const msg = { type: "clone", gitUrl: "https://git.example.com/oss.git" }; expect(wireRoundTrip(cloneMessageSchema, msg)).toEqual(msg); }); it("rejects a missing gitUrl", () => { expect(() => cloneMessageSchema.parse({ type: "clone" })).toThrow(); }); it("rejects an empty gitUrl", () => { expect(() => cloneMessageSchema.parse({ type: "clone", gitUrl: "" }), ).toThrow(); }); it("rejects unknown fields", () => { expect(() => cloneMessageSchema.parse({ type: "clone", gitUrl: "https://git.example.com/x.git", branch: "main", }), ).toThrow(); }); }); describe("installMessageSchema", () => { it("accepts a wire round-trip", () => { const msg = { type: "install" }; expect(wireRoundTrip(installMessageSchema, msg)).toEqual(msg); }); it("rejects unknown fields", () => { expect(() => installMessageSchema.parse({ type: "install", packageManager: "pnpm" }), ).toThrow(); }); }); describe("scanMessageSchema", () => { it("accepts a wire round-trip", () => { const msg = { type: "scan" }; expect(wireRoundTrip(scanMessageSchema, msg)).toEqual(msg); }); it("rejects unknown fields", () => { expect(() => scanMessageSchema.parse({ type: "scan", glob: "src/**" }), ).toThrow(); }); }); describe("adapterStartMessageSchema", () => { it("accepts a wire round-trip", () => { const msg = { type: "adapter-start" }; expect(wireRoundTrip(adapterStartMessageSchema, msg)).toEqual(msg); }); it("rejects unknown fields", () => { expect(() => adapterStartMessageSchema.parse({ type: "adapter-start", port: 5173 }), ).toThrow(); }); }); describe("renderFrameMessageSchema", () => { it("accepts a wire round-trip with props", () => { const msg = { type: "render-frame", componentId: "button", props: { label: "Save", disabled: false }, }; expect(wireRoundTrip(renderFrameMessageSchema, msg)).toEqual(msg); }); it("accepts default props by omission", () => { const msg = { type: "render-frame", componentId: "button" }; expect(wireRoundTrip(renderFrameMessageSchema, msg)).toEqual(msg); }); it("rejects a missing componentId", () => { expect(() => renderFrameMessageSchema.parse({ type: "render-frame" }), ).toThrow(); }); it("rejects unknown fields", () => { expect(() => renderFrameMessageSchema.parse({ type: "render-frame", componentId: "button", viewport: "mobile", }), ).toThrow(); }); }); describe("statusMessageSchema", () => { it.each(RUNNER_STAGES)("accepts a wire round-trip for stage %s", (stage) => { const msg = { type: "status", stage, elapsedMs: 1200 }; expect(wireRoundTrip(statusMessageSchema, msg)).toEqual(msg); }); it("rejects an unknown stage", () => { expect(() => statusMessageSchema.parse({ type: "status", stage: "compiling", elapsedMs: 0, }), ).toThrow(); }); it("rejects a missing elapsedMs", () => { expect(() => statusMessageSchema.parse({ type: "status", stage: "cloning" }), ).toThrow(); }); it("rejects a negative elapsedMs", () => { expect(() => statusMessageSchema.parse({ type: "status", stage: "cloning", elapsedMs: -1, }), ).toThrow(); }); it("rejects a non-integer elapsedMs", () => { expect(() => statusMessageSchema.parse({ type: "status", stage: "cloning", elapsedMs: 3.5, }), ).toThrow(); }); it("rejects unknown fields", () => { expect(() => statusMessageSchema.parse({ type: "status", stage: "cloning", elapsedMs: 0, percent: 40, }), ).toThrow(); }); }); describe("errorMessageSchema", () => { it.each(RUNNER_ERROR_CAUSES)( "accepts a wire round-trip for cause %s", (cause) => { const msg = { type: "error", cause, message: "named cause surfaced" }; expect(wireRoundTrip(errorMessageSchema, msg)).toEqual(msg); }, ); it("accepts an error pinned to a stage", () => { const msg = { type: "error", cause: "install-failed", message: "pnpm install exited 1", stage: "installing", }; expect(wireRoundTrip(errorMessageSchema, msg)).toEqual(msg); }); it("rejects an unknown cause", () => { expect(() => errorMessageSchema.parse({ type: "error", cause: "mystery", message: "?", }), ).toThrow(); }); it("rejects an empty message", () => { expect(() => errorMessageSchema.parse({ type: "error", cause: "clone-failed", message: "", }), ).toThrow(); }); it("rejects an unknown stage", () => { expect(() => errorMessageSchema.parse({ type: "error", cause: "clone-failed", message: "x", stage: "compiling", }), ).toThrow(); }); it("rejects unknown fields", () => { expect(() => errorMessageSchema.parse({ type: "error", cause: "clone-failed", message: "x", retryable: true, }), ).toThrow(); }); }); describe("runnerMessageSchema (discriminated union)", () => { const oneOfEach: RunnerMessage[] = [ { type: "hello" }, { type: "ready" }, { type: "clone", gitUrl: "https://git.example.com/acme.git", pat: "tok" }, { type: "install" }, { type: "scan" }, { type: "adapter-start" }, { type: "render-frame", componentId: "button", props: { label: "Go" } }, { type: "status", stage: "cloning", elapsedMs: 42 }, { type: "error", cause: "clone-failed", message: "boom", stage: "cloning" }, ]; it.each(oneOfEach.map((msg) => [msg.type, msg] as const))( "routes %s through the union on a wire round-trip", (_type, msg) => { expect(wireRoundTrip(runnerMessageSchema, msg)).toEqual(msg); }, ); it("rejects an unknown type", () => { expect(() => runnerMessageSchema.parse({ type: "watch" })).toThrow(); }); it("rejects a missing type", () => { expect(() => runnerMessageSchema.parse({})).toThrow(); }); it("rejects a known type with another type's fields", () => { expect(() => runnerMessageSchema.parse({ type: "install", stage: "installing" }), ).toThrow(); }); });