// @vitest-environment node /** * block-patch-store — the presence fold (TASK-0093). The store keys peers * by (pageId, userId): upsertPresence folds a per-peer `presence` frame, * removePresence drops one (`presence-leave`). The block overlay is * untouched by presence frames (and vice versa). */ import { beforeEach, describe, expect, it } from "vitest"; import { useBlockPatchStore } from "../block-patch-store"; import type { Presence } from "@/lib/types"; const peer = (userId: string, extra?: Partial): Presence => ({ userId, name: `Name ${userId}`, color: "#123456", cursor: null, lastSeen: 1_700_000_000_000, ...extra, }); const state = () => useBlockPatchStore.getState(); describe("block-patch-store — presence fold (per-peer frames, TASK-0093)", () => { beforeEach(() => { useBlockPatchStore.setState({ patches: {}, upserts: {}, deleted: {}, presence: {} }); }); it("upsertPresence adds a peer to the page's roster", () => { state().upsertPresence("pg_1", peer("u1", { cursor: { blockId: "blk_1", offset: 3 } })); expect(state().presence["pg_1"]).toEqual({ u1: peer("u1", { cursor: { blockId: "blk_1", offset: 3 } }), }); }); it("a later presence frame UPDATES the same peer in place (no duplicate)", () => { state().upsertPresence("pg_1", peer("u1")); state().upsertPresence( "pg_1", peer("u1", { cursor: { blockId: "blk_2", offset: 9 }, lastSeen: 1_700_000_000_500 }), ); expect(Object.keys(state().presence["pg_1"] ?? {})).toEqual(["u1"]); expect(state().presence["pg_1"]?.u1).toMatchObject({ cursor: { blockId: "blk_2", offset: 9 }, lastSeen: 1_700_000_000_500, }); }); it("different peers on the same page are both kept", () => { state().upsertPresence("pg_1", peer("u1")); state().upsertPresence("pg_1", peer("u2")); expect(Object.keys(state().presence["pg_1"] ?? {})).toEqual(["u1", "u2"]); }); it("removePresence (presence-leave) drops exactly that peer", () => { state().upsertPresence("pg_1", peer("u1")); state().upsertPresence("pg_1", peer("u2")); state().removePresence("pg_1", "u1"); expect(Object.keys(state().presence["pg_1"] ?? {})).toEqual(["u2"]); }); it("removePresence for an unknown peer is a no-op (idempotent)", () => { state().upsertPresence("pg_1", peer("u1")); state().removePresence("pg_1", "ghost"); state().removePresence("pg_1", "u1"); state().removePresence("pg_1", "u1"); // again — no crash, no entry expect(state().presence["pg_1"]).toEqual({}); }); it("presence state is per-page (a leave on one page never touches another)", () => { state().upsertPresence("pg_1", peer("u1")); state().upsertPresence("pg_2", peer("u1")); state().removePresence("pg_1", "u1"); expect(state().presence["pg_1"]).toEqual({}); expect(Object.keys(state().presence["pg_2"] ?? {})).toEqual(["u1"]); }); it("reset drops the page's presence (page unmount)", () => { state().upsertPresence("pg_1", peer("u1")); state().reset("pg_1"); expect(state().presence["pg_1"]).toEqual({}); }); it("clearBlocks keeps presence (a block change must not wipe who's online)", () => { state().upsertPresence("pg_1", peer("u1")); state().clearBlocks("pg_1"); expect(Object.keys(state().presence["pg_1"] ?? {})).toEqual(["u1"]); }); });