Skip to content
File

Blob: tests/client/stores/shared-inbox.test.ts

typescript84 lines
1import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2import { createFreshDb, deleteDb } from "@tests/client/util/idb";
3import type { BlandDatabase } from "@/client/stores/db/bland-db";
4import type { SharedInboxWorkspaceSummary, SharedWithMeItem } from "@/shared/types";
5 
6let db: BlandDatabase;
7let sharedInboxCommands: typeof import("@/client/stores/db/shared-inbox").sharedInboxCommands;
8 
9const ITEM_ONE: SharedWithMeItem = {
10 page_id: "p1",
11 title: "One",
12 icon: null,
13 cover_url: null,
14 workspace: { id: "ws-1", name: "W1", slug: "w1", icon: null, role: null },
15 permission: "view",
16 shared_by: "u2",
17 shared_by_name: "Alice",
18 shared_at: "2026-04-01T00:00:00.000Z",
19};
20 
21const ITEM_TWO: SharedWithMeItem = {
22 ...ITEM_ONE,
23 page_id: "p2",
24 title: "Two",
25};
26 
27const SUMMARY: SharedInboxWorkspaceSummary = {
28 workspace: { id: "ws-1", name: "W1", slug: "w1", icon: null },
29 count: 2,
30};
31 
32beforeEach(async () => {
33 vi.resetModules();
34 db = createFreshDb();
35 vi.doMock("@/client/stores/db/bland-db", async () => {
36 const actual = await vi.importActual<typeof import("@/client/stores/db/bland-db")>("@/client/stores/db/bland-db");
37 return { ...actual, db };
38 });
39 sharedInboxCommands = (await import("@/client/stores/db/shared-inbox")).sharedInboxCommands;
40});
41 
42afterEach(async () => {
43 await deleteDb(db);
44 vi.restoreAllMocks();
45});
46 
47describe("sharedInboxCommands.replaceAll", () => {
48 it("stores items and workspace summaries", async () => {
49 await sharedInboxCommands.replaceAll({
50 items: [ITEM_ONE, ITEM_TWO],
51 workspaceSummaries: [SUMMARY],
52 });
53 
54 const items = await db.sharedInboxItems.toArray();
55 expect(items.map((r) => r.pageId).sort()).toEqual(["p1", "p2"]);
56 const summaries = await db.sharedInboxWorkspaceSummaries.toArray();
57 expect(summaries.map((r) => r.workspaceId)).toEqual(["ws-1"]);
58 });
59 
60 it("replaces prior rows on each call", async () => {
61 await sharedInboxCommands.replaceAll({ items: [ITEM_ONE, ITEM_TWO], workspaceSummaries: [SUMMARY] });
62 await sharedInboxCommands.replaceAll({ items: [ITEM_ONE], workspaceSummaries: [] });
63 expect((await db.sharedInboxItems.toArray()).map((r) => r.pageId)).toEqual(["p1"]);
64 expect(await db.sharedInboxWorkspaceSummaries.count()).toBe(0);
65 });
66 
67 it("empty input clears both tables", async () => {
68 await sharedInboxCommands.replaceAll({ items: [ITEM_ONE], workspaceSummaries: [SUMMARY] });
69 await sharedInboxCommands.replaceAll({ items: [], workspaceSummaries: [] });
70 expect(await db.sharedInboxItems.count()).toBe(0);
71 expect(await db.sharedInboxWorkspaceSummaries.count()).toBe(0);
72 });
73 
74 it("assigns rank matching the source array index so ordering survives rehydrate", async () => {
75 await sharedInboxCommands.replaceAll({
76 items: [ITEM_TWO, ITEM_ONE],
77 workspaceSummaries: [SUMMARY],
78 });
79 const rankedItems = await db.sharedInboxItems.orderBy("rank").toArray();
80 expect(rankedItems.map((r) => r.pageId)).toEqual(["p2", "p1"]);
81 expect(rankedItems.map((r) => r.rank)).toEqual([0, 1]);
82 });
83});