const { computeDonationRemaining } = require('../src/utils/donationUtils'); describe('computeDonationRemaining', () => { test('a donation with no legs has its full amount remaining', () => { expect(computeDonationRemaining(500, [])).toBe(500); }); test('an allocation leg reduces the remaining balance', () => { const legs = [{ amount: 200 }]; expect(computeDonationRemaining(500, legs)).toBe(300); }); test('multiple allocation legs reduce the remaining balance cumulatively', () => { const legs = [{ amount: 200 }, { amount: 150 }]; expect(computeDonationRemaining(500, legs)).toBe(150); }); test('the 1.4.2 regression: refunding the donation itself (a negative-amount leg) reduces remaining balance, not inflates it', () => { // 500 donation, never allocated, R200 of it refunded directly back to the donor // (a leg with amount: -200). That R200 is no longer available to allocate — remaining // must drop to 300. The pre-1.4.2 bug summed legs without Math.abs(), so // remaining = 500 - (-200) = 700 (inflated) instead of 500 - 200 = 300 (correct). const legs = [{ amount: -200 }]; expect(computeDonationRemaining(500, legs)).toBe(300); }); test('an allocation and a separate direct refund both reduce the remaining balance', () => { // 500 donation: R200 allocated to a registration, R100 separately refunded to the donor. // Remaining = 500 - 200 - 100 = 200. const legs = [{ amount: 200 }, { amount: -100 }]; expect(computeDonationRemaining(500, legs)).toBe(200); }); test('unassigning an allocation removes its leg entirely rather than adding an offsetting one', () => { // unassignDonationFromRegistration deletes the leg row outright (confirmed in // paymentController.js), so the "leg no longer exists" case — not a negative-amount // leg — is how an unassigned allocation becomes available again. const legsAfterUnassign = []; expect(computeDonationRemaining(500, legsAfterUnassign)).toBe(500); }); test('handles a null/undefined legs array', () => { expect(computeDonationRemaining(500, null)).toBe(500); expect(computeDonationRemaining(500, undefined)).toBe(500); }); });