import { scopedThreadKey, scopeThreadRef } from "@t3tools/client-runtime/environment";import { type EnvironmentId, type PreviewEvent, type PreviewSessionSnapshot, ThreadId,} from "@t3tools/contracts";import { beforeEach, describe, expect, it } from "vite-plus/test"; import { __testing, applyPreviewDesktopState, applyPreviewServerEvent as applyPreviewServerEventImpl, applyPreviewServerSnapshot, beginPreviewSessionClose, cancelPreviewSessionClose, previewStateAtom, readThreadPreviewState, reconcilePreviewServerSessions, rememberPreviewUrl, resetPreviewStateForTests, setActivePreviewTab, updatePreviewServerSnapshot,} from "./previewStateStore";import { appAtomRegistry } from "./rpc/atomRegistry"; const environmentId = "env-1" as EnvironmentId;const ref = scopeThreadRef(environmentId, ThreadId.make("thread-1"));const otherRef = scopeThreadRef(environmentId, ThreadId.make("thread-2")); const makeSnapshot = (overrides: Partial<PreviewSessionSnapshot> = {}): PreviewSessionSnapshot => ({ threadId: "thread-1", tabId: "tab_a", navStatus: { _tag: "Loading", url: "http://localhost:5173/", title: "" }, canGoBack: false, canGoForward: false, updatedAt: "2026-01-01T00:00:00.000Z", ...overrides,}); type PreviewEventDraft = PreviewEvent extends infer Event ? Event extends { readonly revision: number } ? Omit<Event, "revision" | "serverEpoch"> : never : never; const serverEpoch = "server-a";let nextServerRevision = 0;const applyPreviewServerEvent = (eventRef: typeof ref, event: PreviewEventDraft): void => { nextServerRevision += 1; applyPreviewServerEventImpl(eventRef, { ...event, serverEpoch, revision: nextServerRevision, } as PreviewEvent);}; beforeEach(() => { nextServerRevision = 0; resetPreviewStateForTests();}); describe("previewStateStore (single-tab)", () => { it("keeps independent state atoms for each thread", () => { expect(previewStateAtom(scopedThreadKey(ref))).toBe(previewStateAtom(scopedThreadKey(ref))); expect(previewStateAtom(scopedThreadKey(ref))).not.toBe( previewStateAtom(scopedThreadKey(otherRef)), ); applyPreviewServerSnapshot(ref, makeSnapshot()); expect(readThreadPreviewState(ref).snapshot?.tabId).toBe("tab_a"); expect(readThreadPreviewState(otherRef)).toEqual(__testing.EMPTY_THREAD_PREVIEW_STATE); }); it("opened event seeds the snapshot and remembers the URL", () => { const snapshot = makeSnapshot(); applyPreviewServerEvent(ref, { type: "opened", threadId: "thread-1", tabId: snapshot.tabId, createdAt: snapshot.updatedAt, snapshot, }); const state = readThreadPreviewState(ref); expect(state.snapshot?.tabId).toBe(snapshot.tabId); expect(state.recentlySeenUrls).toContain("http://localhost:5173/"); }); it("a second `opened` for a different tab replaces the rendered snapshot", () => { const a = makeSnapshot({ tabId: "tab_a" }); const b = makeSnapshot({ tabId: "tab_b" }); applyPreviewServerEvent(ref, { type: "opened", threadId: "thread-1", tabId: a.tabId, createdAt: a.updatedAt, snapshot: a, }); applyPreviewServerEvent(ref, { type: "opened", threadId: "thread-1", tabId: b.tabId, createdAt: b.updatedAt, snapshot: b, }); const state = readThreadPreviewState(ref); expect(state.snapshot?.tabId).toBe(b.tabId); }); it("navigated event updates the snapshot URL", () => { const snapshot = makeSnapshot(); applyPreviewServerEvent(ref, { type: "opened", threadId: "thread-1", tabId: snapshot.tabId, createdAt: snapshot.updatedAt, snapshot, }); applyPreviewServerEvent(ref, { type: "navigated", threadId: "thread-1", tabId: snapshot.tabId, createdAt: "2026-01-01T00:00:01.000Z", snapshot: { ...snapshot, navStatus: { _tag: "Success", url: "http://localhost:5173/about", title: "About" }, }, }); const state = readThreadPreviewState(ref); expect(state.snapshot?.navStatus._tag).toBe("Success"); if (state.snapshot?.navStatus._tag === "Success") { expect(state.snapshot.navStatus.url).toBe("http://localhost:5173/about"); } }); it("resized event updates tab viewport without changing the active tab", () => { const active = makeSnapshot({ tabId: "tab_a" }); const background = makeSnapshot({ tabId: "tab_b" }); applyPreviewServerSnapshot(ref, background); applyPreviewServerSnapshot(ref, active); applyPreviewServerEvent(ref, { type: "resized", threadId: "thread-1", tabId: background.tabId, createdAt: "2026-01-01T00:00:01.000Z", snapshot: { ...background, viewport: { _tag: "preset", presetId: "pixel-8", width: 412, height: 915 }, updatedAt: "2026-01-01T00:00:01.000Z", }, }); const state = readThreadPreviewState(ref); expect(state.activeTabId).toBe(active.tabId); expect(state.sessions[background.tabId]?.viewport).toEqual({ _tag: "preset", presetId: "pixel-8", width: 412, height: 915, }); }); it("failed event flips the snapshot to LoadFailed when tabId matches", () => { const snapshot = makeSnapshot(); applyPreviewServerEvent(ref, { type: "opened", threadId: "thread-1", tabId: snapshot.tabId, createdAt: snapshot.updatedAt, snapshot, }); applyPreviewServerEvent(ref, { type: "failed", threadId: "thread-1", tabId: snapshot.tabId, createdAt: "2026-01-01T00:00:01.000Z", url: "http://localhost:5173/", title: "", code: -105, description: "ERR_NAME_NOT_RESOLVED", }); const state = readThreadPreviewState(ref); expect(state.snapshot?.navStatus._tag).toBe("LoadFailed"); }); it("failed event for a non-active tab is ignored", () => { const snapshot = makeSnapshot({ tabId: "tab_a" }); applyPreviewServerEvent(ref, { type: "opened", threadId: "thread-1", tabId: snapshot.tabId, createdAt: snapshot.updatedAt, snapshot, }); applyPreviewServerEvent(ref, { type: "failed", threadId: "thread-1", tabId: "tab_b", createdAt: "2026-01-01T00:00:01.000Z", url: "http://localhost:9999/", title: "", code: -105, description: "ERR_NAME_NOT_RESOLVED", }); const state = readThreadPreviewState(ref); expect(state.snapshot?.navStatus._tag).toBe("Loading"); }); it("closed event clears snapshot but retains recently-seen URLs", () => { const snapshot = makeSnapshot(); applyPreviewServerEvent(ref, { type: "opened", threadId: "thread-1", tabId: snapshot.tabId, createdAt: snapshot.updatedAt, snapshot, }); applyPreviewServerEvent(ref, { type: "closed", threadId: "thread-1", tabId: snapshot.tabId, createdAt: "2026-01-01T00:00:01.000Z", }); const state = readThreadPreviewState(ref); expect(state.snapshot).toBeNull(); expect(state.recentlySeenUrls).toContain("http://localhost:5173/"); }); it("optimistically removes a session before the server close event arrives", () => { const first = makeSnapshot({ tabId: "tab_a" }); const second = makeSnapshot({ tabId: "tab_b", updatedAt: "2026-01-01T00:00:01.000Z", }); applyPreviewServerSnapshot(ref, first); applyPreviewServerSnapshot(ref, second); beginPreviewSessionClose(ref, second.tabId); const state = readThreadPreviewState(ref); expect(Object.keys(state.sessions)).toEqual([first.tabId]); expect(state.activeTabId).toBe(first.tabId); expect(state.snapshot?.tabId).toBe(first.tabId); }); it("treats a late server close event after optimistic removal as a no-op", () => { const snapshot = makeSnapshot(); applyPreviewServerSnapshot(ref, snapshot); beginPreviewSessionClose(ref, snapshot.tabId); applyPreviewServerEvent(ref, { type: "closed", threadId: "thread-1", tabId: snapshot.tabId, createdAt: "2026-01-01T00:00:01.000Z", }); const state = readThreadPreviewState(ref); expect(state.sessions).toEqual({}); expect(state.snapshot).toBeNull(); }); it("does not resurrect an intentionally closed tab from a stale list snapshot", () => { const snapshot = makeSnapshot(); applyPreviewServerSnapshot(ref, snapshot); beginPreviewSessionClose(ref, snapshot.tabId); applyPreviewServerSnapshot(ref, snapshot); const state = readThreadPreviewState(ref); expect(state.sessions).toEqual({}); expect(state.snapshot).toBeNull(); }); it("can restore a suppressed tab after a failed close", () => { const snapshot = makeSnapshot(); applyPreviewServerSnapshot(ref, snapshot); beginPreviewSessionClose(ref, snapshot.tabId); cancelPreviewSessionClose(ref, snapshot, snapshot.tabId); const state = readThreadPreviewState(ref); expect(state.sessions).toEqual({ [snapshot.tabId]: snapshot }); expect(state.snapshot).toEqual(snapshot); }); it("closed event for a different tab is a no-op", () => { const snapshot = makeSnapshot({ tabId: "tab_a" }); applyPreviewServerEvent(ref, { type: "opened", threadId: "thread-1", tabId: snapshot.tabId, createdAt: snapshot.updatedAt, snapshot, }); applyPreviewServerEvent(ref, { type: "closed", threadId: "thread-1", tabId: "tab_b", createdAt: "2026-01-01T00:00:01.000Z", }); const state = readThreadPreviewState(ref); expect(state.snapshot?.tabId).toBe(snapshot.tabId); }); it("desktopOverlay updates independently of snapshot", () => { const snapshot = makeSnapshot(); applyPreviewServerEvent(ref, { type: "opened", threadId: "thread-1", tabId: snapshot.tabId, createdAt: snapshot.updatedAt, snapshot, }); applyPreviewDesktopState(ref, snapshot.tabId, { hasWebContents: true, canGoBack: true, canGoForward: false, loading: false, zoomFactor: 1, pictureInPicture: false, colorScheme: "system", audioMuted: false, audible: false, controller: "none", favicon: null, }); const state = readThreadPreviewState(ref); expect(state.desktopOverlay?.canGoBack).toBe(true); expect(state.snapshot?.canGoBack).toBe(false); }); it("does not publish duplicate desktop browser state", () => { const snapshot = makeSnapshot(); applyPreviewServerSnapshot(ref, snapshot); const overlay = { hasWebContents: true, canGoBack: true, canGoForward: false, loading: false, zoomFactor: 1, pictureInPicture: false, colorScheme: "system" as const, audioMuted: false, audible: false, controller: "none" as const, favicon: { dataUrl: "data:image/png;base64,AA==", pageUrl: "https://example.com", capturedAt: 1, }, }; let updateCount = 0; const unsubscribe = appAtomRegistry.subscribe(previewStateAtom(scopedThreadKey(ref)), () => { updateCount += 1; }); applyPreviewDesktopState(ref, snapshot.tabId, overlay); applyPreviewDesktopState(ref, snapshot.tabId, { ...overlay, favicon: { ...overlay.favicon } }); unsubscribe(); expect(updateCount).toBe(1); }); it("retains multiple tabs and switches active desktop state", () => { const first = makeSnapshot(); const second = { ...makeSnapshot(), tabId: "tab_2", updatedAt: "2026-01-02T00:00:00.000Z" }; applyPreviewServerSnapshot(ref, first); applyPreviewServerSnapshot(ref, second); applyPreviewDesktopState(ref, first.tabId, { hasWebContents: true, canGoBack: true, canGoForward: false, loading: false, zoomFactor: 1, pictureInPicture: false, colorScheme: "system", audioMuted: false, audible: false, controller: "none", favicon: null, }); setActivePreviewTab(ref, first.tabId); const state = readThreadPreviewState(ref); expect(Object.keys(state.sessions)).toEqual([first.tabId, second.tabId]); expect(state.snapshot?.tabId).toBe(first.tabId); expect(state.desktopOverlay?.canGoBack).toBe(true); }); it("updates a background snapshot without changing the active tab", () => { const background = makeSnapshot({ tabId: "tab_a" }); const active = makeSnapshot({ tabId: "tab_b", updatedAt: "2026-01-01T00:00:01.000Z", }); applyPreviewServerSnapshot(ref, background); applyPreviewServerSnapshot(ref, active); const resized = { ...background, viewport: { _tag: "freeform" as const, width: 900, height: 700 }, updatedAt: "2026-01-01T00:00:02.000Z", }; updatePreviewServerSnapshot(ref, resized); const state = readThreadPreviewState(ref); expect(state.activeTabId).toBe(active.tabId); expect(state.snapshot?.tabId).toBe(active.tabId); expect(state.sessions[background.tabId]).toEqual(resized); }); it("reconciles an authoritative session list without focusing a background tab", () => { const active = makeSnapshot({ tabId: "tab_a" }); const stale = makeSnapshot({ tabId: "tab_stale", updatedAt: "2026-01-01T00:00:01.000Z", }); applyPreviewServerSnapshot(ref, stale); applyPreviewServerSnapshot(ref, active); applyPreviewDesktopState(ref, stale.tabId, { hasWebContents: true, canGoBack: false, canGoForward: false, loading: false, zoomFactor: 1, pictureInPicture: false, colorScheme: "system", audioMuted: false, audible: false, controller: "none", favicon: null, }); reconcilePreviewServerSessions(ref, { sessions: [active], serverEpoch, revision: 1 }); const state = readThreadPreviewState(ref); expect(Object.keys(state.sessions)).toEqual([active.tabId]); expect(state.activeTabId).toBe(active.tabId); expect(state.snapshot).toEqual(active); expect(state.desktopByTabId[stale.tabId]).toBeUndefined(); }); it("clears stale sessions when an authoritative list is empty", () => { applyPreviewServerSnapshot(ref, makeSnapshot()); reconcilePreviewServerSessions(ref, { sessions: [], serverEpoch, revision: 1 }); const state = readThreadPreviewState(ref); expect(state.sessions).toEqual({}); expect(state.activeTabId).toBeNull(); expect(state.snapshot).toBeNull(); }); it("ignores a list response older than the latest server event", () => { const snapshot = makeSnapshot(); applyPreviewServerEvent(ref, { type: "opened", threadId: "thread-1", tabId: snapshot.tabId, createdAt: snapshot.updatedAt, snapshot, }); reconcilePreviewServerSessions(ref, { sessions: [], serverEpoch, revision: 0 }); expect(readThreadPreviewState(ref).sessions).toEqual({ [snapshot.tabId]: snapshot }); }); it("does not resurrect a tab from an event older than its close", () => { const snapshot = makeSnapshot(); applyPreviewServerEvent(ref, { type: "opened", threadId: "thread-1", tabId: snapshot.tabId, createdAt: snapshot.updatedAt, snapshot, }); applyPreviewServerEvent(ref, { type: "closed", threadId: "thread-1", tabId: snapshot.tabId, createdAt: "2026-01-01T00:00:01.000Z", }); applyPreviewServerEventImpl(ref, { type: "opened", threadId: "thread-1", tabId: snapshot.tabId, createdAt: snapshot.updatedAt, serverEpoch, revision: 1, snapshot, }); expect(readThreadPreviewState(ref).sessions).toEqual({}); }); it("accepts a lower revision from a newly restarted server", () => {Lines 1–500 of 611. Load more
import { scopedThreadKey, scopeThreadRef } from "@t3tools/client-runtime/environment"; import { type EnvironmentId, type PreviewEvent, type PreviewSessionSnapshot, ThreadId, } from "@t3tools/contracts"; import { beforeEach, describe, expect, it } from "vite-plus/test"; import { __testing, applyPreviewDesktopState, applyPreviewServerEvent as applyPreviewServerEventImpl, applyPreviewServerSnapshot, beginPreviewSessionClose, cancelPreviewSessionClose, previewStateAtom, readThreadPreviewState, reconcilePreviewServerSessions, rememberPreviewUrl, resetPreviewStateForTests, setActivePreviewTab, updatePreviewServerSnapshot, } from "./previewStateStore"; import { appAtomRegistry } from "./rpc/atomRegistry"; const environmentId = "env-1" as EnvironmentId; const ref = scopeThreadRef(environmentId, ThreadId.make("thread-1")); const otherRef = scopeThreadRef(environmentId, ThreadId.make("thread-2")); const makeSnapshot = (overrides: Partial<PreviewSessionSnapshot> = {}): PreviewSessionSnapshot => ({ threadId: "thread-1", tabId: "tab_a", navStatus: { _tag: "Loading", url: "http://localhost:5173/", title: "" }, canGoBack: false, canGoForward: false, updatedAt: "2026-01-01T00:00:00.000Z", ...overrides, }); type PreviewEventDraft = PreviewEvent extends infer Event ? Event extends { readonly revision: number } ? Omit<Event, "revision" | "serverEpoch"> : never : never; const serverEpoch = "server-a"; let nextServerRevision = 0; const applyPreviewServerEvent = (eventRef: typeof ref, event: PreviewEventDraft): void => { nextServerRevision += 1; applyPreviewServerEventImpl(eventRef, { ...event, serverEpoch, revision: nextServerRevision, } as PreviewEvent); }; beforeEach(() => { nextServerRevision = 0; resetPreviewStateForTests(); }); describe("previewStateStore (single-tab)", () => { it("keeps independent state atoms for each thread", () => { expect(previewStateAtom(scopedThreadKey(ref))).toBe(previewStateAtom(scopedThreadKey(ref))); expect(previewStateAtom(scopedThreadKey(ref))).not.toBe( previewStateAtom(scopedThreadKey(otherRef)), ); applyPreviewServerSnapshot(ref, makeSnapshot()); expect(readThreadPreviewState(ref).snapshot?.tabId).toBe("tab_a"); expect(readThreadPreviewState(otherRef)).toEqual(__testing.EMPTY_THREAD_PREVIEW_STATE); }); it("opened event seeds the snapshot and remembers the URL", () => { const snapshot = makeSnapshot(); applyPreviewServerEvent(ref, { type: "opened", threadId: "thread-1", tabId: snapshot.tabId, createdAt: snapshot.updatedAt, snapshot, }); const state = readThreadPreviewState(ref); expect(state.snapshot?.tabId).toBe(snapshot.tabId); expect(state.recentlySeenUrls).toContain("http://localhost:5173/"); }); it("a second `opened` for a different tab replaces the rendered snapshot", () => { const a = makeSnapshot({ tabId: "tab_a" }); const b = makeSnapshot({ tabId: "tab_b" }); applyPreviewServerEvent(ref, { type: "opened", threadId: "thread-1", tabId: a.tabId, createdAt: a.updatedAt, snapshot: a, }); applyPreviewServerEvent(ref, { type: "opened", threadId: "thread-1", tabId: b.tabId, createdAt: b.updatedAt, snapshot: b, }); const state = readThreadPreviewState(ref); expect(state.snapshot?.tabId).toBe(b.tabId); }); it("navigated event updates the snapshot URL", () => { const snapshot = makeSnapshot(); applyPreviewServerEvent(ref, { type: "opened", threadId: "thread-1", tabId: snapshot.tabId, createdAt: snapshot.updatedAt, snapshot, }); applyPreviewServerEvent(ref, { type: "navigated", threadId: "thread-1", tabId: snapshot.tabId, createdAt: "2026-01-01T00:00:01.000Z", snapshot: { ...snapshot, navStatus: { _tag: "Success", url: "http://localhost:5173/about", title: "About" }, }, }); const state = readThreadPreviewState(ref); expect(state.snapshot?.navStatus._tag).toBe("Success"); if (state.snapshot?.navStatus._tag === "Success") { expect(state.snapshot.navStatus.url).toBe("http://localhost:5173/about"); } }); it("resized event updates tab viewport without changing the active tab", () => { const active = makeSnapshot({ tabId: "tab_a" }); const background = makeSnapshot({ tabId: "tab_b" }); applyPreviewServerSnapshot(ref, background); applyPreviewServerSnapshot(ref, active); applyPreviewServerEvent(ref, { type: "resized", threadId: "thread-1", tabId: background.tabId, createdAt: "2026-01-01T00:00:01.000Z", snapshot: { ...background, viewport: { _tag: "preset", presetId: "pixel-8", width: 412, height: 915 }, updatedAt: "2026-01-01T00:00:01.000Z", }, }); const state = readThreadPreviewState(ref); expect(state.activeTabId).toBe(active.tabId); expect(state.sessions[background.tabId]?.viewport).toEqual({ _tag: "preset", presetId: "pixel-8", width: 412, height: 915, }); }); it("failed event flips the snapshot to LoadFailed when tabId matches", () => { const snapshot = makeSnapshot(); applyPreviewServerEvent(ref, { type: "opened", threadId: "thread-1", tabId: snapshot.tabId, createdAt: snapshot.updatedAt, snapshot, }); applyPreviewServerEvent(ref, { type: "failed", threadId: "thread-1", tabId: snapshot.tabId, createdAt: "2026-01-01T00:00:01.000Z", url: "http://localhost:5173/", title: "", code: -105, description: "ERR_NAME_NOT_RESOLVED", }); const state = readThreadPreviewState(ref); expect(state.snapshot?.navStatus._tag).toBe("LoadFailed"); }); it("failed event for a non-active tab is ignored", () => { const snapshot = makeSnapshot({ tabId: "tab_a" }); applyPreviewServerEvent(ref, { type: "opened", threadId: "thread-1", tabId: snapshot.tabId, createdAt: snapshot.updatedAt, snapshot, }); applyPreviewServerEvent(ref, { type: "failed", threadId: "thread-1", tabId: "tab_b", createdAt: "2026-01-01T00:00:01.000Z", url: "http://localhost:9999/", title: "", code: -105, description: "ERR_NAME_NOT_RESOLVED", }); const state = readThreadPreviewState(ref); expect(state.snapshot?.navStatus._tag).toBe("Loading"); }); it("closed event clears snapshot but retains recently-seen URLs", () => { const snapshot = makeSnapshot(); applyPreviewServerEvent(ref, { type: "opened", threadId: "thread-1", tabId: snapshot.tabId, createdAt: snapshot.updatedAt, snapshot, }); applyPreviewServerEvent(ref, { type: "closed", threadId: "thread-1", tabId: snapshot.tabId, createdAt: "2026-01-01T00:00:01.000Z", }); const state = readThreadPreviewState(ref); expect(state.snapshot).toBeNull(); expect(state.recentlySeenUrls).toContain("http://localhost:5173/"); }); it("optimistically removes a session before the server close event arrives", () => { const first = makeSnapshot({ tabId: "tab_a" }); const second = makeSnapshot({ tabId: "tab_b", updatedAt: "2026-01-01T00:00:01.000Z", }); applyPreviewServerSnapshot(ref, first); applyPreviewServerSnapshot(ref, second); beginPreviewSessionClose(ref, second.tabId); const state = readThreadPreviewState(ref); expect(Object.keys(state.sessions)).toEqual([first.tabId]); expect(state.activeTabId).toBe(first.tabId); expect(state.snapshot?.tabId).toBe(first.tabId); }); it("treats a late server close event after optimistic removal as a no-op", () => { const snapshot = makeSnapshot(); applyPreviewServerSnapshot(ref, snapshot); beginPreviewSessionClose(ref, snapshot.tabId); applyPreviewServerEvent(ref, { type: "closed", threadId: "thread-1", tabId: snapshot.tabId, createdAt: "2026-01-01T00:00:01.000Z", }); const state = readThreadPreviewState(ref); expect(state.sessions).toEqual({}); expect(state.snapshot).toBeNull(); }); it("does not resurrect an intentionally closed tab from a stale list snapshot", () => { const snapshot = makeSnapshot(); applyPreviewServerSnapshot(ref, snapshot); beginPreviewSessionClose(ref, snapshot.tabId); applyPreviewServerSnapshot(ref, snapshot); const state = readThreadPreviewState(ref); expect(state.sessions).toEqual({}); expect(state.snapshot).toBeNull(); }); it("can restore a suppressed tab after a failed close", () => { const snapshot = makeSnapshot(); applyPreviewServerSnapshot(ref, snapshot); beginPreviewSessionClose(ref, snapshot.tabId); cancelPreviewSessionClose(ref, snapshot, snapshot.tabId); const state = readThreadPreviewState(ref); expect(state.sessions).toEqual({ [snapshot.tabId]: snapshot }); expect(state.snapshot).toEqual(snapshot); }); it("closed event for a different tab is a no-op", () => { const snapshot = makeSnapshot({ tabId: "tab_a" }); applyPreviewServerEvent(ref, { type: "opened", threadId: "thread-1", tabId: snapshot.tabId, createdAt: snapshot.updatedAt, snapshot, }); applyPreviewServerEvent(ref, { type: "closed", threadId: "thread-1", tabId: "tab_b", createdAt: "2026-01-01T00:00:01.000Z", }); const state = readThreadPreviewState(ref); expect(state.snapshot?.tabId).toBe(snapshot.tabId); }); it("desktopOverlay updates independently of snapshot", () => { const snapshot = makeSnapshot(); applyPreviewServerEvent(ref, { type: "opened", threadId: "thread-1", tabId: snapshot.tabId, createdAt: snapshot.updatedAt, snapshot, }); applyPreviewDesktopState(ref, snapshot.tabId, { hasWebContents: true, canGoBack: true, canGoForward: false, loading: false, zoomFactor: 1, pictureInPicture: false, colorScheme: "system", audioMuted: false, audible: false, controller: "none", favicon: null, }); const state = readThreadPreviewState(ref); expect(state.desktopOverlay?.canGoBack).toBe(true); expect(state.snapshot?.canGoBack).toBe(false); }); it("does not publish duplicate desktop browser state", () => { const snapshot = makeSnapshot(); applyPreviewServerSnapshot(ref, snapshot); const overlay = { hasWebContents: true, canGoBack: true, canGoForward: false, loading: false, zoomFactor: 1, pictureInPicture: false, colorScheme: "system" as const, audioMuted: false, audible: false, controller: "none" as const, favicon: { dataUrl: "data:image/png;base64,AA==", pageUrl: "https://example.com", capturedAt: 1, }, }; let updateCount = 0; const unsubscribe = appAtomRegistry.subscribe(previewStateAtom(scopedThreadKey(ref)), () => { updateCount += 1; }); applyPreviewDesktopState(ref, snapshot.tabId, overlay); applyPreviewDesktopState(ref, snapshot.tabId, { ...overlay, favicon: { ...overlay.favicon } }); unsubscribe(); expect(updateCount).toBe(1); }); it("retains multiple tabs and switches active desktop state", () => { const first = makeSnapshot(); const second = { ...makeSnapshot(), tabId: "tab_2", updatedAt: "2026-01-02T00:00:00.000Z" }; applyPreviewServerSnapshot(ref, first); applyPreviewServerSnapshot(ref, second); applyPreviewDesktopState(ref, first.tabId, { hasWebContents: true, canGoBack: true, canGoForward: false, loading: false, zoomFactor: 1, pictureInPicture: false, colorScheme: "system", audioMuted: false, audible: false, controller: "none", favicon: null, }); setActivePreviewTab(ref, first.tabId); const state = readThreadPreviewState(ref); expect(Object.keys(state.sessions)).toEqual([first.tabId, second.tabId]); expect(state.snapshot?.tabId).toBe(first.tabId); expect(state.desktopOverlay?.canGoBack).toBe(true); }); it("updates a background snapshot without changing the active tab", () => { const background = makeSnapshot({ tabId: "tab_a" }); const active = makeSnapshot({ tabId: "tab_b", updatedAt: "2026-01-01T00:00:01.000Z", }); applyPreviewServerSnapshot(ref, background); applyPreviewServerSnapshot(ref, active); const resized = { ...background, viewport: { _tag: "freeform" as const, width: 900, height: 700 }, updatedAt: "2026-01-01T00:00:02.000Z", }; updatePreviewServerSnapshot(ref, resized); const state = readThreadPreviewState(ref); expect(state.activeTabId).toBe(active.tabId); expect(state.snapshot?.tabId).toBe(active.tabId); expect(state.sessions[background.tabId]).toEqual(resized); }); it("reconciles an authoritative session list without focusing a background tab", () => { const active = makeSnapshot({ tabId: "tab_a" }); const stale = makeSnapshot({ tabId: "tab_stale", updatedAt: "2026-01-01T00:00:01.000Z", }); applyPreviewServerSnapshot(ref, stale); applyPreviewServerSnapshot(ref, active); applyPreviewDesktopState(ref, stale.tabId, { hasWebContents: true, canGoBack: false, canGoForward: false, loading: false, zoomFactor: 1, pictureInPicture: false, colorScheme: "system", audioMuted: false, audible: false, controller: "none", favicon: null, }); reconcilePreviewServerSessions(ref, { sessions: [active], serverEpoch, revision: 1 }); const state = readThreadPreviewState(ref); expect(Object.keys(state.sessions)).toEqual([active.tabId]); expect(state.activeTabId).toBe(active.tabId); expect(state.snapshot).toEqual(active); expect(state.desktopByTabId[stale.tabId]).toBeUndefined(); }); it("clears stale sessions when an authoritative list is empty", () => { applyPreviewServerSnapshot(ref, makeSnapshot()); reconcilePreviewServerSessions(ref, { sessions: [], serverEpoch, revision: 1 }); const state = readThreadPreviewState(ref); expect(state.sessions).toEqual({}); expect(state.activeTabId).toBeNull(); expect(state.snapshot).toBeNull(); }); it("ignores a list response older than the latest server event", () => { const snapshot = makeSnapshot(); applyPreviewServerEvent(ref, { type: "opened", threadId: "thread-1", tabId: snapshot.tabId, createdAt: snapshot.updatedAt, snapshot, }); reconcilePreviewServerSessions(ref, { sessions: [], serverEpoch, revision: 0 }); expect(readThreadPreviewState(ref).sessions).toEqual({ [snapshot.tabId]: snapshot }); }); it("does not resurrect a tab from an event older than its close", () => { const snapshot = makeSnapshot(); applyPreviewServerEvent(ref, { type: "opened", threadId: "thread-1", tabId: snapshot.tabId, createdAt: snapshot.updatedAt, snapshot, }); applyPreviewServerEvent(ref, { type: "closed", threadId: "thread-1", tabId: snapshot.tabId, createdAt: "2026-01-01T00:00:01.000Z", }); applyPreviewServerEventImpl(ref, { type: "opened", threadId: "thread-1", tabId: snapshot.tabId, createdAt: snapshot.updatedAt, serverEpoch, revision: 1, snapshot, }); expect(readThreadPreviewState(ref).sessions).toEqual({}); }); it("accepts a lower revision from a newly restarted server", () => {