From 550f314a54f1c3a5f876724917767b3cfc577ccc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Fri, 12 Jun 2026 22:56:03 +0200 Subject: [PATCH] test(measurements,whoop): the workout fall-through test reaches its path again Ladder reconciliation ranks every enum source, so the unranked fall-through needs out-of-enum fixtures now; a stored single-source ladder resolving one canonical row is pinned as the new contract. The body-sync test sheds the import its retired weight path used. --- .../pick-canonical-workout-rows.test.ts | 46 ++++++++++++++----- src/lib/whoop/__tests__/sync-body.test.ts | 1 - 2 files changed, 34 insertions(+), 13 deletions(-) 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 18fd09e6b..680acbdb9 100644 --- a/src/lib/measurements/__tests__/pick-canonical-workout-rows.test.ts +++ b/src/lib/measurements/__tests__/pick-canonical-workout-rows.test.ts @@ -185,8 +185,36 @@ describe("pickCanonicalWorkoutRows", () => { it("falls through to keeping every row when sources aren't on the ladder at all", () => { // Theoretical safety net — no real source emits a value outside // the canonical enum, but the picker MUST NEVER drop signal it - // can't classify. Forcing a ladder of a single source the bucket - // doesn't carry exercises the fallback path. + // can't classify. Since v1.16.11 the resolver reconciles every + // stored ladder against the defaults, so ANY enum source is always + // ranked — the only unrankable rows carry a source outside the + // enum entirely (a future source reaching an old reader). + const rows = [ + { + id: "a", + startedAt: new Date("2026-05-16T08:00:00Z"), + sportType: "running", + source: "SOMETHING_NEW" as never, + }, + { + id: "b", + startedAt: new Date("2026-05-16T08:01:00Z"), + sportType: "running", + source: "SOMETHING_ELSE" as never, + }, + ] as RowFixture[]; + expect( + pickCanonicalWorkoutRows(rows, null) + .map((r) => r.id) + .sort(), + ).toEqual(["a", "b"]); + }); + + it("a stored single-source ladder still resolves a canonical row (reconciled defaults rank the rest)", () => { + // The pre-v1.16.11 contract for this input was "nothing ranked → + // keep both"; reconciliation now appends the default ladder after + // the stored entry, so the bucket resolves one canonical row like + // every ranked pick. const rows: RowFixture[] = [ { id: "a", @@ -201,15 +229,9 @@ describe("pickCanonicalWorkoutRows", () => { source: "WITHINGS", }, ]; - const oddPriority = { - metricPriority: { - steps: ["IMPORT"], - }, - }; - expect( - pickCanonicalWorkoutRows(rows, oddPriority) - .map((r) => r.id) - .sort(), - ).toEqual(["a", "b"]); + const picked = pickCanonicalWorkoutRows(rows, { + metricPriority: { steps: ["IMPORT"] }, + }).map((r) => r.id); + expect(picked).toHaveLength(1); }); }); diff --git a/src/lib/whoop/__tests__/sync-body.test.ts b/src/lib/whoop/__tests__/sync-body.test.ts index 4613b0cd4..45f5d3144 100644 --- a/src/lib/whoop/__tests__/sync-body.test.ts +++ b/src/lib/whoop/__tests__/sync-body.test.ts @@ -8,7 +8,6 @@ */ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { WhoopApiError } from "../response-classifier"; -import type { WhoopMeasurementUpsert } from "../sync"; // ── Module mocks ──────────────────────────────────────────────── const {