import { describe, it, expect } from "vitest"; import { canPerformAction, getAvailableActions, getTransition, requiresNote, } from "@/lib/po-state-machine"; describe("PO State Machine", () => { describe("canPerformAction", () => { it("allows TECHNICAL to submit a DRAFT", () => { expect(canPerformAction("DRAFT", "submit", "TECHNICAL")).toBe(true); }); it("allows MANNING to submit a DRAFT", () => { expect(canPerformAction("DRAFT", "submit", "MANNING")).toBe(true); }); it("disallows ACCOUNTS from submitting a DRAFT", () => { expect(canPerformAction("DRAFT", "submit", "ACCOUNTS")).toBe(false); }); it("allows MANAGER to approve in MGR_REVIEW", () => { expect(canPerformAction("MGR_REVIEW", "approve", "MANAGER")).toBe(true); }); it("allows SUPERUSER to approve in MGR_REVIEW", () => { expect(canPerformAction("MGR_REVIEW", "approve", "SUPERUSER")).toBe(true); }); it("disallows TECHNICAL from approving", () => { expect(canPerformAction("MGR_REVIEW", "approve", "TECHNICAL")).toBe(false); }); it("allows ACCOUNTS to process payment on MGR_APPROVED", () => { expect(canPerformAction("MGR_APPROVED", "process_payment", "ACCOUNTS")).toBe(true); }); it("allows TECHNICAL to confirm receipt on PAID_DELIVERED", () => { expect(canPerformAction("PAID_DELIVERED", "confirm_receipt", "TECHNICAL")).toBe(true); }); it("disallows action on wrong status", () => { expect(canPerformAction("CLOSED", "approve", "MANAGER")).toBe(false); }); }); describe("getTransition", () => { it("returns correct target state for submit from DRAFT", () => { const t = getTransition("DRAFT", "submit"); expect(t?.to).toBe("SUBMITTED"); }); it("returns correct target state for approve from MGR_REVIEW", () => { const t = getTransition("MGR_REVIEW", "approve"); expect(t?.to).toBe("MGR_APPROVED"); }); it("returns correct target state for reject from MGR_REVIEW", () => { const t = getTransition("MGR_REVIEW", "reject"); expect(t?.to).toBe("REJECTED"); }); it("returns null for unknown action on status", () => { expect(getTransition("CLOSED", "approve")).toBeNull(); }); }); describe("requiresNote", () => { it("reject requires a note", () => { expect(requiresNote("MGR_REVIEW", "reject")).toBe(true); }); it("approve does not require a note", () => { expect(requiresNote("MGR_REVIEW", "approve")).toBe(false); }); it("approve_with_note requires a note", () => { expect(requiresNote("MGR_REVIEW", "approve_with_note")).toBe(true); }); it("request_edits requires a note", () => { expect(requiresNote("MGR_REVIEW", "request_edits")).toBe(true); }); }); describe("getAvailableActions", () => { it("returns submit for TECHNICAL on DRAFT", () => { const actions = getAvailableActions("DRAFT", "TECHNICAL"); expect(actions).toContain("submit"); }); it("returns all 5 actions for MANAGER on MGR_REVIEW", () => { const actions = getAvailableActions("MGR_REVIEW", "MANAGER"); expect(actions).toContain("approve"); expect(actions).toContain("approve_with_note"); expect(actions).toContain("reject"); expect(actions).toContain("request_edits"); expect(actions).toContain("request_vendor_id"); }); it("returns empty for ACCOUNTS on DRAFT", () => { const actions = getAvailableActions("DRAFT", "ACCOUNTS"); expect(actions).toHaveLength(0); }); it("returns empty for closed PO", () => { const actions = getAvailableActions("CLOSED", "MANAGER"); expect(actions).toHaveLength(0); }); // Role expansions added in feat: manager PO creation it("returns submit for MANAGER on DRAFT", () => { expect(getAvailableActions("DRAFT", "MANAGER")).toContain("submit"); }); it("returns submit for MANAGER on EDITS_REQUESTED", () => { expect(getAvailableActions("EDITS_REQUESTED", "MANAGER")).toContain("submit"); }); it("returns provide_vendor_id for ACCOUNTS on VENDOR_ID_PENDING", () => { expect(getAvailableActions("VENDOR_ID_PENDING", "ACCOUNTS")).toContain("provide_vendor_id"); }); it("still returns no submit for ACCOUNTS on DRAFT", () => { expect(getAvailableActions("DRAFT", "ACCOUNTS")).not.toContain("submit"); }); it("AUDITOR has no available actions on any status", () => { for (const status of ["DRAFT", "MGR_REVIEW", "VENDOR_ID_PENDING", "MGR_APPROVED"] as const) { expect(getAvailableActions(status, "AUDITOR")).toHaveLength(0); } }); }); describe("canPerformAction — new role expansions", () => { it("MANAGER can submit from DRAFT", () => { expect(canPerformAction("DRAFT", "submit", "MANAGER")).toBe(true); }); it("MANAGER can submit from EDITS_REQUESTED", () => { expect(canPerformAction("EDITS_REQUESTED", "submit", "MANAGER")).toBe(true); }); it("ACCOUNTS can provide_vendor_id from VENDOR_ID_PENDING", () => { expect(canPerformAction("VENDOR_ID_PENDING", "provide_vendor_id", "ACCOUNTS")).toBe(true); }); it("ACCOUNTS still cannot submit from DRAFT", () => { expect(canPerformAction("DRAFT", "submit", "ACCOUNTS")).toBe(false); }); it("AUDITOR cannot perform any action", () => { expect(canPerformAction("DRAFT", "submit", "AUDITOR")).toBe(false); expect(canPerformAction("MGR_REVIEW", "approve", "AUDITOR")).toBe(false); }); it("ADMIN cannot perform any PO state transitions", () => { expect(canPerformAction("DRAFT", "submit", "ADMIN")).toBe(false); expect(canPerformAction("MGR_REVIEW", "approve", "ADMIN")).toBe(false); expect(canPerformAction("MGR_APPROVED", "process_payment", "ADMIN")).toBe(false); }); }); });