import { describe, expect, it, vi, beforeEach, afterEach } from "vitest"; import { renderHook } from "@testing-library/react"; // --------------------------------------------------------------------------- // Mock next-auth/react so the hook can run without a real auth provider. // --------------------------------------------------------------------------- const mockUseSession = vi.fn(); vi.mock("next-auth/react", () => ({ useSession: () => mockUseSession(), })); const { usePermissions } = await import("./usePermissions.js"); // --------------------------------------------------------------------------- // Helper: build a mock session object with the given role. // --------------------------------------------------------------------------- function sessionWith(role: string) { return { data: { user: { role } } }; } // --------------------------------------------------------------------------- // Tests // --------------------------------------------------------------------------- describe("usePermissions", () => { beforeEach(() => { mockUseSession.mockReset(); }); afterEach(() => { vi.restoreAllMocks(); }); // ------------------------------------------------------------------------- // No session / unauthenticated // ------------------------------------------------------------------------- describe("when there is no session", () => { it("falls back to role USER when data is null", () => { mockUseSession.mockReturnValue({ data: null }); const { result } = renderHook(() => usePermissions()); expect(result.current.role).toBe("USER"); }); it("falls back to role USER when data is undefined", () => { mockUseSession.mockReturnValue({ data: undefined }); const { result } = renderHook(() => usePermissions()); expect(result.current.role).toBe("USER"); }); it("falls back to role USER when user has no role property", () => { mockUseSession.mockReturnValue({ data: { user: {} } }); const { result } = renderHook(() => usePermissions()); expect(result.current.role).toBe("USER"); }); it("denies all privileged permissions for anonymous user", () => { mockUseSession.mockReturnValue({ data: null }); const { result } = renderHook(() => usePermissions()); expect(result.current.canViewCosts).toBe(false); expect(result.current.canEdit).toBe(false); expect(result.current.canManageUsers).toBe(false); expect(result.current.canManageBlueprints).toBe(false); expect(result.current.canViewScores).toBe(false); }); }); // ------------------------------------------------------------------------- // ADMIN role // ------------------------------------------------------------------------- describe("ADMIN role", () => { beforeEach(() => { mockUseSession.mockReturnValue(sessionWith("ADMIN")); }); it("exposes role as ADMIN", () => { const { result } = renderHook(() => usePermissions()); expect(result.current.role).toBe("ADMIN"); }); it("canViewCosts is true", () => { const { result } = renderHook(() => usePermissions()); expect(result.current.canViewCosts).toBe(true); }); it("canEdit is true", () => { const { result } = renderHook(() => usePermissions()); expect(result.current.canEdit).toBe(true); }); it("canManageUsers is true", () => { const { result } = renderHook(() => usePermissions()); expect(result.current.canManageUsers).toBe(true); }); it("canManageBlueprints is true", () => { const { result } = renderHook(() => usePermissions()); expect(result.current.canManageBlueprints).toBe(true); }); it("canViewScores is true", () => { const { result } = renderHook(() => usePermissions()); expect(result.current.canViewScores).toBe(true); }); }); // ------------------------------------------------------------------------- // MANAGER role // ------------------------------------------------------------------------- describe("MANAGER role", () => { beforeEach(() => { mockUseSession.mockReturnValue(sessionWith("MANAGER")); }); it("exposes role as MANAGER", () => { const { result } = renderHook(() => usePermissions()); expect(result.current.role).toBe("MANAGER"); }); it("canViewCosts is true", () => { const { result } = renderHook(() => usePermissions()); expect(result.current.canViewCosts).toBe(true); }); it("canEdit is true", () => { const { result } = renderHook(() => usePermissions()); expect(result.current.canEdit).toBe(true); }); it("canManageUsers is false", () => { const { result } = renderHook(() => usePermissions()); expect(result.current.canManageUsers).toBe(false); }); it("canManageBlueprints is false", () => { const { result } = renderHook(() => usePermissions()); expect(result.current.canManageBlueprints).toBe(false); }); it("canViewScores is true", () => { const { result } = renderHook(() => usePermissions()); expect(result.current.canViewScores).toBe(true); }); }); // ------------------------------------------------------------------------- // CONTROLLER role // ------------------------------------------------------------------------- describe("CONTROLLER role", () => { beforeEach(() => { mockUseSession.mockReturnValue(sessionWith("CONTROLLER")); }); it("exposes role as CONTROLLER", () => { const { result } = renderHook(() => usePermissions()); expect(result.current.role).toBe("CONTROLLER"); }); it("canViewCosts is true", () => { const { result } = renderHook(() => usePermissions()); expect(result.current.canViewCosts).toBe(true); }); it("canEdit is false (CONTROLLER is not in EDIT_ROLES)", () => { const { result } = renderHook(() => usePermissions()); expect(result.current.canEdit).toBe(false); }); it("canManageUsers is false", () => { const { result } = renderHook(() => usePermissions()); expect(result.current.canManageUsers).toBe(false); }); it("canManageBlueprints is false", () => { const { result } = renderHook(() => usePermissions()); expect(result.current.canManageBlueprints).toBe(false); }); it("canViewScores is false (CONTROLLER is not in SCORE_ROLES)", () => { const { result } = renderHook(() => usePermissions()); expect(result.current.canViewScores).toBe(false); }); }); // ------------------------------------------------------------------------- // USER role (default / authenticated but unprivileged) // ------------------------------------------------------------------------- describe("USER role", () => { beforeEach(() => { mockUseSession.mockReturnValue(sessionWith("USER")); }); it("exposes role as USER", () => { const { result } = renderHook(() => usePermissions()); expect(result.current.role).toBe("USER"); }); it("canViewCosts is false", () => { const { result } = renderHook(() => usePermissions()); expect(result.current.canViewCosts).toBe(false); }); it("canEdit is false", () => { const { result } = renderHook(() => usePermissions()); expect(result.current.canEdit).toBe(false); }); it("canManageUsers is false", () => { const { result } = renderHook(() => usePermissions()); expect(result.current.canManageUsers).toBe(false); }); it("canManageBlueprints is false", () => { const { result } = renderHook(() => usePermissions()); expect(result.current.canManageBlueprints).toBe(false); }); it("canViewScores is false", () => { const { result } = renderHook(() => usePermissions()); expect(result.current.canViewScores).toBe(false); }); }); // ------------------------------------------------------------------------- // Unknown / arbitrary role // ------------------------------------------------------------------------- describe("unknown role", () => { it("denies all privileged permissions for an unknown role string", () => { mockUseSession.mockReturnValue(sessionWith("SUPER_DUPER_ADMIN")); const { result } = renderHook(() => usePermissions()); expect(result.current.canViewCosts).toBe(false); expect(result.current.canEdit).toBe(false); expect(result.current.canManageUsers).toBe(false); expect(result.current.canManageBlueprints).toBe(false); expect(result.current.canViewScores).toBe(false); }); it("still surfaces the raw role string for arbitrary roles", () => { mockUseSession.mockReturnValue(sessionWith("VIEWER")); const { result } = renderHook(() => usePermissions()); expect(result.current.role).toBe("VIEWER"); }); }); });