import { describe, expect, it } from "vitest"; import { BlockChangedFrameSchema, ClientFrameSchema, PresenceBroadcastSchema, PresenceFrameSchema, PresenceLeaveBroadcastSchema, PresenceLeaveFrameSchema, ServerFrameSchema, } from "./frames.js"; describe("BlockChangedFrameSchema (TASK-0092 (b) refetch-hint)", () => { it("accepts a pageId (+ optional advisory version)", () => { const r = BlockChangedFrameSchema.safeParse({ type: "block:changed", pageId: "pg_1", version: 7, }); expect(r.success).toBe(true); if (r.success) expect(r.data).toEqual({ type: "block:changed", pageId: "pg_1", version: 7 }); }); it("version is optional (a REST write may omit it)", () => { const r = BlockChangedFrameSchema.safeParse({ type: "block:changed", pageId: "pg_1" }); expect(r.success).toBe(true); if (r.success) expect(r.data).toEqual({ type: "block:changed", pageId: "pg_1" }); }); it("rejects an empty pageId", () => { expect(BlockChangedFrameSchema.safeParse({ type: "block:changed", pageId: "" }).success).toBe( false, ); }); it("rejects a non-integer / <1 version", () => { expect( BlockChangedFrameSchema.safeParse({ type: "block:changed", pageId: "pg_1", version: 0 }) .success, ).toBe(false); expect( BlockChangedFrameSchema.safeParse({ type: "block:changed", pageId: "pg_1", version: 1.5 }) .success, ).toBe(false); }); it("is a member of the ServerFrame discriminated union", () => { const r = ServerFrameSchema.safeParse({ type: "block:changed", pageId: "pg_1", version: 3 }); expect(r.success).toBe(true); }); }); describe("PresenceFrameSchema / PresenceLeaveFrameSchema (TASK-0093 client frames)", () => { it("accepts a cursor move (blockId + offset)", () => { const r = PresenceFrameSchema.safeParse({ type: "presence", cursor: { blockId: "b3", offset: 4 }, }); expect(r.success).toBe(true); }); it("accepts a cursor with a (multi-block) selection range", () => { const r = PresenceFrameSchema.safeParse({ type: "presence", cursor: { blockId: "b3", offset: 2, selection: { fromBlockId: "b3", fromOffset: 0, toBlockId: "b4", toOffset: 5 }, }, viewing: true, }); expect(r.success).toBe(true); }); it("accepts a cursor CLEAR (cursor: null — tab hidden / blur)", () => { const r = PresenceFrameSchema.safeParse({ type: "presence", cursor: null, viewing: false }); expect(r.success).toBe(true); if (r.success) expect(r.data.cursor).toBeNull(); }); it("accepts a viewing-only update (cursor absent = no change)", () => { const r = PresenceFrameSchema.safeParse({ type: "presence", viewing: false }); expect(r.success).toBe(true); if (r.success) expect(r.data.cursor).toBeUndefined(); }); it("rejects a non-integer / negative offset", () => { expect( PresenceFrameSchema.safeParse({ type: "presence", cursor: { blockId: "b3", offset: -1 } }) .success, ).toBe(false); expect( PresenceFrameSchema.safeParse({ type: "presence", cursor: { blockId: "b3", offset: 1.5 } }) .success, ).toBe(false); }); it("rejects an empty blockId", () => { expect( PresenceFrameSchema.safeParse({ type: "presence", cursor: { blockId: "", offset: 0 } }) .success, ).toBe(false); }); it("is a member of the ClientFrame discriminated union (both frames)", () => { expect( ClientFrameSchema.safeParse({ type: "presence", cursor: { blockId: "b3", offset: 0 } }) .success, ).toBe(true); expect(ClientFrameSchema.safeParse({ type: "presence-leave" }).success).toBe(true); }); it("presence-leave carries no payload", () => { const r = PresenceLeaveFrameSchema.safeParse({ type: "presence-leave" }); expect(r.success).toBe(true); }); }); describe("PresenceBroadcastSchema (TASK-0093 server → client)", () => { const user = { id: "u-1", name: "Ana", color: "sky" }; it("accepts a full peer state (user + cursor + viewing + lastSeen)", () => { const r = PresenceBroadcastSchema.safeParse({ type: "presence", pageId: "pg_1", user, cursor: { blockId: "b3", offset: 4 }, viewing: true, lastSeen: 1700000000000, }); expect(r.success).toBe(true); }); it("accepts an avatars-only state (cap strip: no cursor, no viewing)", () => { const r = PresenceBroadcastSchema.safeParse({ type: "presence", pageId: "pg_1", user, lastSeen: 1700000000000, }); expect(r.success).toBe(true); }); it("rejects an empty pageId or a missing/empty user id", () => { expect( PresenceBroadcastSchema.safeParse({ type: "presence", pageId: "", user, lastSeen: 1 }) .success, ).toBe(false); expect( PresenceBroadcastSchema.safeParse({ type: "presence", pageId: "pg_1", user: { id: "", name: "A", color: "sky" }, lastSeen: 1, }).success, ).toBe(false); }); it("is a member of the ServerFrame discriminated union", () => { expect( ServerFrameSchema.safeParse({ type: "presence", pageId: "pg_1", user, lastSeen: 1 }).success, ).toBe(true); }); }); describe("PresenceLeaveBroadcastSchema (TASK-0093 server → client leave)", () => { it("accepts a leave with a room id + user id", () => { const r = PresenceLeaveBroadcastSchema.safeParse({ type: "presence-leave", pageId: "page:pg_1", userId: "u-1", }); expect(r.success).toBe(true); }); it("rejects an empty room id or user id", () => { expect( PresenceLeaveBroadcastSchema.safeParse({ type: "presence-leave", pageId: "", userId: "u-1" }) .success, ).toBe(false); expect( PresenceLeaveBroadcastSchema.safeParse({ type: "presence-leave", pageId: "page:pg_1", userId: "", }).success, ).toBe(false); }); it("is a member of the ServerFrame discriminated union", () => { expect( ServerFrameSchema.safeParse({ type: "presence-leave", pageId: "page:pg_1", userId: "u-1" }) .success, ).toBe(true); }); });