import { HttpResponse, http } from "msw"; import { setupServer } from "msw/node"; import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from "vitest"; import { createExternalAuthSessionAdapter } from "../../src/adapters/auth/external-session-adapter.js"; import { createHttpClient } from "../../src/adapters/http/client.js"; let responseStatuses = []; const server = setupServer( http.get("https://api.test/api/sample/resources", () => { const status = responseStatuses.shift() ?? 200; if (status === 401) { return HttpResponse.json( { success: false, error: { code: "UNAUTHENTICATED" }, meta: { requestId: "request-1", traceId: "trace-1" }, }, { status }, ); } return HttpResponse.json({ success: true, data: [{ id: "resource-1", name: "Example" }], meta: { requestId: "request-2", traceId: "trace-1" }, }); }), ); beforeAll(() => server.listen({ onUnhandledRequest: "error" })); afterEach(() => { responseStatuses = []; server.resetHandlers(); }); afterAll(() => server.close()); const clock = { now: () => 0, sleep: async () => {} }; describe("bounded 401 session recovery", () => { it("calls recovery once and replays a safe request once", async () => { responseStatuses = [401, 200]; const recoverSession = vi.fn(async () => "restored"); const authSession = createExternalAuthSessionAdapter({ readState: () => "authenticated", attachCredential: async (request) => request, recoverSession, notifyUnauthenticated: vi.fn(), }); const client = createHttpClient({ baseUrl: "https://api.test", authSession, clock, }); await expect(client.execute("LIST_SAMPLE_RESOURCES")).resolves.toMatchObject({ ok: true, }); expect(recoverSession).toHaveBeenCalledTimes(1); }); it("stops after a second 401 and notifies unauthenticated once", async () => { responseStatuses = [401, 401]; const notifyUnauthenticated = vi.fn(); const authSession = createExternalAuthSessionAdapter({ readState: () => "authenticated", attachCredential: async (request) => request, recoverSession: async () => "restored", notifyUnauthenticated, }); const client = createHttpClient({ baseUrl: "https://api.test", authSession, clock, }); await expect(client.execute("LIST_SAMPLE_RESOURCES")).resolves.toMatchObject({ ok: false, error: { kind: "AUTH_REQUIRED" }, }); expect(notifyUnauthenticated).toHaveBeenCalledTimes(1); }); it("normalizes attach and invalid recovery failures", async () => { const attachFailure = createExternalAuthSessionAdapter({ readState: () => "authenticated", attachCredential: async () => { throw new Error("credential detail"); }, recoverSession: async () => "restored", notifyUnauthenticated: vi.fn(), }); const client = createHttpClient({ baseUrl: "https://api.test", authSession: attachFailure, clock, }); await expect(client.execute("LIST_SAMPLE_RESOURCES")).resolves.toMatchObject({ ok: false, error: { kind: "AUTH_INTEGRATION_FAILURE" }, }); }); });