Skip to content
Source
Sign inSign up

closedViewStore.test.ts

135 lines5.0 KB

1import { scopeThreadRef } from "@t3tools/client-runtime/environment";
2import {
3 type EnvironmentId,
4 INCOGNITO_BROWSER_PROFILE_ID,
5 type PreviewSessionSnapshot,
6 ThreadId,
7} from "@t3tools/contracts";
8import { beforeEach, describe, expect, it } from "vite-plus/test";
9​
10import { type ClosedViewEntry, useClosedViewStore } from "./closedViewStore";
11​
12const refA = scopeThreadRef("env-1" as EnvironmentId, ThreadId.make("thread-A"));
13const refB = scopeThreadRef("env-2" as EnvironmentId, ThreadId.make("thread-A"));
14const diff = (threadRef: typeof refA) =>
15 ({ kind: "panel-tab", threadRef, surface: { kind: "diff", id: "diff" } }) as const;
16​
17beforeEach(() => {
18 useClosedViewStore.setState({ entries: [] });
19});
20​
21const snapshot: PreviewSessionSnapshot = {
22 threadId: refA.threadId,
23 tabId: "private-tab",
24 profileId: INCOGNITO_BROWSER_PROFILE_ID,
25 navStatus: { _tag: "Success", url: "https://private.example", title: "Private page" },
26 canGoBack: false,
27 canGoForward: false,
28 updatedAt: "2026-10-06T17:00:00.000Z",
29};
30​
31describe("closedViewStore", () => {
32 it.each([
33 { id: "bad", kind: "browser", threadRef: refA, snapshot: {} },
34 {
35 id: "bad",
36 kind: "browser",
37 threadRef: refA,
38 snapshot: { ...snapshot, profileId: "default", navStatus: null },
39 },
40 { id: "bad", kind: "panel-tab", surface: { kind: "diff", id: "diff" } },
41 { id: "bad", kind: "panel-tab", threadRef: refA },
42 { id: "bad", kind: "panel-tab", threadRef: {}, surface: { kind: "diff", id: "diff" } },
43 { id: "bad", kind: "panel-tab", threadRef: refA, surface: {} },
44 { id: "bad", kind: "panel-tab", threadRef: refA, surface: { kind: "file", id: "file:x" } },
45 {
46 id: "bad",
47 kind: "panel-tab",
48 threadRef: refA,
49 surface: { kind: "device", id: "device:x", target: {} },
50 },
51 {
52 id: "bad",
53 kind: "panel-tab",
54 threadRef: refA,
55 surface: { kind: "pull-request", id: "pull-request:x", repository: "owner/repo", number: 1 },
56 },
57 {
58 id: "bad",
59 kind: "panel-tab",
60 threadRef: refA,
61 surface: { kind: "side-chat", id: "side-chat:x" },
62 },
63 ])("discards incomplete saved views %j while retaining valid history", async (entry) => {
64 const id = useClosedViewStore.getState().remember(diff(refA));
65 const { storage, name } = useClosedViewStore.persist.getOptions();
66 await storage!.setItem(name!, {
67 state: { entries: [entry as ClosedViewEntry, ...useClosedViewStore.getState().entries] },
68 version: 1,
69 });
70 await useClosedViewStore.persist.rehydrate();
71 expect(useClosedViewStore.persist.hasHydrated()).toBe(true);
72 expect(useClosedViewStore.getState().entries).toEqual([{ ...diff(refA), id }]);
73 expect(() => useClosedViewStore.getState().remember(diff(refB))).not.toThrow();
74 });
75​
76 it("keeps private tabs available in memory without saving their metadata", async () => {
77 const store = useClosedViewStore.getState();
78 const publicId = store.remember(diff(refA));
79 const privateId = store.remember({ kind: "browser", threadRef: refA, snapshot });
80 expect(useClosedViewStore.getState().entries.map((entry) => entry.id)).toEqual([
81 privateId,
82 publicId,
83 ]);
84 const { storage, name } = useClosedViewStore.persist.getOptions();
85 const saved = JSON.stringify(await storage!.getItem(name!));
86 expect(saved).not.toContain("private.example");
87 expect(saved).not.toContain("Private page");
88 await useClosedViewStore.persist.rehydrate();
89 expect(useClosedViewStore.getState().entries.map((entry) => entry.id)).toEqual([publicId]);
90 });
91​
92 it("removes private metadata and malformed entries from history saved by earlier versions", async () => {
93 const store = useClosedViewStore.getState();
94 const sideChatId = store.remember({
95 kind: "panel-tab",
96 threadRef: refA,
97 surface: { id: "side-chat:side", kind: "side-chat", threadId: ThreadId.make("side") },
98 });
99 const publicId = store.remember(diff(refA));
100 const browserId = store.remember({
101 kind: "browser",
102 threadRef: refA,
103 snapshot: {
104 ...snapshot,
105 tabId: "public-tab",
106 profileId: "default",
107 navStatus: { _tag: "Success", url: "https://public.example", title: "Public page" },
108 },
109 });
110 store.remember({ kind: "browser", threadRef: refA, snapshot });
111 const { storage, name } = useClosedViewStore.persist.getOptions();
112 await storage!.setItem(name!, {
113 state: {
114 entries: [
115 null,
116 {},
117 { kind: "browser" },
118 { kind: "browser", snapshot: null },
119 ...useClosedViewStore.getState().entries,
120 ] as ClosedViewEntry[],
121 },
122 version: 0,
123 });
124 await useClosedViewStore.persist.rehydrate();
125 expect(useClosedViewStore.persist.hasHydrated()).toBe(true);
126 expect(useClosedViewStore.getState().entries.map((entry) => entry.id)).toEqual([
127 browserId,
128 publicId,
129 sideChatId,
130 ]);
131 const saved = JSON.stringify(await storage!.getItem(name!));
132 expect(saved).not.toContain("private.example");
133 expect(saved).not.toContain("Private page");
134 });
135});