import { render, screen, waitFor } from "@testing-library/react" import userEvent from "@testing-library/user-event" import { describe, it, expect, vi, beforeEach } from "vitest" import { AuthProvider, useAuth } from "./AuthContext" import { api, UnauthorizedError } from "@/api/client" const USER = { id: "u1", email: "a@b.com" } const PROJECT = { id: "p1", name: "Default" } function Probe() { const { user, project, loading, login, register, logout } = useAuth() return (
{String(loading)} {user ? user.email : "none"} {project ? project.name : "none"}
) } function renderProbe() { return render( , ) } beforeEach(() => { vi.restoreAllMocks() }) describe("AuthContext", () => { it("populates user/project from api.auth.me() on mount", async () => { vi.spyOn(api.auth, "me").mockResolvedValue({ user: USER, project: PROJECT }) renderProbe() expect(screen.getByTestId("loading").textContent).toBe("true") await waitFor(() => expect(screen.getByTestId("loading").textContent).toBe("false")) expect(screen.getByTestId("user").textContent).toBe(USER.email) expect(screen.getByTestId("project").textContent).toBe(PROJECT.name) }) it("treats 401 from api.auth.me() as unauthenticated, not an error", async () => { vi.spyOn(api.auth, "me").mockRejectedValue(new UnauthorizedError()) renderProbe() await waitFor(() => expect(screen.getByTestId("loading").textContent).toBe("false")) expect(screen.getByTestId("user").textContent).toBe("none") expect(screen.getByTestId("project").textContent).toBe("none") }) it("login sets user/project in context", async () => { vi.spyOn(api.auth, "me").mockRejectedValue(new UnauthorizedError()) vi.spyOn(api.auth, "login").mockResolvedValue({ user: USER, project: PROJECT }) const user = userEvent.setup() renderProbe() await waitFor(() => expect(screen.getByTestId("loading").textContent).toBe("false")) await user.click(screen.getByRole("button", { name: "login" })) await waitFor(() => expect(screen.getByTestId("user").textContent).toBe(USER.email)) expect(screen.getByTestId("project").textContent).toBe(PROJECT.name) }) it("treats a non-401 error from api.auth.me() as logged-out but logs it for diagnostics", async () => { const consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => {}) const err = new Error("network down") vi.spyOn(api.auth, "me").mockRejectedValue(err) renderProbe() await waitFor(() => expect(screen.getByTestId("loading").textContent).toBe("false")) expect(screen.getByTestId("user").textContent).toBe("none") expect(screen.getByTestId("project").textContent).toBe("none") expect(consoleErrorSpy).toHaveBeenCalledWith(err) }) it("logout clears user/project from context", async () => { vi.spyOn(api.auth, "me").mockResolvedValue({ user: USER, project: PROJECT }) vi.spyOn(api.auth, "logout").mockResolvedValue(undefined) const user = userEvent.setup() renderProbe() await waitFor(() => expect(screen.getByTestId("user").textContent).toBe(USER.email)) await user.click(screen.getByRole("button", { name: "logout" })) await waitFor(() => expect(screen.getByTestId("user").textContent).toBe("none")) expect(screen.getByTestId("project").textContent).toBe("none") }) })