import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { DESKTOP_SERVER_URL_KEY } from "./desktopServerConfig"; import { clearLoginCredential, getSavedLoginCredential, saveLoginCredential, } from "./savedLoginCredentials"; const invokeMock = vi.hoisted(() => vi.fn()); vi.mock("@tauri-apps/api/core", () => ({ invoke: invokeMock, })); const SERVER_ORIGIN = "https://ctms.example.com/"; const createStorage = (): Storage => { const data = new Map(); return { get length() { return data.size; }, clear: () => data.clear(), getItem: (key) => data.get(key) ?? null, key: (index) => Array.from(data.keys())[index] ?? null, removeItem: (key) => data.delete(key), setItem: (key, value) => { data.set(key, String(value)); }, }; }; describe("saved login credentials", () => { beforeEach(() => { vi.useFakeTimers(); vi.setSystemTime(new Date("2026-07-08T00:00:00.000Z")); Object.defineProperty(window, "localStorage", { value: createStorage(), configurable: true }); localStorage.clear(); invokeMock.mockReset(); Reflect.deleteProperty(window, "__TAURI_INTERNALS__"); Reflect.deleteProperty(window, "PasswordCredential"); Reflect.deleteProperty(navigator, "credentials"); }); afterEach(() => { vi.useRealTimers(); localStorage.clear(); Reflect.deleteProperty(window, "__TAURI_INTERNALS__"); Reflect.deleteProperty(window, "PasswordCredential"); Reflect.deleteProperty(navigator, "credentials"); }); it("stores desktop remembered passwords in the system credential store", async () => { Object.defineProperty(window, "__TAURI_INTERNALS__", { value: {}, configurable: true }); localStorage.setItem(DESKTOP_SERVER_URL_KEY, SERVER_ORIGIN); let stored = ""; invokeMock.mockImplementation(async (command: string, args: any) => { if (command === "login_credential_set") { stored = args.credential; return undefined; } if (command === "login_credential_get") return stored; if (command === "login_credential_delete") { stored = ""; return undefined; } return undefined; }); await expect(saveLoginCredential("Admin@Example.com", "secret-password")).resolves.toBe(true); expect(invokeMock).toHaveBeenCalledWith("login_credential_set", { serverOrigin: SERVER_ORIGIN, credential: expect.any(String), }); expect(JSON.parse(stored)).toMatchObject({ version: 1, email: "admin@example.com", password: "secret-password", savedAt: Date.now(), }); await expect(getSavedLoginCredential()).resolves.toEqual({ email: "admin@example.com", password: "secret-password", }); await expect(clearLoginCredential()).resolves.toBe(true); expect(invokeMock).toHaveBeenCalledWith("login_credential_delete", { serverOrigin: SERVER_ORIGIN }); }); it("deletes malformed desktop remembered credentials", async () => { Object.defineProperty(window, "__TAURI_INTERNALS__", { value: {}, configurable: true }); localStorage.setItem(DESKTOP_SERVER_URL_KEY, SERVER_ORIGIN); invokeMock.mockImplementation(async (command: string) => { if (command === "login_credential_get") return JSON.stringify({ password: "missing-email" }); return undefined; }); await expect(getSavedLoginCredential()).resolves.toBeNull(); expect(invokeMock).toHaveBeenCalledWith("login_credential_delete", { serverOrigin: SERVER_ORIGIN }); }); it("uses browser credential management without writing passwords to localStorage", async () => { const storeMock = vi.fn(); const preventSilentAccessMock = vi.fn(); Object.defineProperty(window, "PasswordCredential", { configurable: true, value: class { id: string; password: string; constructor(data: { id: string; password: string }) { this.id = data.id; this.password = data.password; } }, }); Object.defineProperty(navigator, "credentials", { configurable: true, value: { get: vi.fn(async () => ({ id: "Browser@Example.com", password: "browser-secret" })), store: storeMock, preventSilentAccess: preventSilentAccessMock, }, }); await expect(getSavedLoginCredential()).resolves.toEqual({ email: "browser@example.com", password: "browser-secret", }); await expect(saveLoginCredential("Browser@Example.com", "browser-secret")).resolves.toBe(true); await expect(clearLoginCredential()).resolves.toBe(true); expect(storeMock).toHaveBeenCalledTimes(1); expect(preventSilentAccessMock).toHaveBeenCalledTimes(1); expect(JSON.stringify(localStorage)).not.toContain("browser-secret"); }); });