mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-07 04:12:04 +00:00
test(insights): pin the clock in the two-service workout collapse case
The case built its sessions from the real clock: one copy a day before now, the other 30 s later. The cross-source workout picker groups sessions into fixed five-minute slots of the epoch, so whenever the suite ran in the last 30 s of a slot the two copies landed in different slots and counted twice. It had nothing to do with day boundaries or time zones: the outcome followed the minute of the wall clock alone. The case now pins Date to an instant well inside a slot. With the pin at 12:04:45Z or 23:59:45Z the case failed under UTC, Europe/Berlin and Pacific/Kiritimati alike; at the committed 12:02:00Z it passes under all three. The production code reads no clock here (the block takes `now` from its caller). What the flake exposed is the fixed slot grid itself: two copies of one session that straddle a slot edge are not collapsed. That is a change to the picker every workout surface shares, so it is left for a change of its own.
This commit is contained in:
1 parent
9bdd0b1a60
commit
1915f91526
1 file changed
+16
-4
@@ -559,6 +559,14 @@ describe("extractFeatures — v1.22 workouts block", () => {
|
||||
});
|
||||
|
||||
it("counts a session synced by two services once", async () => {
|
||||
// The cross-source picker groups sessions into fixed five-minute slots
|
||||
// of the epoch (`pick-canonical-workout-rows.ts`). With a start taken
|
||||
// from the real clock, the 30 s gap between the two copies crossed a
|
||||
// slot edge whenever the test ran in the last 30 s of a slot, and the
|
||||
// pair counted twice. The clock is pinned to an instant well inside a
|
||||
// slot, so the case tests the collapse rather than the time of day.
|
||||
vi.useFakeTimers({ toFake: ["Date"] });
|
||||
vi.setSystemTime(Date.parse("2026-10-22T12:02:00Z"));
|
||||
const startedAt = new Date(Date.now() - 1 * DAY_MS);
|
||||
prismaMock.workout.findMany.mockResolvedValue([
|
||||
{
|
||||
@@ -576,10 +584,14 @@ describe("extractFeatures — v1.22 workouts block", () => {
|
||||
totalDistanceM: 5010,
|
||||
},
|
||||
]);
|
||||
const f = await extractFeatures("user-1", false);
|
||||
expect(f.workouts?.last7.count).toBe(1);
|
||||
expect(f.workouts?.last7.totalDurationMin).toBe(30);
|
||||
expect(f.workouts?.last7.totalDistanceKm).toBe(5);
|
||||
try {
|
||||
const f = await extractFeatures("user-1", false);
|
||||
expect(f.workouts?.last7.count).toBe(1);
|
||||
expect(f.workouts?.last7.totalDurationMin).toBe(30);
|
||||
expect(f.workouts?.last7.totalDistanceKm).toBe(5);
|
||||
} finally {
|
||||
vi.useRealTimers();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in new issue
Block a user