/** * Vela Payroll Engine — Comprehensive Tests * * Run with: npx vitest src/lib/payroll/__tests__/engine.test.ts * or: npx vitest src/lib/payroll/__tests__/ */ import { describe, it, expect } from "vitest"; import { getTaxJurisdiction, calculatePayslip, AustraliaTax, USTax, UKTax, CanadaTax, NewZealandTax, SingaporeTax, FlatRateTax, PayrollEngine, isNativelySupported, getSupportedJurisdictions, progressiveTaxCalc, hourlyToAnnual, toPeriod, round2, type TaxJurisdiction, } from "../index"; // ── Utility Tests ──────────────────────────────────────────── describe("Utility functions", () => { it("rounds to 2 decimal places", () => { expect(round2(123.456)).toBe(123.46); expect(round2(100)).toBe(100); expect(round2(0.1 + 0.2)).toBe(0.3); }); it("converts hourly to annual", () => { expect(hourlyToAnnual(25, 38)).toBe(25 * 38 * 52); // 38h/w expect(hourlyToAnnual(50, 40)).toBe(50 * 40 * 52); // 40h/w }); it("converts annual to period amounts", () => { expect(toPeriod(52_000, "weekly")).toBe(1_000); expect(toPeriod(52_000, "fortnightly")).toBe(2_000); expect(toPeriod(60_000, "monthly")).toBe(5_000); }); it("calculates progressive tax correctly", () => { const brackets = [ { min: 0, max: 10_000, rate: 0.1 }, { min: 10_000, max: 50_000, rate: 0.2 }, { min: 50_000, max: null, rate: 0.3 }, ]; // $60,000 income: $1,000 + $8,000 + $3,000 = $12,000 expect(progressiveTaxCalc(60_000, brackets)).toBe(12_000); expect(progressiveTaxCalc(5_000, brackets)).toBe(500); expect(progressiveTaxCalc(0, brackets)).toBe(0); }); }); // ── Factory Tests ──────────────────────────────────────────── describe("Factory function", () => { it("returns Australia for AU", () => { const j = getTaxJurisdiction("AU"); expect(j.name).toBe("Australia"); expect(j.countryCode).toBe("AU"); }); it("returns US for USA (alpha-3)", () => { const j = getTaxJurisdiction("USA"); expect(j.name).toBe("United States"); }); it("returns UK for GB and UK", () => { expect(getTaxJurisdiction("GB").name).toBe("United Kingdom"); expect(getTaxJurisdiction("UK").name).toBe("United Kingdom"); }); it("returns FlatRateTax for unsupported country", () => { const j = getTaxJurisdiction("BR"); expect(j).toBeInstanceOf(FlatRateTax); }); it("returns FlatRateTax for DEFAULT", () => { const j = getTaxJurisdiction("XX"); expect(j).toBeInstanceOf(FlatRateTax); }); it("supports natively for core jurisdictions", () => { expect(isNativelySupported("AU")).toBe(true); expect(isNativelySupported("US")).toBe(true); expect(isNativelySupported("GB")).toBe(true); expect(isNativelySupported("CA")).toBe(true); expect(isNativelySupported("NZ")).toBe(true); expect(isNativelySupported("SG")).toBe(true); expect(isNativelySupported("DE")).toBe(false); }); it("lists supported jurisdictions", () => { const list = getSupportedJurisdictions(); expect(list.length).toBeGreaterThan(20); expect(list).toContain("AU"); expect(list).toContain("US"); expect(list).toContain("DE"); }); }); // ── Australia Tests ────────────────────────────────────────── describe("Australia (ATO 2025-26)", () => { const au = new AustraliaTax(); it("calculates $0 salary", () => { const result = calculatePayslip({ grossAnnual: 0, payFrequency: "monthly", jurisdiction: au, }); expect(result.netPay).toBe(0); expect(result.totalDeductions).toBe(0); }); it("calculates below tax-free threshold ($18,200)", () => { const result = calculatePayslip({ grossAnnual: 15_000, payFrequency: "fortnightly", jurisdiction: au, }); // No income tax, but Medicare Levy still applies expect(result.deductions.some((d) => d.name === "PAYG Income Tax")).toBe(true); const incomeTax = result.deductions.find((d) => d.name === "PAYG Income Tax"); expect(incomeTax!.amount).toBe(0); }); it("calculates $95,000 annual (typical professional)", () => { const result = calculatePayslip({ grossAnnual: 95_000, payFrequency: "monthly", jurisdiction: au, }); expect(result.grossAnnual).toBe(95_000); expect(result.grossPay).toBe(round2(95_000 / 12)); expect(result.jurisdiction).toBe("Australia"); // Income tax should be calculated (in the 30% bracket) const incomeTax = result.deductions.find((d) => d.name === "PAYG Income Tax"); expect(incomeTax!.amount).toBeGreaterThan(0); // Medicare Levy at 2% const medicare = result.deductions.find((d) => d.name === "Medicare Levy"); expect(medicare!.amount).toBe(round2(95_000 * 0.02)); // Super Guarantee at 11.5% const super_ = result.employerContributions.find( (c) => c.name === "Superannuation Guarantee" ); expect(super_!.amount).toBe(round2(95_000 * 0.115)); // Net pay should be less than gross expect(result.netPay).toBeLessThan(result.grossPay); }); it("calculates $190,000+ (top bracket)", () => { const result = calculatePayslip({ grossAnnual: 250_000, payFrequency: "monthly", jurisdiction: au, }); expect(result.totalDeductions).toBeGreaterThan(75_000); expect(result.totalEmployerContributions).toBe(round2(250_000 * 0.115)); }); }); // ── United States Tests ────────────────────────────────────── describe("United States (IRS 2025)", () => { it("calculates with no state tax (Texas)", () => { const us = new USTax({ stateTaxRate: 0, stateName: "TX" }); const result = calculatePayslip({ grossAnnual: 80_000, payFrequency: "monthly", jurisdiction: us, }); expect(result.jurisdiction).toBe("United States"); // No state tax expect(result.deductions.find((d) => d.name.includes("State"))).toBeUndefined(); }); it("calculates with state tax (California 9.3%)", () => { const us = new USTax({ stateTaxRate: 0.093, stateName: "CA" }); const result = calculatePayslip({ grossAnnual: 100_000, payFrequency: "monthly", jurisdiction: us, }); expect(result.deductions.find((d) => d.name.includes("CA"))).toBeDefined(); }); it("applies standard deduction", () => { const us = new USTax({ stateTaxRate: 0 }); const result = calculatePayslip({ grossAnnual: 15_000, payFrequency: "monthly", jurisdiction: us, }); // Below standard deduction ($15,000) → no federal tax const fedTax = result.deductions.find((d) => d.name === "Federal Income Tax"); expect(fedTax!.amount).toBe(0); }); it("applies Social Security cap", () => { const us = new USTax({ stateTaxRate: 0 }); const result = calculatePayslip({ grossAnnual: 200_000, payFrequency: "monthly", jurisdiction: us, }); const ss = result.deductions.find((d) => d.name === "Social Security Tax"); // Capped at $176,100 × 6.2% expect(ss!.amount).toBe(round2(176_100 * 0.062)); }); it("applies Additional Medicare Tax above $200k", () => { const us = new USTax({ stateTaxRate: 0 }); const result = calculatePayslip({ grossAnnual: 250_000, payFrequency: "monthly", jurisdiction: us, }); expect(result.deductions.find((d) => d.name === "Additional Medicare Tax")).toBeDefined(); }); it("calculates hourly: $45/h × 40h/week", () => { const us = new USTax({ stateTaxRate: 0.05, stateName: "NY" }); const result = calculatePayslip({ hourlyRate: 45, hoursPerWeek: 40, payFrequency: "monthly", jurisdiction: us, }); expect(result.grossAnnual).toBe(45 * 40 * 52); expect(result.netPay).toBeGreaterThan(0); }); }); // ── United Kingdom Tests ───────────────────────────────────── describe("United Kingdom (HMRC 2025-26)", () => { const uk = new UKTax(); it("calculates below personal allowance (£12,570)", () => { const result = calculatePayslip({ grossAnnual: 12_000, payFrequency: "monthly", jurisdiction: uk, }); const tax = result.deductions.find((d) => d.name === "Income Tax (PAYE)"); expect(tax!.amount).toBe(0); const ni = result.deductions.find((d) => d.name === "Employee National Insurance"); expect(ni!.amount).toBe(0); }); it("calculates £45,000 (basic rate)", () => { const result = calculatePayslip({ grossAnnual: 45_000, payFrequency: "monthly", jurisdiction: uk, }); expect(result.grossAnnual).toBe(45_000); expect(result.deductions.some((d) => d.name === "Income Tax (PAYE)")).toBe(true); expect(result.deductions.some((d) => d.name === "Employee National Insurance")).toBe(true); expect(result.employerContributions.some((c) => c.name === "Employer National Insurance")).toBe(true); }); it("tapers personal allowance above £100,000", () => { const result = calculatePayslip({ grossAnnual: 120_000, payFrequency: "monthly", jurisdiction: uk, }); // PA should be reduced from £12,570 // £120k - £100k = £20k / 2 = £10k reduction → PA = £2,570 expect(result.totalDeductions).toBeGreaterThan(30_000); }); it("zero personal allowance at £125,140+", () => { const result = calculatePayslip({ grossAnnual: 130_000, payFrequency: "monthly", jurisdiction: uk, }); expect(result.totalDeductions).toBeGreaterThan(40_000); }); }); // ── Canada Tests ───────────────────────────────────────────── describe("Canada (CRA 2025)", () => { const ca = new CanadaTax(); it("calculates $60,000 CAD", () => { const result = calculatePayslip({ grossAnnual: 60_000, payFrequency: "monthly", jurisdiction: ca, }); expect(result.jurisdiction).toBe("Canada"); expect(result.deductions.some((d) => d.name === "Federal Income Tax")).toBe(true); expect(result.deductions.some((d) => d.name === "CPP Contribution")).toBe(true); expect(result.deductions.some((d) => d.name === "EI Premium")).toBe(true); }); it("caps CPP at YAMPE", () => { const result = calculatePayslip({ grossAnnual: 100_000, payFrequency: "monthly", jurisdiction: ca, }); const cpp = result.deductions.find((d) => d.name === "CPP Contribution"); expect(cpp!.amount).toBe(round2((71_300 - 3_500) * 0.0595)); }); it("caps EI at maximum insurable earnings", () => { const result = calculatePayslip({ grossAnnual: 80_000, payFrequency: "monthly", jurisdiction: ca, }); const ei = result.deductions.find((d) => d.name === "EI Premium"); expect(ei!.amount).toBe(round2(65_700 * 0.0137)); }); }); // ── New Zealand Tests ──────────────────────────────────────── describe("New Zealand (IRD 2025)", () => { const nz = new NewZealandTax(); it("calculates $75,000 NZD", () => { const result = calculatePayslip({ grossAnnual: 75_000, payFrequency: "monthly", jurisdiction: nz, }); expect(result.jurisdiction).toBe("New Zealand"); expect(result.deductions.some((d) => d.name === "PAYE Income Tax")).toBe(true); expect(result.deductions.some((d) => d.name === "ACC Earner Levy")).toBe(true); }); it("has no employer contributions", () => { const result = calculatePayslip({ grossAnnual: 100_000, payFrequency: "monthly", jurisdiction: nz, }); expect(result.employerContributions).toHaveLength(0); }); }); // ── Singapore Tests ────────────────────────────────────────── describe("Singapore (IRAS 2025 + CPF)", () => { it("calculates CPF for SC/PR", () => { const sg = new SingaporeTax({ isCPRorSC: true }); const result = calculatePayslip({ grossAnnual: 84_000, // $7,000/mo (above $750 threshold, below $6,800 OW ceiling) payFrequency: "monthly", jurisdiction: sg, }); expect(result.deductions.some((d) => d.name === "CPF (Employee)")).toBe(true); expect(result.employerContributions.some((c) => c.name === "CPF (Employer)")).toBe(true); // No income tax deducted from payslip const incomeTax = result.deductions.find((d) => d.name === "Income Tax"); expect(incomeTax).toBeDefined(); expect(incomeTax!.amount).toBe(0); }); it("no CPF for foreign employee (EP)", () => { const sg = new SingaporeTax({ isCPRorSC: false }); const result = calculatePayslip({ grossAnnual: 120_000, payFrequency: "monthly", jurisdiction: sg, }); expect(result.deductions).toHaveLength(0); expect(result.employerContributions).toHaveLength(0); // Net = gross expect(result.netPay).toBe(result.grossPay); }); it("caps CPF at OW ceiling", () => { const sg = new SingaporeTax({ isCPRorSC: true }); const result = calculatePayslip({ grossAnnual: 120_000, // $10,000/mo — above $6,800 ceiling payFrequency: "monthly", jurisdiction: sg, }); const cpf = result.deductions.find((d) => d.name === "CPF (Employee)"); // Capped at $6,800 × 20% × 12 expect(cpf!.amount).toBe(round2(6_800 * 0.20 * 12)); }); it("no CPF below $750/mo", () => { const sg = new SingaporeTax({ isCPRorSC: true }); const result = calculatePayslip({ grossAnnual: 9_000, // $750/mo — at threshold payFrequency: "monthly", jurisdiction: sg, }); const cpf = result.deductions.find((d) => d.name === "CPF (Employee)"); expect(cpf).toBeUndefined(); }); }); // ── FlatRateTax Tests ──────────────────────────────────────── describe("FlatRateTax (generic fallback)", () => { it("calculates flat 25% tax", () => { const flat = new FlatRateTax({ flatIncomeTaxRate: 0.25, displayName: "Test Country", currency: "EUR", countryCode: "TC", }); const result = calculatePayslip({ grossAnnual: 100_000, payFrequency: "monthly", jurisdiction: flat, }); expect(result.deductions[0].amount).toBe(25_000); expect(result.jurisdiction).toBe("Test Country"); }); it("applies tax-free allowance", () => { const flat = new FlatRateTax({ flatIncomeTaxRate: 0.30, taxFreeAllowance: 10_000, displayName: "Test", currency: "EUR", }); const result = calculatePayslip({ grossAnnual: 50_000, payFrequency: "monthly", jurisdiction: flat, }); // Tax on $40,000 at 30% = $12,000 expect(result.deductions[0].amount).toBe(12_000); }); it("includes employer contributions", () => { const flat = new FlatRateTax({ flatIncomeTaxRate: 0.20, employerPensionRate: 0.10, displayName: "Test", currency: "EUR", }); const result = calculatePayslip({ grossAnnual: 80_000, payFrequency: "monthly", jurisdiction: flat, }); expect(result.employerContributions[0].amount).toBe(8_000); }); }); // ── Engine Tests ───────────────────────────────────────────── describe("PayrollEngine", () => { it("handles hourly input correctly", () => { const engine = new PayrollEngine(); const au = getTaxJurisdiction("AU"); const result = engine.calculate({ hourlyRate: 50, hoursPerWeek: 38, payFrequency: "fortnightly", jurisdiction: au, }); expect(result.grossAnnual).toBe(50 * 38 * 52); expect(result.payPeriod).toBe("fortnightly"); expect(result.netPay).toBeGreaterThan(0); }); it("returns consistent annual totals", () => { const engine = new PayrollEngine(); const uk = getTaxJurisdiction("GB"); const result = engine.calculate({ grossAnnual: 65_000, payFrequency: "weekly", jurisdiction: uk, }); expect(result.annualNetPay).toBe(round2(result.grossAnnual - result.totalDeductions)); }); it("total employer cost = gross + employer contributions", () => { const engine = new PayrollEngine(); const au = getTaxJurisdiction("AU"); const result = engine.calculate({ grossAnnual: 90_000, payFrequency: "monthly", jurisdiction: au, }); const expectedCost = toPeriod( result.grossAnnual + result.totalEmployerContributions, "monthly" ); expect(round2(result.totalEmployerCost)).toBe(round2(expectedCost)); }); }); // ── Cross-Jurisdiction Sanity Check ────────────────────────── describe("Cross-jurisdiction sanity check", () => { const jurisdictions = [ { code: "AU", salary: 95_000 }, { code: "US", salary: 95_000 }, { code: "GB", salary: 65_000 }, { code: "CA", salary: 90_000 }, { code: "NZ", salary: 90_000 }, { code: "SG", salary: 96_000 }, ]; jurisdictions.forEach(({ code, salary }) => { it(`${code} produces valid payslip for $${salary.toLocaleString()}`, () => { const j = getTaxJurisdiction(code); const result = calculatePayslip({ grossAnnual: salary, payFrequency: "monthly", jurisdiction: j, }); // Basic sanity checks expect(result.grossPay).toBeGreaterThan(0); expect(result.netPay).toBeGreaterThan(0); expect(result.netPay).toBeLessThanOrEqual(result.grossPay); expect(result.totalDeductions).toBeGreaterThanOrEqual(0); expect(result.totalEmployerContributions).toBeGreaterThanOrEqual(0); expect(result.jurisdictionCode).toBe(code.toUpperCase()); }); }); });