import { afterAll, beforeEach, describe, expect, it } from "vitest"; import { prisma, ensureUser, resetUser, U, closePrisma } from "./helpers"; import { rolloverFixedPlans } from "../src/jobs/rollover"; describe("rolloverFixedPlans", () => { beforeEach(async () => { await resetUser(U); await ensureUser(U); }); it("advances overdue plans and resets funding", async () => { const plan = await prisma.fixedPlan.create({ data: { userId: U, name: "Test Plan", totalCents: 10000n, fundedCents: 6000n, priority: 10, cycleStart: new Date("2025-01-01T00:00:00Z"), dueOn: new Date("2025-01-05T00:00:00Z"), periodDays: 30, }, select: { id: true }, }); const results = await rolloverFixedPlans(prisma, "2025-01-10T00:00:00Z"); const match = results.find((r) => r.planId === plan.id); expect(match?.cyclesAdvanced).toBe(1); expect(match?.deficitCents).toBe(4000); const updated = await prisma.fixedPlan.findUniqueOrThrow({ where: { id: plan.id } }); expect(updated.fundedCents).toBe(0n); expect(updated.dueOn.toISOString()).toBe("2025-02-04T00:00:00.000Z"); }); it("handles multiple missed cycles and carries surplus", async () => { const plan = await prisma.fixedPlan.create({ data: { userId: U, name: "Surplus Plan", totalCents: 5000n, fundedCents: 12000n, priority: 5, cycleStart: new Date("2025-01-01T00:00:00Z"), dueOn: new Date("2025-01-10T00:00:00Z"), periodDays: 15, }, select: { id: true }, }); const results = await rolloverFixedPlans(prisma, "2025-02-05T00:00:00Z"); const match = results.find((r) => r.planId === plan.id); expect(match?.cyclesAdvanced).toBe(2); expect(match?.carryForwardCents).toBe(2000); const updated = await prisma.fixedPlan.findUniqueOrThrow({ where: { id: plan.id } }); expect(updated.fundedCents).toBe(2000n); }); }); afterAll(async () => { await closePrisma(); });