Skip to content
File

Blob: tests/client/lib/share-page-model.test.ts

typescript95 lines
1import { describe, expect, it } from "vitest";
2import { deriveSharePagePresentation } from "@/client/lib/share-page-model";
3import type { ActivePageState } from "@/client/lib/active-page-model";
4import type { ShareRootPage } from "@/client/components/share/use-share-view";
5 
6const ROOT_PAGE: ShareRootPage = {
7 id: "page-root",
8 kind: "doc",
9 title: "Root",
10 icon: "๐Ÿ“„",
11 cover_url: "/uploads/root-cover",
12 permission: "view",
13};
14 
15describe("deriveSharePagePresentation", () => {
16 it("uses the ready page when the active page is loaded", () => {
17 const state: ActivePageState = {
18 kind: "ready",
19 backing: "live",
20 snapshot: { id: "page-child", workspaceId: "ws-1", kind: "doc", title: "Child", icon: "๐ŸŒฟ", coverUrl: null },
21 access: { mode: "edit" },
22 ancestors: [],
23 ancestorsStatus: "ready",
24 };
25 
26 expect(deriveSharePagePresentation(ROOT_PAGE, "page-child", state)).toMatchObject({
27 activePageId: "page-child",
28 isRootActive: false,
29 isPageLoading: false,
30 isAncestorTrailLoading: false,
31 displayTitle: "Child",
32 displayIcon: "๐ŸŒฟ",
33 isViewOnly: false,
34 });
35 });
36 
37 it("does not synthesize root metadata when the active page state is still loading", () => {
38 // Boundary remount + useState(initialSnapshot) makes this transient state
39 // unreachable for the root page in practice, but the derivation must not
40 // paper over loading with stale rootPage fallbacks โ€” display stays empty.
41 const state: ActivePageState = { kind: "loading" };
42 
43 expect(deriveSharePagePresentation(ROOT_PAGE, "page-root", state)).toMatchObject({
44 activePageId: "page-root",
45 isRootActive: true,
46 isPageLoading: true,
47 isAncestorTrailLoading: false,
48 displayTitle: "",
49 displayIcon: null,
50 displayCoverUrl: null,
51 isViewOnly: true,
52 });
53 });
54 
55 it("does not leak stale ready data from a previous page id", () => {
56 const state: ActivePageState = {
57 kind: "ready",
58 backing: "live",
59 snapshot: { id: "page-old", workspaceId: "ws-1", kind: "doc", title: "Old", icon: null, coverUrl: null },
60 access: { mode: "view" },
61 ancestors: [],
62 ancestorsStatus: "ready",
63 };
64 
65 expect(deriveSharePagePresentation(ROOT_PAGE, "page-next", state)).toMatchObject({
66 activePageId: "page-next",
67 isRootActive: false,
68 isPageLoading: true,
69 isAncestorTrailLoading: false,
70 page: null,
71 displayTitle: "",
72 displayIcon: null,
73 isViewOnly: true,
74 });
75 });
76 
77 it("surfaces ancestor trail loading separately from page readiness", () => {
78 const state: ActivePageState = {
79 kind: "ready",
80 backing: "live",
81 snapshot: { id: "page-child", workspaceId: "ws-1", kind: "doc", title: "Child", icon: null, coverUrl: null },
82 access: { mode: "view" },
83 ancestors: [],
84 ancestorsStatus: "loading",
85 };
86 
87 expect(deriveSharePagePresentation(ROOT_PAGE, "page-child", state)).toMatchObject({
88 activePageId: "page-child",
89 isPageLoading: false,
90 isAncestorTrailLoading: true,
91 page: { id: "page-child" },
92 });
93 });
94});