Files
HealthLog/tests/integration/local-day-keys.test.ts
T
Marc-André Bombeck 41de0ca126 refactor(medications): drop the compliance rollup table that nothing reads
medication_compliance_rollups lost its last reader when compliance moved
to the schedule-anchored computation, yet every dose write still upserted
it, a boot backfill refolded it, and the wipe and backup plans carried it.

The per-dose hook keeps the one derived row that still hangs off a dose
day, the supplement nutrients, under dose-day-refresh. The pending-row
mints (today projection, reminder) no longer call it, since an untaken
dose adds no nutrients. The import job finishes without its per-day
recompute phase; its progress keeps touchedDays and rollupProcessed on
the wire, inert and documented as deprecated. The backfill queue is
retired on boot and migration 0414 drops the table under a bounded lock
wait.
2026-10-20 13:01:45 +02:00

96 lines
2.8 KiB
TypeScript

/**
* Local day keys from naive UTC timestamps, against a real Postgres.
*
* `measured_at` and `scheduled_for` hold UTC wall-clock time in `timestamp`
* columns. The dashboard streak and the medication-compliance backfill keyed
* them with a single `AT TIME ZONE tz`, which reads the value as local time
* and shifts it the wrong way. Both now agree with `userDayKey`: a reading at
* 23:30 UTC is the next day in Berlin and still the same day in Los Angeles,
* a reading at 03:00 UTC is the previous day in Los Angeles.
*/
import { beforeEach, describe, expect, it, vi } from "vitest";
import { getPrismaClient, truncateAllTables } from "./setup";
import { readActivityDayKeys } from "@/lib/dashboard/summary-reads";
import { userDayKey } from "@/lib/tz/format";
vi.mock("@/lib/db-compat", () => ({
ensureDbCompatibility: vi.fn().mockResolvedValue(undefined),
}));
const prisma = getPrismaClient();
const USER = "local-day-keys";
const now = new Date();
/** UTC midnight ten days back. */
const D = Date.UTC(
now.getUTCFullYear(),
now.getUTCMonth(),
now.getUTCDate() - 10,
);
const LATE = new Date(D + 23.5 * 3_600_000); // 23:30 UTC on D
const EARLY = new Date(D + 3 * 3_600_000); // 03:00 UTC on D
const key = (ms: number) => new Date(ms).toISOString().slice(0, 10);
beforeEach(async () => {
await truncateAllTables(prisma);
await prisma.user.create({
data: {
id: USER,
username: USER,
email: `${USER}@example.test`,
timezone: "Europe/Berlin",
},
});
});
describe("readActivityDayKeys", () => {
beforeEach(async () => {
await prisma.measurement.createMany({
data: [
{ at: LATE, deleted: false },
{ at: EARLY, deleted: false },
{ at: new Date(D - 3 * 86_400_000), deleted: true },
].map(({ at, deleted }, i) => ({
id: `${USER}-m${i}`,
userId: USER,
type: "WEIGHT" as const,
source: "MANUAL" as const,
value: 80,
unit: "kg",
measuredAt: at,
deletedAt: deleted ? new Date() : null,
})),
});
});
const since = new Date(D - 5 * 86_400_000);
it("keys a late reading onto the next day east of UTC", async () => {
const keys = await readActivityDayKeys(
prisma,
USER,
"Europe/Berlin",
since,
now,
);
expect(keys).toEqual([key(D), key(D + 86_400_000)]);
expect(keys).toEqual(
[EARLY, LATE].map((at) => userDayKey(at, "Europe/Berlin")),
);
});
it("keys an early reading onto the previous day west of UTC", async () => {
const keys = await readActivityDayKeys(
prisma,
USER,
"America/Los_Angeles",
since,
now,
);
expect(keys).toEqual([key(D - 86_400_000), key(D)]);
expect(keys).toEqual(
[EARLY, LATE].map((at) => userDayKey(at, "America/Los_Angeles")),
);
});
});