import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { installApiAuthResponseMonitor, onApiUnauthorized } from "./apiAuthEvents"; const FETCH_PATCH_FLAG = "__mastersToolkitAuthFetchPatched"; async function flushAsync(): Promise { await new Promise((resolve) => window.setTimeout(resolve, 0)); } describe("apiAuthEvents", () => { let originalFetch: typeof window.fetch; beforeEach(() => { originalFetch = window.fetch.bind(window); delete (window as Window & { [FETCH_PATCH_FLAG]?: boolean })[FETCH_PATCH_FLAG]; }); afterEach(() => { window.fetch = originalFetch; delete (window as Window & { [FETCH_PATCH_FLAG]?: boolean })[FETCH_PATCH_FLAG]; }); it("ignores 401 responses without Authorization header", async () => { const events: Array<{ status: number; message: string }> = []; const dispose = onApiUnauthorized((detail) => { events.push({ status: detail.status, message: detail.message }); }); window.fetch = vi.fn(async () => { return new Response(JSON.stringify({ detail: "Missing Authorization header." }), { status: 401, headers: { "content-type": "application/json", "x-masters-auth-error": "1", }, }); }) as unknown as typeof window.fetch; installApiAuthResponseMonitor(); await window.fetch("/api/ui/tabs"); await flushAsync(); dispose(); expect(events).toHaveLength(0); }); it("emits unauthorized event for protected 401 responses with Authorization header", async () => { const events: Array<{ status: number; message: string }> = []; const dispose = onApiUnauthorized((detail) => { events.push({ status: detail.status, message: detail.message }); }); window.fetch = vi.fn(async () => { return new Response(JSON.stringify({ detail: "Invalid or expired token." }), { status: 401, headers: { "content-type": "application/json", "x-masters-auth-error": "1", }, }); }) as unknown as typeof window.fetch; installApiAuthResponseMonitor(); await window.fetch("/api/health", { headers: { Authorization: "Bearer token" }, }); await flushAsync(); dispose(); expect(events).toHaveLength(1); expect(events[0]?.status).toBe(401); expect(events[0]?.message).toContain("Invalid or expired token"); }); });