From 401511d4aa36422a0e372399966514867578d725 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Thu, 4 Jun 2026 02:23:23 +0200 Subject: [PATCH] test(whoop): cover WHOOP workout cross-source resolution in the read-time picker Prove a WHOOP run and the same Apple-Health run inside the 5-minute clustering window collapse to the APPLE_HEALTH canonical row (richer GPS + HR record), and a lone WHOOP run survives when no richer source logged the session. The measurement-side WHOOP/Apple/Withings oracle already lives in source-priority-whoop-applehealth.test.ts; this closes the workout axis. --- .../pick-canonical-workout-rows.test.ts | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/lib/measurements/__tests__/pick-canonical-workout-rows.test.ts b/src/lib/measurements/__tests__/pick-canonical-workout-rows.test.ts index aed1ac1b9..18fd09e6b 100644 --- a/src/lib/measurements/__tests__/pick-canonical-workout-rows.test.ts +++ b/src/lib/measurements/__tests__/pick-canonical-workout-rows.test.ts @@ -6,7 +6,7 @@ interface RowFixture { id: string; startedAt: Date; sportType: string; - source: "APPLE_HEALTH" | "WITHINGS" | "MANUAL" | "IMPORT"; + source: "APPLE_HEALTH" | "WHOOP" | "WITHINGS" | "MANUAL" | "IMPORT"; } describe("pickCanonicalWorkoutRows", () => { @@ -44,6 +44,41 @@ describe("pickCanonicalWorkoutRows", () => { expect(pickCanonicalWorkoutRows(rows).map((r) => r.id)).toEqual(["apple"]); }); + it("collapses a WHOOP run and the same Apple-Health run to APPLE_HEALTH", () => { + // The E-slice oracle for workouts (v1.11.0): a WHOOP strap and an Apple + // Watch both log the same run within the 5-min clustering window. Apple + // Watch GPS + HR is the richer record, so it leads the default workout + // ladder; WHOOP ranks second. WHOOP's `start` typically differs from the + // HealthKit `startDate` by seconds — well inside the window. + const rows: RowFixture[] = [ + { + id: "whoop", + startedAt: new Date("2026-06-03T06:30:00Z"), + sportType: "running", + source: "WHOOP", + }, + { + id: "apple", + startedAt: new Date("2026-06-03T06:30:40Z"), // 40 s apart — same slot + sportType: "running", + source: "APPLE_HEALTH", + }, + ]; + expect(pickCanonicalWorkoutRows(rows).map((r) => r.id)).toEqual(["apple"]); + }); + + it("keeps the WHOOP run when no richer source logged the same session", () => { + const rows: RowFixture[] = [ + { + id: "whoop", + startedAt: new Date("2026-06-03T06:30:00Z"), + sportType: "running", + source: "WHOOP", + }, + ]; + expect(pickCanonicalWorkoutRows(rows).map((r) => r.id)).toEqual(["whoop"]); + }); + it("does NOT collapse two distinct runs whose starts are > 5 min apart", () => { const rows: RowFixture[] = [ {