import { beforeEach, describe, expect, it, vi } from "vitest"; import { createPinia, setActivePinia } from "pinia"; vi.mock("../router", () => ({ default: { replace: vi.fn(), }, })); vi.mock("../api/authClient", () => ({ extendToken: vi.fn(), unlockSession: vi.fn(), })); describe("session manager idle recovery", () => { beforeEach(() => { vi.resetModules(); vi.useFakeTimers(); setActivePinia(createPinia()); const storage = (() => { const data = new Map(); return { getItem: (key: string) => data.get(key) ?? null, setItem: (key: string, value: string) => { data.set(key, String(value)); }, removeItem: (key: string) => { data.delete(key); }, clear: () => { data.clear(); }, }; })(); Object.defineProperty(window, "localStorage", { value: storage, configurable: true, }); Object.defineProperty(window, "sessionStorage", { value: storage, configurable: true, }); Object.defineProperty(window, "BroadcastChannel", { value: class { onmessage: ((event: MessageEvent) => void) | null = null; postMessage() {} close() {} }, configurable: true, }); }); it("locks instead of refreshing activity after long inactivity when user activity resumes", async () => { vi.setSystemTime(new Date("2026-03-10T01:00:00.000Z")); const { useSessionStore } = await import("../store/session"); const { IDLE_TIMEOUT_MINUTES, AUTO_LOGOUT_TIMEOUT_HOURS, markUserActive } = await import("./sessionManager"); const session = useSessionStore(); const oldTs = Date.now() - (IDLE_TIMEOUT_MINUTES * 60 * 1000 + 1_000); session.recordUserActivity(oldTs); session.recordNetworkActivity(oldTs); markUserActive(Date.now()); expect(session.locked).toBe(true); expect(session.lockReason).toBe("idle"); expect(session.lockAutoLogoutDeadlineAt).toBe(oldTs + AUTO_LOGOUT_TIMEOUT_HOURS * 60 * 60 * 1000); }); it("locks instead of refreshing activity after long inactivity when network activity resumes", async () => { vi.setSystemTime(new Date("2026-03-10T01:00:00.000Z")); const { useSessionStore } = await import("../store/session"); const { IDLE_TIMEOUT_MINUTES, AUTO_LOGOUT_TIMEOUT_HOURS, markNetworkActive } = await import("./sessionManager"); const session = useSessionStore(); const oldTs = Date.now() - (IDLE_TIMEOUT_MINUTES * 60 * 1000 + 1_000); session.recordUserActivity(oldTs); session.recordNetworkActivity(oldTs); markNetworkActive(Date.now()); expect(session.locked).toBe(true); expect(session.lockReason).toBe("idle"); expect(session.lockAutoLogoutDeadlineAt).toBe(oldTs + AUTO_LOGOUT_TIMEOUT_HOURS * 60 * 60 * 1000); }); });