import { afterEach, describe, expect, it } from "vitest"; import { addMockInvoiceComment, areMocksEnabled, getMockApprovalPolicies, getMockApprovals, getMockDepartments, getMockGlAccounts, getMockInvoice, getMockInvoices, getMockPendingApprovals, getMockSessionUser, getMockUsers, getMockVendors, resetMockApprovalPolicies, resetMockApprovals, resetMockDepartments, resetMockGlAccounts, resetMockInvoices, resetMockSession, resetMockUsers, resetMockVendors, setMockSessionUserId, transitionMockInvoiceStatus, updateMockApprovalStatus, updateMockInvoiceHeader, updateMockInvoiceLines, updateMockInvoicePayDate, upsertMockDepartment, upsertMockGlAccount, upsertMockVendor, upsertMockUser, upsertMockApprovalPolicy, } from "@/mocks"; describe("mocks module", () => { afterEach(() => { resetMockInvoices(); resetMockVendors(); resetMockGlAccounts(); resetMockDepartments(); resetMockUsers(); resetMockApprovalPolicies(); resetMockApprovals(); resetMockSession(); }); it("defaults to mocks enabled", () => { expect(areMocksEnabled()).toBe(true); }); it("exposes sample invoices and vendors", () => { expect(getMockVendors().length).toBeGreaterThan(0); expect(getMockInvoices().length).toBeGreaterThanOrEqual(6); }); it("seeds Stampli catalog fields on every invoice (AP-47)", () => { const invoices = getMockInvoices(); expect(invoices.length).toBeGreaterThan(0); for (const invoice of invoices) { expect(typeof invoice.hasBolt).toBe("boolean"); expect(typeof invoice.hasBell).toBe("boolean"); expect(typeof invoice.hasEye).toBe("boolean"); expect(invoice.actionLabel.length).toBeGreaterThan(0); expect(invoice.lastUpdate).toMatch(/^\d{4}-\d{2}-\d{2}$/); expect(invoice.invoiceDate).toMatch(/^\d{4}-\d{2}-\d{2}$/); expect(invoice.processingBegan).toMatch(/^\d{4}-\d{2}-\d{2}$/); expect(typeof invoice.tagging).toBe("string"); expect(typeof invoice.fs).toBe("string"); expect(typeof invoice.description).toBe("string"); expect(typeof invoice.invoiceType).toBe("string"); expect(typeof invoice.location).toBe("string"); expect(typeof invoice.paymentAccount).toBe("string"); expect(invoice.relatedInvoice === null || typeof invoice.relatedInvoice === "string").toBe( true, ); expect(invoice.rowCount).toBe(invoice.lines.length); } const pending = invoices.filter((invoice) => invoice.status === "pending_approval"); expect(pending.every((invoice) => invoice.actionLabel === "Approve invoice")).toBe(true); }); it("seeds at least two invoices per dashboard tab", () => { const invoices = getMockInvoices(); const pending = invoices.filter((invoice) => invoice.status === "pending_approval"); const ready = invoices.filter((invoice) => invoice.status === "approved"); expect(pending.length).toBeGreaterThanOrEqual(2); expect(ready.length).toBeGreaterThanOrEqual(2); expect(invoices.every((invoice) => invoice.invoiceNumbers && invoice.amount >= 0)).toBe(true); }); it("updates pay date in the mutable mock store", () => { const before = getMockInvoices().find((invoice) => invoice.id === "inv-1"); expect(before).toBeDefined(); const updated = updateMockInvoicePayDate("inv-1", "2026-08-18"); expect(updated.payDate).toBe("2026-08-18"); const after = getMockInvoices().find((invoice) => invoice.id === "inv-1"); expect(after?.payDate).toBe("2026-08-18"); }); it("throws when updating an unknown invoice", () => { expect(() => updateMockInvoicePayDate("missing", "2026-08-18")).toThrow( /Mock invoice not found/, ); }); it("returns invoice detail with lines, comments, and activity", () => { const invoice = getMockInvoice("inv-2"); expect(invoice).toBeDefined(); expect(invoice?.documentUrl).toBe("/fixtures/sample-invoice.pdf"); expect(invoice?.lines.length).toBeGreaterThan(0); expect(invoice?.comments.length).toBeGreaterThan(0); expect(invoice?.activity.length).toBeGreaterThan(0); }); it("updates header and lines coding against mocks", () => { const updated = updateMockInvoiceHeader("inv-2", { memo: "Updated memo", amountDue: 4700 }); expect(updated.memo).toBe("Updated memo"); expect(updated.amountDue).toBe(4700); const withLines = updateMockInvoiceLines("inv-2", [ { id: "inv-2-line-1", description: "Updated line", amount: 4700, glAccountId: "gl-2", departmentId: "dept-1", }, ]); expect(withLines.lines).toHaveLength(1); expect(withLines.lines[0].description).toBe("Updated line"); expect(getMockInvoice("inv-2")?.lines[0].description).toBe("Updated line"); }); it("adds comments and transitions status with activity", () => { const withComment = addMockInvoiceComment("inv-2", { authorUserId: "user-1", authorName: "Alex Rivera", body: "Need another look", }); expect(withComment.comments.some((comment) => comment.body === "Need another look")).toBe(true); const approved = transitionMockInvoiceStatus("inv-2", "approved", { actorUserId: "user-2", actorName: "Jordan Lee", message: "Approved", }); expect(approved.status).toBe("approved"); expect(approved.activity.some((entry) => entry.message === "Approved")).toBe(true); expect(getMockPendingApprovals().some((item) => item.invoiceId === "inv-2")).toBe(false); expect(getMockApprovals().find((item) => item.invoiceId === "inv-2")?.status).toBe("approved"); }); it("returns undefined for unknown invoice ids", () => { expect(getMockInvoice("missing-invoice")).toBeUndefined(); }); it("switches mock session user", () => { expect(getMockSessionUser().id).toBe("user-1"); const next = setMockSessionUserId("user-2"); expect(next.role).toBe("approver"); expect(getMockSessionUser().id).toBe("user-2"); }); it("includes inv-8 referenced by approvals", () => { expect(getMockInvoice("inv-8")).toBeDefined(); expect(getMockApprovals().some((item) => item.invoiceId === "inv-8")).toBe(true); }); it("seeds settings entities and supports upsert", () => { expect(getMockVendors().length).toBeGreaterThanOrEqual(4); expect(getMockGlAccounts().length).toBeGreaterThanOrEqual(3); expect(getMockDepartments().length).toBeGreaterThanOrEqual(3); expect(getMockUsers().length).toBeGreaterThanOrEqual(3); expect(getMockApprovalPolicies().length).toBeGreaterThanOrEqual(3); const vendor = upsertMockVendor({ id: "vendor-new", name: "New Vendor", email: "new@example.com", defaultPaymentMethod: "ach", }); expect(getMockVendors().some((row) => row.id === vendor.id)).toBe(true); upsertMockGlAccount({ id: "gl-new", code: "9999", name: "Misc" }); expect(getMockGlAccounts().some((row) => row.id === "gl-new")).toBe(true); upsertMockDepartment({ id: "dept-new", code: "NEW", name: "New Dept" }); expect(getMockDepartments().some((row) => row.id === "dept-new")).toBe(true); upsertMockUser({ id: "user-new", name: "New User", email: "new.user@seahaven.example", role: "approver", }); expect(getMockUsers().some((row) => row.id === "user-new")).toBe(true); upsertMockApprovalPolicy({ id: "policy-new", name: "Ad hoc", amountThreshold: 250, approverRole: "admin", }); expect(getMockApprovalPolicies().some((row) => row.id === "policy-new")).toBe(true); }); it("lists pending approvals and updates status", () => { const pending = getMockPendingApprovals(); expect(pending.length).toBeGreaterThanOrEqual(2); expect(getMockApprovals().length).toBeGreaterThanOrEqual(pending.length); const first = pending[0]; const updated = updateMockApprovalStatus(first.id, "approved"); expect(updated.status).toBe("approved"); expect(getMockPendingApprovals().some((row) => row.id === first.id)).toBe(false); }); it("throws when updating an unknown approval", () => { expect(() => updateMockApprovalStatus("missing", "rejected")).toThrow( /Mock approval not found/, ); }); });