pelagia-portal/App/tests/unit/po-state-machine.test.ts
2026-05-18 23:18:58 +05:30

164 lines
5.8 KiB
TypeScript

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);
});
});
});