From 0bab369a6bc6a64bfd8fedd577e69eb27bfb1178 Mon Sep 17 00:00:00 2001 From: Martin Kagamino Lehoux Date: Mon, 5 Oct 2026 07:37:35 +0200 Subject: Show time since done or lateness instead of the last-done date --- src/lib/shared/routine-metrics.test.ts | 64 ++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) (limited to 'src/lib/shared/routine-metrics.test.ts') diff --git a/src/lib/shared/routine-metrics.test.ts b/src/lib/shared/routine-metrics.test.ts index 88d0498..7f4d656 100644 --- a/src/lib/shared/routine-metrics.test.ts +++ b/src/lib/shared/routine-metrics.test.ts @@ -4,6 +4,7 @@ import { computeHealthScore, computeHealthSeries, computeProjectHealthSeries, + formatDoneAge, type HealthPoint, } from './routine-metrics'; const CREATED = '2026-09-01T00:00:00.000Z'; @@ -240,6 +241,69 @@ describe('computeRoutineState (quota)', () => { }); }); +describe('daysSinceDone', () => { + it('is null when the routine was never done', () => { + const state = computeRoutineState(routine, [], plusDays(created, 3)); + expect(state.daysSinceDone).toBeNull(); + }); + + it('counts whole UTC calendar days since the last completion', () => { + const state = computeRoutineState( + routine, + [{ routineId: 1, doneAt: '2026-09-07T20:00:00.000Z' }], + Temporal.Instant.from('2026-09-10T08:00:00.000Z'), + ); + expect(state.daysSinceDone).toBe(3); // not 2: calendar days, not 24h chunks + }); + + it('is 0 for a completion earlier the same calendar day', () => { + const state = computeRoutineState( + routine, + [{ routineId: 1, doneAt: '2026-09-10T08:00:00.000Z' }], + Temporal.Instant.from('2026-09-10T20:00:00.000Z'), + ); + expect(state.daysSinceDone).toBe(0); + }); + + it('clamps a future-dated completion to 0', () => { + const state = computeRoutineState( + routine, + [{ routineId: 1, doneAt: '2026-09-12T08:00:00.000Z' }], + Temporal.Instant.from('2026-09-10T20:00:00.000Z'), + ); + expect(state.daysSinceDone).toBe(0); + }); +}); + +describe('formatDoneAge', () => { + it('shows the lateness once a day past due, even when never done', () => { + expect(formatDoneAge({ daysSinceDone: null, overdueDays: 3 })).toBe( + '3 jours de retard', + ); + expect(formatDoneAge({ daysSinceDone: 10, overdueDays: 1 })).toBe( + '1 jour de retard', + ); + expect(formatDoneAge({ daysSinceDone: 10, overdueDays: 3 })).toBe( + '3 jours de retard', + ); + }); + + it('shows the time since done while the deadline is still ahead', () => { + expect(formatDoneAge({ daysSinceDone: null, overdueDays: 0 })).toBe( + 'jamais fait', + ); + expect(formatDoneAge({ daysSinceDone: 0, overdueDays: 0 })).toBe( + "fait aujourd'hui", + ); + expect(formatDoneAge({ daysSinceDone: 1, overdueDays: 0 })).toBe( + 'fait hier', + ); + expect(formatDoneAge({ daysSinceDone: 5, overdueDays: 0 })).toBe( + 'fait il y a 5 jours', + ); + }); +}); + describe('computeHealthSeries', () => { it('decays from 100 at creation to 0 two periods overdue when never done', () => { const now = plusDays(created, 22); -- cgit v1.3