import { describe, it, expect } from "vitest"; import { formatCurrency, formatDate, formatDateTime, generatePoNumber, PO_STATUS_LABELS, PO_STATUS_VARIANTS, } from "@/lib/utils"; describe("formatCurrency", () => { it("formats numbers as INR by default", () => { const result = formatCurrency(1000); expect(result).toMatch(/1,000/); expect(result).toMatch(/₹|INR/); }); it("formats decimal amounts to 2 decimal places", () => { const result = formatCurrency(1234.5); expect(result).toMatch(/1,234/); }); it("accepts string input and formats it", () => { const result = formatCurrency("500"); expect(result).toMatch(/500/); }); it("formats zero without error", () => { const result = formatCurrency(0); expect(result).toMatch(/0/); }); it("formats large numbers with commas", () => { const result = formatCurrency(225498); expect(result).toMatch(/2,25,498|225,498/); // en-IN uses 2,25,498 grouping }); }); describe("formatDate", () => { it("returns a readable date string", () => { const result = formatDate(new Date("2026-04-29")); expect(result).toMatch(/2026/); expect(result).toMatch(/Apr|29/); }); it("accepts a date string as input", () => { const result = formatDate("2026-01-15"); expect(result).toMatch(/2026/); }); }); describe("formatDateTime", () => { it("includes both date and time", () => { const result = formatDateTime(new Date("2026-04-29T14:30:00")); expect(result).toMatch(/2026/); // Should contain hours expect(result).toMatch(/\d{1,2}:\d{2}/); }); }); describe("generatePoNumber", () => { it("starts with PO-", () => { expect(generatePoNumber()).toMatch(/^PO-/); }); it("includes the current year", () => { const year = new Date().getFullYear().toString(); expect(generatePoNumber()).toContain(year); }); it("generates a 5-digit zero-padded sequence", () => { const result = generatePoNumber(); // Format: PO-YYYY-NNNNN expect(result).toMatch(/^PO-\d{4}-\d{5}$/); }); it("generates unique values across calls", () => { const numbers = new Set(Array.from({ length: 20 }, () => generatePoNumber())); // Very unlikely to get a collision with 20 draws from 100000 expect(numbers.size).toBeGreaterThan(1); }); }); describe("PO_STATUS_LABELS", () => { it("maps every status to a non-empty label", () => { const statuses = [ "DRAFT", "SUBMITTED", "MGR_REVIEW", "VENDOR_ID_PENDING", "EDITS_REQUESTED", "REJECTED", "MGR_APPROVED", "SENT_FOR_PAYMENT", "PAID_DELIVERED", "CLOSED", ] as const; for (const s of statuses) { expect(PO_STATUS_LABELS[s]).toBeTruthy(); } }); }); describe("PO_STATUS_VARIANTS", () => { it("assigns danger variant to REJECTED", () => { expect(PO_STATUS_VARIANTS["REJECTED"]).toBe("danger"); }); it("assigns success variant to MGR_APPROVED", () => { expect(PO_STATUS_VARIANTS["MGR_APPROVED"]).toBe("success"); }); it("assigns warning variant to EDITS_REQUESTED", () => { expect(PO_STATUS_VARIANTS["EDITS_REQUESTED"]).toBe("warning"); }); it("assigns outline variant to DRAFT", () => { expect(PO_STATUS_VARIANTS["DRAFT"]).toBe("outline"); }); });