import { describe, it, expect } from 'vitest'; import { barProgress, statusIndexFor, elapsedTenths, BAR_CEILING, STATUS_SCHEDULE_SECONDS, STATUS_COUNT, } from './processingProgress'; const s = (seconds: number) => seconds * 1000; describe('barProgress', () => { it('starts at zero', () => { expect(barProgress(0)).toBe(0); }); it('increases strictly for every second up to 60s', () => { for (let t = 1; t <= 60; t++) { expect(barProgress(s(t))).toBeGreaterThan(barProgress(s(t - 1))); } }); // Regression test for the competitor defect: their bar pegs at 100% and // freezes when generation outruns the animation. Ours must always have // somewhere left to go, across every duration that can realistically // occur, the worst generation ever measured is 48s. it('never reaches the ceiling across any realistic duration', () => { for (const t of [10, 35, 48, 120, 300, 514]) { expect(barProgress(s(t))).toBeLessThan(BAR_CEILING); } }); // Documents a known float64 limit rather than hiding it: past ~514s the // exponential underflows and the fill lands exactly on the ceiling. That // is an order of magnitude beyond any observed generation, and even there // the bar reads 92%, it never presents as complete, which is the // property that actually matters to the shopper. it('saturates at the ceiling only far beyond any real generation', () => { expect(barProgress(s(514))).toBeLessThan(BAR_CEILING); expect(barProgress(s(600))).toBe(BAR_CEILING); }); it('is roughly half full at the measured p50 of 11s', () => { expect(barProgress(s(11))).toBeCloseTo(0.5, 2); }); it('is still visibly climbing at the measured p90 of 35s', () => { expect(barProgress(s(35))).toBeCloseTo(0.844, 2); }); it('is still climbing at the worst observed duration of 48s', () => { expect(barProgress(s(48))).toBeCloseTo(0.89, 2); }); it('clamps a negative elapsed to zero', () => { expect(barProgress(-5000)).toBe(0); }); }); describe('statusIndexFor', () => { it('starts on the first string', () => { expect(statusIndexFor(0)).toBe(0); }); it('clamps a negative elapsed to the first string', () => { expect(statusIndexFor(-5000)).toBe(0); }); it('advances exactly on each scheduled boundary', () => { STATUS_SCHEDULE_SECONDS.forEach((boundary, index) => { expect(statusIndexFor(s(boundary))).toBe(index); if (boundary > 0) { expect(statusIndexFor(s(boundary) - 1)).toBe(index - 1); } }); }); // Regression test: a repeating carousel is what exposes the pacing as // theatre. The final string must hold indefinitely instead of wrapping. it('never loops and never exceeds the last string, out to 300s', () => { let previous = 0; for (let t = 0; t <= 300; t++) { const index = statusIndexFor(s(t)); expect(index).toBeGreaterThanOrEqual(previous); expect(index).toBeLessThanOrEqual(STATUS_COUNT - 1); previous = index; } expect(statusIndexFor(s(300))).toBe(STATUS_COUNT - 1); }); }); describe('elapsedTenths', () => { it('truncates to one decimal place', () => { expect(elapsedTenths(12449)).toBe(12.4); expect(elapsedTenths(0)).toBe(0); }); it('clamps a negative elapsed to zero', () => { expect(elapsedTenths(-100)).toBe(0); }); });