import { completeLogout, reportLogoutAudit } from "./logoutFlow"; describe("reportLogoutAudit", () => { it("starts an authenticated keepalive request", async () => { const fetcher = jest.fn( async (_input: RequestInfo | URL, _init?: RequestInit) => ({ ok: true }) as Response, ); await reportLogoutAudit({ endpoint: "https://server.example/api/v1/audit-events", accessToken: "access-token", fetcher: fetcher as typeof fetch, }); expect(fetcher).toHaveBeenCalledTimes(1); const [url, init] = fetcher.mock.calls[0]; expect(url).toBe("https://server.example/api/v1/audit-events"); expect(init).toMatchObject({ method: "POST", body: JSON.stringify({ event: "logout" }), keepalive: true, }); expect(new Headers(init?.headers).get("Authorization")).toBe( "Bearer access-token", ); }); }); describe("completeLogout", () => { it("navigates immediately without waiting for audit reporting", async () => { const reportAudit = jest.fn( () => new Promise(() => undefined), ); const clearLocalState = jest.fn(); const navigate = jest.fn(); const result = completeLogout({ reportAudit, clearLocalState, navigate, }); await Promise.resolve(); expect(reportAudit).toHaveBeenCalledTimes(1); expect(clearLocalState).toHaveBeenCalledTimes(1); expect(navigate).toHaveBeenCalledWith("/api/auth/keycloak-logout"); await expect(result).resolves.toEqual({ success: true }); }); it("completes logout when audit reporting fails", async () => { const reportAudit = jest.fn(() => Promise.reject(new Error("offline"))); const clearLocalState = jest.fn(); const navigate = jest.fn(); await expect( completeLogout({ reportAudit, clearLocalState, navigate }), ).resolves.toEqual({ success: true }); expect(clearLocalState).toHaveBeenCalledTimes(1); expect(navigate).toHaveBeenCalledWith("/api/auth/keycloak-logout"); }); it("completes logout when audit reporting throws synchronously", async () => { const clearLocalState = jest.fn(); const navigate = jest.fn(); await expect( completeLogout({ reportAudit: () => { throw new Error("invalid request"); }, clearLocalState, navigate, }), ).resolves.toEqual({ success: true }); expect(clearLocalState).toHaveBeenCalledTimes(1); expect(navigate).toHaveBeenCalledWith("/api/auth/keycloak-logout"); }); });