import { describe, it, expect } from 'vitest'; import { agingBucket, AGING_BUCKETS, monthKey, monthRange, netContribution, } from '@/lib/services/reports/financial-math'; describe('agingBucket', () => { it('buckets day counts into the 4 age bands', () => { expect(agingBucket(0)).toBe('0-30'); expect(agingBucket(30)).toBe('0-30'); expect(agingBucket(31)).toBe('31-60'); expect(agingBucket(60)).toBe('31-60'); expect(agingBucket(61)).toBe('61-90'); expect(agingBucket(90)).toBe('61-90'); expect(agingBucket(91)).toBe('90+'); expect(agingBucket(400)).toBe('90+'); }); it('exposes the buckets in ascending order for stable chart rows', () => { expect(AGING_BUCKETS).toEqual(['0-30', '31-60', '61-90', '90+']); }); }); describe('monthKey', () => { it('formats a date as zero-padded YYYY-MM (UTC)', () => { expect(monthKey(new Date('2026-01-09T00:00:00Z'))).toBe('2026-01'); expect(monthKey(new Date('2026-12-31T23:59:59Z'))).toBe('2026-12'); }); }); describe('monthRange', () => { it('produces a continuous ascending month series, inclusive of both ends', () => { const series = monthRange(new Date('2025-11-15T00:00:00Z'), new Date('2026-02-02T00:00:00Z')); expect(series).toEqual(['2025-11', '2025-12', '2026-01', '2026-02']); }); it('returns a single month when from and to share a month', () => { expect(monthRange(new Date('2026-03-01T00:00:00Z'), new Date('2026-03-28T00:00:00Z'))).toEqual([ '2026-03', ]); }); }); describe('netContribution', () => { it('is revenue minus expenses', () => { expect(netContribution(1000, 250)).toBe(750); expect(netContribution(100, 400)).toBe(-300); }); });