/** * Unit tests for `getAdminUser()`. The dev_session cookie bypass has been * removed; the only path into the admin is through a real Neon Auth * session. These tests mock the `getSession()` function and the DB layer * to exercise the lookup. */ import { describe, it, expect, vi, beforeEach } from "vitest"; // Use vi.hoisted to ensure mocks are available when vi.mock runs const { mockDb, mockWithPlatformAdmin, mockGetSession, mockCookies } = vi.hoisted(() => { const mockDb = { select: vi.fn(), }; return { mockDb, mockWithPlatformAdmin: vi.fn(async (fn: (db: typeof mockDb) => Promise) => { return fn(mockDb); }), mockGetSession: vi.fn(), mockCookies: vi.fn(), }; }); // Stub the server-only guard so the module can be imported under vitest. vi.mock("server-only", () => ({})); // Mock the Drizzle client wrapper vi.mock("@/db/client", () => ({ withPlatformAdmin: mockWithPlatformAdmin, })); // Mock the getSession() function vi.mock("@/lib/auth", () => ({ getSession: mockGetSession, })); // Mock cookies() so we don't read a real cookie store vi.mock("next/headers", () => ({ cookies: mockCookies, })); import { getAdminUser, buildDevAdmin, permissionsForRole } from "@/lib/admin-permissions"; const cookieStore = { get: vi.fn() }; beforeEach(() => { mockDb.select.mockReset(); mockWithPlatformAdmin.mockReset(); mockGetSession.mockReset(); mockCookies.mockImplementation(() => Promise.resolve(cookieStore)); cookieStore.get.mockReturnValue(undefined); }); describe("getAdminUser()", () => { it("returns null when there is no Neon Auth session", async () => { mockGetSession.mockResolvedValue({ data: null }); const u = await getAdminUser(); expect(u).toBeNull(); }); it("returns null when the session has no email", async () => { mockGetSession.mockResolvedValue({ data: { user: { name: "no-email" } } }); const u = await getAdminUser(); expect(u).toBeNull(); }); it("returns null when the email is not in the users table", async () => { mockGetSession.mockResolvedValue({ data: { user: { email: "unknown@example.com" } } }); // First select: users. Returns empty. mockDb.select.mockReturnValueOnce({ from: () => ({ where: () => ({ limit: async () => [], }), }), }); const u = await getAdminUser(); expect(u).toBeNull(); }); it("returns null when the user exists but has no admin_user_brands row", async () => { mockGetSession.mockResolvedValue({ data: { user: { email: "no-brand@example.com" } } }); // First select: users — returns the user mockDb.select .mockReturnValueOnce({ from: () => ({ where: () => ({ limit: async () => [ { id: "user-1", email: "no-brand@example.com", name: "No Brand", role: "brand_admin", }, ], }), }), }) // Second select: adminUserBrands — returns empty // The real code awaits `.from().innerJoin().where()` directly (no .limit()), // so the mock makes `.where()` itself the thenable. .mockReturnValueOnce({ from: () => ({ innerJoin: () => ({ where: async () => [], }), }), }); const u = await getAdminUser(); expect(u).toBeNull(); }); it("returns a fully-populated AdminUser for a provisioned brand_admin", async () => { mockGetSession.mockResolvedValue({ data: { user: { email: "admin@tuxedo.example" } } }); mockDb.select .mockReturnValueOnce({ from: () => ({ where: () => ({ limit: async () => [ { id: "user-tux", email: "admin@tuxedo.example", name: "Tux Admin", role: "brand_admin", }, ], }), }), }) // The real code awaits `.from().innerJoin().where()` directly (no .limit()), // so the mock makes `.where()` itself the thenable. .mockReturnValueOnce({ from: () => ({ innerJoin: () => ({ where: async () => [ { brandId: "brand-tux", brandName: "Tuxedo Citrus", brandSlug: "tuxedo", }, ], }), }), }); const u = await getAdminUser(); expect(u).not.toBeNull(); expect(u?.email).toBe("admin@tuxedo.example"); expect(u?.brand_id).toBe("brand-tux"); expect(u?.brand_slug).toBe("tuxedo"); expect(u?.role).toBe("brand_admin"); expect(u?.can_manage_products).toBe(true); expect(u?.can_manage_team).toBe(true); }); }); describe("buildDevAdmin()", () => { it("returns a platform_admin with no brand", () => { const u = buildDevAdmin("platform_admin"); expect(u.role).toBe("platform_admin"); expect(u.brand_id).toBeNull(); expect(u.brand_slug).toBeNull(); expect(u.can_manage_billing).toBe(true); }); it("returns a brand_admin tied to the tuxedo brand", () => { const u = buildDevAdmin("brand_admin"); expect(u.role).toBe("brand_admin"); expect(u.brand_slug).toBe("tuxedo"); expect(u.can_manage_users).toBe(false); }); it("returns a store_employee with limited permissions", () => { const u = buildDevAdmin("store_employee"); expect(u.role).toBe("store_employee"); expect(u.can_manage_products).toBe(false); expect(u.can_manage_orders).toBe(true); expect(u.can_manage_billing).toBe(false); }); }); describe("permissionsForRole()", () => { it("platform_admin can do everything", () => { const p = permissionsForRole("platform_admin"); expect(Object.values(p).every((v) => v === true)).toBe(true); }); it("brand_admin can manage most things but not users", () => { const p = permissionsForRole("brand_admin"); expect(p.can_manage_users).toBe(false); expect(p.can_manage_billing).toBe(true); }); it("store_employee is restricted to orders + pickup", () => { const p = permissionsForRole("store_employee"); expect(p.can_manage_orders).toBe(true); expect(p.can_manage_pickup).toBe(true); expect(p.can_manage_products).toBe(false); expect(p.can_manage_billing).toBe(false); }); });