From 16cdbf3d7c69d8d99b62e5f37a4ec4295268ead5 Mon Sep 17 00:00:00 2001 From: Lucas Berger Date: Wed, 10 Jun 2026 10:48:09 -0400 Subject: [PATCH] test(06-01): add failing tests for end-tracking duration math - computeNewTimedEnd: 1h delta, 26h multi-day delta, floor-to-1h rule - computeNewAllDayEnd: 0-day span, 3-day span, floor-to-same-day rule - RED: all 6 new cases fail with missing-export TypeError --- apps/pwa/src/lib/eventDateTime.test.ts | 63 +++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/apps/pwa/src/lib/eventDateTime.test.ts b/apps/pwa/src/lib/eventDateTime.test.ts index 32cb997..ae4cf4f 100644 --- a/apps/pwa/src/lib/eventDateTime.test.ts +++ b/apps/pwa/src/lib/eventDateTime.test.ts @@ -13,7 +13,7 @@ */ import { describe, it, expect } from 'vitest' -import { serializeEventDateTime, localWallClockToUtcIso } from './eventDateTime.js' +import { serializeEventDateTime, localWallClockToUtcIso, computeNewTimedEnd, computeNewAllDayEnd } from './eventDateTime.js' describe('serializeEventDateTime (BUG A — write-path TZ)', () => { it('serializes a timed start to a UTC instant (ends in Z)', () => { @@ -51,3 +51,64 @@ describe('serializeEventDateTime (BUG A — write-path TZ)', () => { expect(new Date(iso).getHours()).toBe(9) }) }) + +describe('computeNewTimedEnd (D-04 — end-tracking)', () => { + it('preserves a 1-hour timed delta when start moves forward', () => { + // Old: 2026-06-11 09:00 → 10:00 (1h duration) + // New start: 2026-06-11 11:00 → new end should be 12:00 + const result = computeNewTimedEnd( + '2026-06-11', '11:00', + '2026-06-11', '09:00', + '2026-06-11', '10:00', + ) + expect(result.endDate).toBe('2026-06-11') + expect(result.endTime).toBe('12:00') + }) + + it('preserves a multi-day timed delta (26h) when start moves', () => { + // Old: 2026-06-11 08:00 → 2026-06-12 10:00 (26h duration) + // New start: 2026-06-13 08:00 → new end should be 2026-06-14 10:00 + const result = computeNewTimedEnd( + '2026-06-13', '08:00', + '2026-06-11', '08:00', + '2026-06-12', '10:00', + ) + expect(result.endDate).toBe('2026-06-14') + expect(result.endTime).toBe('10:00') + }) + + it('floors to 1h when old end was already behind old start', () => { + // Old end (10:00) <= old start (11:00) — stale/invalid state + // New start: 2026-06-11 14:00 → new end should snap to +1h = 15:00 + const result = computeNewTimedEnd( + '2026-06-11', '14:00', + '2026-06-11', '11:00', + '2026-06-11', '10:00', + ) + expect(result.endDate).toBe('2026-06-11') + expect(result.endTime).toBe('15:00') + }) +}) + +describe('computeNewAllDayEnd (D-04 — all-day end-tracking)', () => { + it('preserves a 0-day span (single-day all-day event)', () => { + // Old: 2026-06-11 → 2026-06-11 (0-day span, single day) + // New start: 2026-06-15 → new end should be 2026-06-15 + const result = computeNewAllDayEnd('2026-06-15', '2026-06-11', '2026-06-11') + expect(result).toBe('2026-06-15') + }) + + it('preserves a 3-day span when start moves', () => { + // Old: 2026-06-11 → 2026-06-14 (3-day span) + // New start: 2026-06-20 → new end should be 2026-06-23 + const result = computeNewAllDayEnd('2026-06-20', '2026-06-11', '2026-06-14') + expect(result).toBe('2026-06-23') + }) + + it('floors to same day when old end was already behind old start', () => { + // Old end (2026-06-10) < old start (2026-06-11) — stale/invalid state + // New start: 2026-06-15 → new end should snap to same day 2026-06-15 + const result = computeNewAllDayEnd('2026-06-15', '2026-06-11', '2026-06-10') + expect(result).toBe('2026-06-15') + }) +})