228 lines · 7.9 KB · TypeScript
RawDownload
/** * Tests for cost formatting utilities */ import { describe, it, expect } from 'vitest';import { formatCostUsd, formatCostCompact } from '@shared/utils/costFormatting'; describe('Cost Formatting', () => {  describe('formatCostUsd', () => {    describe('Zero values', () => {      it('should format zero as $0.00', () => {        expect(formatCostUsd(0)).toBe('$0.00');      });       it('should format negative zero as $0.00', () => {        expect(formatCostUsd(-0)).toBe('$0.00');      });    });     describe('Standard amounts (>= $0.01)', () => {      it('should format 1 cent with 2 decimal places', () => {        expect(formatCostUsd(0.01)).toBe('$0.01');      });       it('should format 1 dollar with 2 decimal places', () => {        expect(formatCostUsd(1.0)).toBe('$1.00');      });       it('should format dollars and cents', () => {        expect(formatCostUsd(1.23)).toBe('$1.23');      });       it('should format large amounts', () => {        expect(formatCostUsd(999.99)).toBe('$999.99');        expect(formatCostUsd(1234.56)).toBe('$1234.56');      });       it('should round to 2 decimal places for amounts >= 1 cent', () => {        expect(formatCostUsd(1.234)).toBe('$1.23');        expect(formatCostUsd(1.235)).toBe('$1.24'); // Rounds up        expect(formatCostUsd(1.999)).toBe('$2.00');      });    });     describe('Sub-cent amounts ($0.001 - $0.01)', () => {      it('should format 1 tenth of a cent with 3 decimal places', () => {        expect(formatCostUsd(0.001)).toBe('$0.001');      });       it('should format sub-cent amounts with 3 decimal places', () => {        expect(formatCostUsd(0.005)).toBe('$0.005');        expect(formatCostUsd(0.009)).toBe('$0.009');      });       it('should round to 3 decimal places for sub-cent amounts', () => {        expect(formatCostUsd(0.0012)).toBe('$0.001');        expect(formatCostUsd(0.0015)).toBe('$0.002'); // Rounds up        expect(formatCostUsd(0.0099)).toBe('$0.010');      });    });     describe('Very small amounts (< $0.001)', () => {      it('should format tiny amounts with 4 decimal places', () => {        expect(formatCostUsd(0.0001)).toBe('$0.0001');        expect(formatCostUsd(0.0005)).toBe('$0.0005');        expect(formatCostUsd(0.0009)).toBe('$0.0009');      });       it('should round to 4 decimal places for tiny amounts', () => {        expect(formatCostUsd(0.00012)).toBe('$0.0001');        expect(formatCostUsd(0.00016)).toBe('$0.0002'); // Rounds up        expect(formatCostUsd(0.00099)).toBe('$0.0010');      });       it('should handle very tiny amounts', () => {        expect(formatCostUsd(0.000001)).toBe('$0.0000');      });    });     describe('Edge cases', () => {      it('should handle negative amounts with 4 decimal places', () => {        // Negative numbers don't match >= comparisons, so they use 4 decimals        expect(formatCostUsd(-1.23)).toBe('$-1.2300');        expect(formatCostUsd(-0.001)).toBe('$-0.0010');        expect(formatCostUsd(-0.0001)).toBe('$-0.0001');      });       it('should handle very large amounts', () => {        expect(formatCostUsd(1000000)).toBe('$1000000.00');      });       it('should handle precision boundaries', () => {        // Boundary between 2 and 3 decimal places        expect(formatCostUsd(0.01)).toBe('$0.01');        expect(formatCostUsd(0.00999)).toBe('$0.010'); // Just below threshold, uses 3 decimals         // Boundary between 3 and 4 decimal places        expect(formatCostUsd(0.001)).toBe('$0.001');        expect(formatCostUsd(0.00099)).toBe('$0.0010'); // Just below threshold, uses 4 decimals      });    });     describe('Real-world API cost examples', () => {      it('should format typical Claude API costs', () => {        // 1M input tokens at $3.00/M        expect(formatCostUsd(3.0)).toBe('$3.00');         // 100k input tokens at $3.00/M        expect(formatCostUsd(0.3)).toBe('$0.30');         // 10k cache read tokens at $0.30/M        expect(formatCostUsd(0.003)).toBe('$0.003');         // 1k cache read tokens at $0.30/M        expect(formatCostUsd(0.0003)).toBe('$0.0003');      });       it('should format session totals', () => {        // Small session        expect(formatCostUsd(0.15)).toBe('$0.15');         // Medium session        expect(formatCostUsd(5.67)).toBe('$5.67');         // Large session        expect(formatCostUsd(29.57)).toBe('$29.57');      });    });  });   describe('formatCostCompact', () => {    describe('Zero values', () => {      it('should format zero as 0.00', () => {        expect(formatCostCompact(0)).toBe('0.00');      });       it('should format negative zero as 0.00', () => {        expect(formatCostCompact(-0)).toBe('0.00');      });    });     describe('Standard amounts (>= $0.01)', () => {      it('should format amounts without $ prefix', () => {        expect(formatCostCompact(0.01)).toBe('0.01');        expect(formatCostCompact(1.0)).toBe('1.00');        expect(formatCostCompact(1.23)).toBe('1.23');      });       it('should format large amounts', () => {        expect(formatCostCompact(999.99)).toBe('999.99');        expect(formatCostCompact(1234.56)).toBe('1234.56');      });       it('should round to 2 decimal places', () => {        expect(formatCostCompact(1.234)).toBe('1.23');        expect(formatCostCompact(1.235)).toBe('1.24'); // Rounds up        expect(formatCostCompact(1.999)).toBe('2.00');      });    });     describe('Sub-cent amounts ($0.001 - $0.01)', () => {      it('should format sub-cent amounts with 3 decimal places', () => {        expect(formatCostCompact(0.001)).toBe('0.001');        expect(formatCostCompact(0.005)).toBe('0.005');        expect(formatCostCompact(0.009)).toBe('0.009');      });       it('should round to 3 decimal places', () => {        expect(formatCostCompact(0.0012)).toBe('0.001');        expect(formatCostCompact(0.0015)).toBe('0.002'); // Rounds up        expect(formatCostCompact(0.0099)).toBe('0.010');      });    });     describe('Very small amounts (< $0.001)', () => {      it('should format tiny amounts with 4 decimal places', () => {        expect(formatCostCompact(0.0001)).toBe('0.0001');        expect(formatCostCompact(0.0005)).toBe('0.0005');        expect(formatCostCompact(0.0009)).toBe('0.0009');      });       it('should round to 4 decimal places', () => {        expect(formatCostCompact(0.00012)).toBe('0.0001');        expect(formatCostCompact(0.00016)).toBe('0.0002'); // Rounds up        expect(formatCostCompact(0.00099)).toBe('0.0010');      });    });     describe('Edge cases', () => {      it('should handle negative amounts with 4 decimal places', () => {        // Negative numbers don't match >= comparisons, so they use 4 decimals        expect(formatCostCompact(-1.23)).toBe('-1.2300');        expect(formatCostCompact(-0.001)).toBe('-0.0010');        expect(formatCostCompact(-0.0001)).toBe('-0.0001');      });       it('should handle very large amounts', () => {        expect(formatCostCompact(1000000)).toBe('1000000.00');      });    });     describe('Comparison with formatCostUsd', () => {      it('should match formatCostUsd except for $ prefix', () => {        const testCases = [0, 0.0001, 0.001, 0.01, 1.23, 999.99];         testCases.forEach((cost) => {          const withPrefix = formatCostUsd(cost);          const compact = formatCostCompact(cost);           // Compact should equal the USD format without the $          expect(compact).toBe(withPrefix.substring(1));        });      });    });     describe('Badge display use cases', () => {      it('should format for badge display', () => {        // Small per-message costs        expect(formatCostCompact(0.0015)).toBe('0.002');        expect(formatCostCompact(0.01)).toBe('0.01');         // Session totals in badges        expect(formatCostCompact(2.5)).toBe('2.50');        expect(formatCostCompact(15.0)).toBe('15.00');      });    });  });});