import { beforeEach, describe, expect, it, vi } from "vitest"; describe("recovery confirmation state", () => { let local: { get: ReturnType; set: ReturnType; remove: ReturnType }; let session: { get: ReturnType; set: ReturnType; remove: ReturnType }; let sessionValues: Record; beforeEach(() => { vi.resetModules(); sessionValues = {}; local = { get: vi.fn(async () => ({})), set: vi.fn(async () => undefined), remove: vi.fn(async () => undefined), }; session = { get: vi.fn(async (key: string) => ({ [key]: sessionValues[key] })), set: vi.fn(async (values: Record) => Object.assign(sessionValues, values)), remove: vi.fn(async (key: string) => { delete sessionValues[key]; }), }; vi.stubGlobal("chrome", { storage: { local, session } }); }); it("stores the pending exemption in session storage, never local storage", async () => { const pending = await import("./recovery-pending"); await pending.setRecoveryConfirmPending(); expect(session.set).toHaveBeenCalledWith({ peach_recovery_pending: expect.any(Number), }); expect(local.set).not.toHaveBeenCalled(); await expect(pending.isRecoveryConfirmPending()).resolves.toBe(true); }); it("clears the session-owned exemption", async () => { const pending = await import("./recovery-pending"); await pending.setRecoveryConfirmPending(); await pending.clearRecoveryConfirmPending(); expect(session.remove).toHaveBeenCalledWith("peach_recovery_pending"); await expect(pending.isRecoveryConfirmPending()).resolves.toBe(false); expect(local.remove).not.toHaveBeenCalled(); }); it("uses background memory when session storage is unavailable", async () => { vi.stubGlobal("chrome", { storage: { local } }); const pending = await import("./recovery-pending"); await pending.setRecoveryConfirmPending(); await expect(pending.isRecoveryConfirmPending()).resolves.toBe(true); await pending.clearRecoveryConfirmPending(); await expect(pending.isRecoveryConfirmPending()).resolves.toBe(false); expect(local.set).not.toHaveBeenCalled(); }); it("expires the recovery exemption after its hard deadline", async () => { vi.useFakeTimers(); try { const pending = await import("./recovery-pending"); await pending.setRecoveryConfirmPending(); await vi.advanceTimersByTimeAsync(10 * 60 * 1000 + 1); await expect(pending.isRecoveryConfirmPending()).resolves.toBe(false); expect(session.remove).toHaveBeenCalledWith("peach_recovery_pending"); } finally { vi.useRealTimers(); } }); it("clears the recovery exemption when the vault locks", async () => { const pending = await import("./recovery-pending"); const vault = await import("./vault"); await pending.setRecoveryConfirmPending(); vault.lock(); await vi.waitFor(() => expect(sessionValues.peach_recovery_pending).toBeUndefined()); }); });