import { describe, it, expect, vi } from "vitest"; // L'enum est aussi un type ; on l'importe de manière statique pour TS. import { UserRole } from "@/generated/prisma/enums"; // next-auth tire next/server qui n'est pas résolu dans le tunnel vitest. // On stubbe les modules nécessaires avant d'importer carbet-access (qui // importe Session de next-auth uniquement en type-only, mais authorization.ts // dépend de auth() — d'où le mock). vi.mock("next-auth", () => ({ default: () => ({}) })); vi.mock("@/auth", () => ({ auth: () => Promise.resolve(null) })); vi.mock("@/lib/authorization", () => ({ requireRole: () => Promise.resolve({}), })); const { canManageCarbet } = await import("@/lib/carbet-access"); // Pure-data shape qui satisfait la signature de canManageCarbet sans tirer // next-auth/server (incompatible vitest sans setup). type MinimalSession = { user: { id: string; role: UserRole; organizationId?: string | null; email?: string | null; }; }; function makeSession(opts: { userId: string; role: UserRole; organizationId?: string | null; }): MinimalSession { return { user: { id: opts.userId, role: opts.role, organizationId: opts.organizationId ?? null, email: "test@example.com", }, }; } describe("canManageCarbet", () => { it("admin can always manage", () => { const session = makeSession({ userId: "u-admin", role: UserRole.ADMIN }); expect(canManageCarbet(session as unknown as Parameters[0], "u-other", [])).toBe(true); expect(canManageCarbet(session as unknown as Parameters[0], "u-other", ["org-x"])).toBe(true); }); it("owner can manage their own carbet", () => { const session = makeSession({ userId: "u1", role: UserRole.OWNER }); expect(canManageCarbet(session as unknown as Parameters[0], "u1", [])).toBe(true); }); it("owner cannot manage someone else's carbet", () => { const session = makeSession({ userId: "u1", role: UserRole.OWNER }); expect(canManageCarbet(session as unknown as Parameters[0], "u2", [])).toBe(false); }); it("CE_MANAGER can manage carbet linked to their org via membership", () => { const session = makeSession({ userId: "u-ce", role: UserRole.CE_MANAGER, organizationId: "org-1", }); expect(canManageCarbet(session as unknown as Parameters[0], "u-creator", ["org-1"])).toBe(true); }); it("CE_MANAGER cannot manage carbet of another org", () => { const session = makeSession({ userId: "u-ce", role: UserRole.CE_MANAGER, organizationId: "org-1", }); expect(canManageCarbet(session as unknown as Parameters[0], "u-creator", ["org-2"])).toBe(false); }); it("CE_MANAGER cannot manage when carbet has no memberships", () => { const session = makeSession({ userId: "u-ce", role: UserRole.CE_MANAGER, organizationId: "org-1", }); expect(canManageCarbet(session as unknown as Parameters[0], "u-creator", [])).toBe(false); }); it("CE_MANAGER without organizationId cannot manage anything via membership", () => { const session = makeSession({ userId: "u-ce", role: UserRole.CE_MANAGER, organizationId: null, }); expect(canManageCarbet(session as unknown as Parameters[0], "u-creator", ["org-1"])).toBe(false); }); it("TOURIST cannot manage", () => { const session = makeSession({ userId: "u1", role: UserRole.TOURIST }); expect(canManageCarbet(session as unknown as Parameters[0], "u-other", ["org-1"])).toBe(false); expect(canManageCarbet(session as unknown as Parameters[0], "u1", ["org-1"])).toBe(true); // matches as owner }); it("CE_MANAGER can also manage as direct owner (rare but possible)", () => { const session = makeSession({ userId: "u-ce", role: UserRole.CE_MANAGER, organizationId: "org-1", }); expect(canManageCarbet(session as unknown as Parameters[0], "u-ce", [])).toBe(true); }); });