1import { type ConfirmDialogOptions, type ContextMenuItem } from "@t3tools/contracts";
2import { afterEach, beforeEach, describe, expect, it, vi } from "vite-plus/test";
3
4const showContextMenuFallbackMock =
5 vi.fn<
6 <T extends string>(
7 items: readonly ContextMenuItem<T>[],
8 position?: { x: number; y: number },
9 ) => Promise<T | null>
10 >();
11const dismissContextMenuMock = vi.fn<() => void>();
12
13const requestConfirmDialogMock =
14 vi.fn<(message: string, options?: ConfirmDialogOptions) => Promise<boolean> | undefined>();
15
16vi.mock("./contextMenuFallback", () => ({
17 showContextMenuFallback: showContextMenuFallbackMock,
18 dismissContextMenu: dismissContextMenuMock,
19}));
20
21vi.mock("./confirmDialog", () => ({
22 requestConfirmDialog: requestConfirmDialogMock,
23}));
24
25function createLocalStorageStub(): Storage {
26 const values = new Map<string, string>();
27 return {
28 getItem: (key) => values.get(key) ?? null,
29 setItem: (key, value) => {
30 values.set(key, value);
31 },
32 removeItem: (key) => {
33 values.delete(key);
34 },
35 clear: () => values.clear(),
36 key: (index) => [...values.keys()][index] ?? null,
37 get length() {
38 return values.size;
39 },
40 };
41}
42
43function testWindow(): Window & typeof globalThis {
44 return globalThis.window ?? (globalThis as unknown as Window & typeof globalThis);
45}
46
47beforeEach(() => {
48 vi.resetModules();
49 vi.clearAllMocks();
50 if (globalThis.window === undefined) {
51 Object.defineProperty(globalThis, "window", {
52 configurable: true,
53 value: globalThis,
54 });
55 }
56 Reflect.deleteProperty(testWindow(), "desktopBridge");
57 Object.defineProperty(testWindow(), "localStorage", {
58 configurable: true,
59 value: createLocalStorageStub(),
60 });
61});
62
63afterEach(() => {
64 vi.restoreAllMocks();
65});
66
67describe("LocalApi", () => {
68 it("fails closed in a browser when no themed host is available", async () => {
69 requestConfirmDialogMock.mockReturnValue(undefined);
70 const { createLocalApi } = await import("./localApi");
71
72 await expect(createLocalApi().dialogs.confirm("Delete this thread?")).resolves.toBe(false);
73 });
74});