codeburn/tests/budget.test.ts
ozymandiashh 057de97360
feat(budget): spend budgets with overview display and scriptable --check (#562)
Ported onto current main after the locale-grouping change in overview.ts;
review follow-ups included:
- explicit note: budgets count the full would-be API cost including
  subscription-proxied spend, consistent with the overview Cost total
- percent display floors the raw value on both surfaces, so 99.6 percent
  renders as 99 percent in warn state and 100 percent appears only when the
  state is over; regression tests cover the boundary on overview and --check
- overview keeps main's en-US locale-grouped formatting and the
  unpriced-model warning block; the budget line renders after it
2026-07-16 11:10:16 -07:00

27 lines
1.5 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import { computeBudgetStatus } from '../src/budget.js'
describe('computeBudgetStatus', () => {
it('classifies under, warn, and over at the threshold boundaries', () => {
expect(computeBudgetStatus({ spent: 79.99, budget: 100, elapsedDays: 1, totalDays: 1 }).state).toBe('under')
expect(computeBudgetStatus({ spent: 80, budget: 100, elapsedDays: 1, totalDays: 1 }).state).toBe('warn')
expect(computeBudgetStatus({ spent: 99.99, budget: 100, elapsedDays: 1, totalDays: 1 }).state).toBe('warn')
expect(computeBudgetStatus({ spent: 100, budget: 100, elapsedDays: 1, totalDays: 1 }).state).toBe('over')
})
it('computes percent and linear projection from elapsed and total days', () => {
const status = computeBudgetStatus({ spent: 30, budget: 120, elapsedDays: 10, totalDays: 30 })
expect(status.pct).toBe(25)
expect(status.projected).toBe(90)
})
it('rejects invalid numeric inputs', () => {
expect(() => computeBudgetStatus({ spent: -1, budget: 100, elapsedDays: 1, totalDays: 1 })).toThrow(/spent/)
expect(() => computeBudgetStatus({ spent: 1, budget: 0, elapsedDays: 1, totalDays: 1 })).toThrow(/budget/)
expect(() => computeBudgetStatus({ spent: 1, budget: 100, elapsedDays: 0, totalDays: 1 })).toThrow(/elapsedDays/)
expect(() => computeBudgetStatus({ spent: 1, budget: 100, elapsedDays: 1, totalDays: -1 })).toThrow(/totalDays/)
expect(() => computeBudgetStatus({ spent: Number.POSITIVE_INFINITY, budget: 100, elapsedDays: 1, totalDays: 1 })).toThrow(/spent/)
})
})