import { describe, it, expect, afterEach, vi } from "vitest"; import { hasPermission } from "@/lib/permissions"; // Verifies the crewing rows of the §6 grant matrix in the wiki // Crewing-Implementation-Spec are wired up exactly as written. describe("Crewing permissions (spec §6)", () => { it("SITE_STAFF holds its site-level grants", () => { for (const p of [ "request_relief_cover", "sign_off_crew", "view_crew_records", "upload_crew_records", "issue_ppe", "apply_leave", "record_attendance", "view_attendance", "raise_appraisal", ] as const) { expect(hasPermission("SITE_STAFF", p)).toBe(true); } }); it("SITE_STAFF cannot raise requisitions or decide leave or do any purchasing", () => { expect(hasPermission("SITE_STAFF", "raise_requisition")).toBe(false); expect(hasPermission("SITE_STAFF", "decide_leave")).toBe(false); expect(hasPermission("SITE_STAFF", "create_po")).toBe(false); expect(hasPermission("SITE_STAFF", "manage_ranks")).toBe(false); }); it("MPO (MANNING) has NO attendance or leave access (R5/R1)", () => { expect(hasPermission("MANNING", "record_attendance")).toBe(false); expect(hasPermission("MANNING", "view_attendance")).toBe(false); expect(hasPermission("MANNING", "apply_leave")).toBe(false); expect(hasPermission("MANNING", "decide_leave")).toBe(false); }); it("MPO sources recruitment but never gives final approvals", () => { expect(hasPermission("MANNING", "raise_requisition")).toBe(true); expect(hasPermission("MANNING", "manage_candidates")).toBe(true); expect(hasPermission("MANNING", "record_interview_result")).toBe(true); expect(hasPermission("MANNING", "verify_site_records")).toBe(true); // Approvals are Manager-only: expect(hasPermission("MANNING", "approve_salary_structure")).toBe(false); expect(hasPermission("MANNING", "select_candidate")).toBe(false); expect(hasPermission("MANNING", "approve_interview_waiver")).toBe(false); }); it("Manager owns every crewing approval gate (R1/R2/R8)", () => { for (const p of [ "decide_leave", "approve_interview_waiver", "approve_salary_structure", "select_candidate", "approve_appraisal", "approve_wage_report", "generate_wage_report", ] as const) { expect(hasPermission("MANAGER", p)).toBe(true); } }); it("Accounts verifies bank/EPF and sees wages only (R11)", () => { expect(hasPermission("ACCOUNTS", "verify_bank_epf")).toBe(true); expect(hasPermission("ACCOUNTS", "view_wage_report")).toBe(true); expect(hasPermission("ACCOUNTS", "view_crew_records")).toBe(true); expect(hasPermission("ACCOUNTS", "verify_site_records")).toBe(false); expect(hasPermission("ACCOUNTS", "record_attendance")).toBe(false); }); it("manage_ranks is Manager + Admin only (not SuperUser)", () => { expect(hasPermission("MANAGER", "manage_ranks")).toBe(true); expect(hasPermission("ADMIN", "manage_ranks")).toBe(true); expect(hasPermission("SUPERUSER", "manage_ranks")).toBe(false); expect(hasPermission("MANNING", "manage_ranks")).toBe(false); }); it("Auditor keeps read-only crewing visibility", () => { expect(hasPermission("AUDITOR", "view_requisitions")).toBe(true); expect(hasPermission("AUDITOR", "view_crew_records")).toBe(true); expect(hasPermission("AUDITOR", "view_wage_report")).toBe(true); expect(hasPermission("AUDITOR", "raise_requisition")).toBe(false); }); }); describe("CREWING_ENABLED flag", () => { afterEach(() => { vi.unstubAllEnvs(); vi.resetModules(); }); it("defaults off when the env var is unset", async () => { vi.resetModules(); vi.stubEnv("NEXT_PUBLIC_CREWING_ENABLED", ""); const flags = await import("@/lib/feature-flags"); expect(flags.CREWING_ENABLED).toBe(false); }); it("is on only for the exact string \"true\"", async () => { vi.resetModules(); vi.stubEnv("NEXT_PUBLIC_CREWING_ENABLED", "true"); const flags = await import("@/lib/feature-flags"); expect(flags.CREWING_ENABLED).toBe(true); }); });