From d75d47b4fa8e5a80cabdf1d10a8bcd7d2b8bf11e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Thu, 14 May 2026 19:12:19 +0200 Subject: [PATCH] fix(test): spread batch-delete fixture rows across distinct measuredAt The W17b/c sleep-stage migration widened the measurement unique index to (user_id, type, measured_at, source, sleep_stage) with NULLs treated as not-distinct, so three same-instant APPLE_HEALTH weight rows now collide on insert. Derive a stable per-externalId minute offset and stagger the seeded `measuredAt` accordingly so the deletion-by-externalId contract is exercised without piggy- backing on dedup behaviour the route doesn't care about. --- .../measurements-batch-delete.test.ts | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/tests/integration/measurements-batch-delete.test.ts b/tests/integration/measurements-batch-delete.test.ts index 205135471..31190cd77 100644 --- a/tests/integration/measurements-batch-delete.test.ts +++ b/tests/integration/measurements-batch-delete.test.ts @@ -78,11 +78,28 @@ function makeRequest(body: { externalIds: string[] }): NextRequest { }); } +// Hash an externalId into a stable minute offset (0..1023) so two +// rows seeded with different externalIds land on different +// `measuredAt` values. The W17b/c unique index now covers +// (user_id, type, measured_at, source, sleep_stage) with NULLs not +// distinct, so all-same-instant fixtures collide; spreading by +// minute keeps the fixture deterministic without sacrificing the +// "owned by the caller" intent of the test. +function minuteOffsetFor(externalId: string): number { + let h = 0; + for (let i = 0; i < externalId.length; i++) { + h = (h * 31 + externalId.charCodeAt(i)) | 0; + } + return Math.abs(h) % 1024; +} + async function seedMeasurement(opts: { userId: string; externalId: string; value?: number; }): Promise { + const base = new Date("2026-05-09T07:30:00.000Z").getTime(); + const measuredAt = new Date(base + minuteOffsetFor(opts.externalId) * 60_000); await getPrismaClient().measurement.create({ data: { userId: opts.userId, @@ -90,7 +107,7 @@ async function seedMeasurement(opts: { value: opts.value ?? 80, unit: "kg", source: "APPLE_HEALTH", - measuredAt: new Date("2026-05-09T07:30:00.000Z"), + measuredAt, externalId: opts.externalId, }, });