mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-12 06:06:10 +00:00
test(01-11): specify rolling weekly overdue identity
- pin the prior-day Mounjaro occurrence across local midnight and DST - cover resolution state, band end, schedule siblings, and era isolation
This commit is contained in:
1 parent
18d0facdfe
commit
d5f473d672
2 files changed
+179
No files matched your search
@@ -558,3 +558,144 @@ describe("as-needed (zero schedules) — never due", () => {
|
||||
expect(display).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("Mounjaro rolling weekly — canonical overdue band after day change", () => {
|
||||
const lastTaken = d("2026-07-21T06:00:00.000Z"); // Jul 21 08:00 Berlin
|
||||
const missedOccurrence = d("2026-07-28T06:00:00.000Z"); // Jul 28 08:00
|
||||
const nextOccurrence = d("2026-08-04T06:00:00.000Z"); // Aug 4 08:00
|
||||
const medication = makeMedication({
|
||||
startsOn: d("2026-01-01T00:00:00.000Z"),
|
||||
});
|
||||
const schedule = makeRollingSchedule({
|
||||
id: "mounjaro-weekly",
|
||||
timesOfDay: ["08:00"],
|
||||
});
|
||||
const identifiedMark = (
|
||||
at: Date,
|
||||
identity: Record<string, unknown>,
|
||||
): ResolvedSlotMark =>
|
||||
({
|
||||
...mark(at),
|
||||
...identity,
|
||||
}) as ResolvedSlotMark;
|
||||
|
||||
it("keeps yesterday's unresolved occurrence overdue on the following local day", () => {
|
||||
const display = computeDisplayDue({
|
||||
medication,
|
||||
schedules: [schedule],
|
||||
now: d("2026-07-29T10:00:00.000Z"),
|
||||
userTz: BERLIN,
|
||||
lastIntakeAt: lastTaken,
|
||||
resolvedSlots: [],
|
||||
});
|
||||
|
||||
expect(display).toMatchObject({
|
||||
at: missedOccurrence,
|
||||
overdue: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps the occurrence through the exact canonical band end, then closes it", () => {
|
||||
const atBandEnd = computeDisplayDue({
|
||||
medication,
|
||||
schedules: [schedule],
|
||||
now: d("2026-08-02T06:00:00.000Z"),
|
||||
userTz: BERLIN,
|
||||
lastIntakeAt: lastTaken,
|
||||
resolvedSlots: [],
|
||||
});
|
||||
expect(atBandEnd).toMatchObject({
|
||||
at: missedOccurrence,
|
||||
overdue: true,
|
||||
});
|
||||
|
||||
const afterBandEnd = computeDisplayDue({
|
||||
medication,
|
||||
schedules: [schedule],
|
||||
now: d("2026-08-02T06:00:00.001Z"),
|
||||
userTz: BERLIN,
|
||||
lastIntakeAt: lastTaken,
|
||||
resolvedSlots: [],
|
||||
});
|
||||
expect(afterBandEnd).toBeNull();
|
||||
});
|
||||
|
||||
it.each(["taken", "skipped", "autoMissed"] as const)(
|
||||
"an exact %s row suppresses only this occurrence and advances",
|
||||
(status) => {
|
||||
const display = computeDisplayDue({
|
||||
medication,
|
||||
schedules: [schedule],
|
||||
now: d("2026-07-29T10:00:00.000Z"),
|
||||
userTz: BERLIN,
|
||||
lastIntakeAt:
|
||||
status === "taken"
|
||||
? d("2026-07-28T06:10:00.000Z")
|
||||
: lastTaken,
|
||||
resolvedSlots: [
|
||||
identifiedMark(missedOccurrence, {
|
||||
scheduleId: "mounjaro-weekly",
|
||||
status,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
expect(display).toMatchObject({
|
||||
at: nextOccurrence,
|
||||
overdue: false,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
it("does not let a sibling schedule's resolved occurrence suppress this schedule", () => {
|
||||
const sibling = makeRollingSchedule({
|
||||
id: "mounjaro-sibling",
|
||||
timesOfDay: ["10:00"],
|
||||
windowStart: "10:00",
|
||||
windowEnd: "10:00",
|
||||
});
|
||||
const display = computeDisplayDue({
|
||||
medication,
|
||||
schedules: [schedule, sibling],
|
||||
now: d("2026-07-29T10:00:00.000Z"),
|
||||
userTz: BERLIN,
|
||||
lastIntakeAt: lastTaken,
|
||||
resolvedSlots: [
|
||||
identifiedMark(missedOccurrence, {
|
||||
scheduleId: "mounjaro-weekly",
|
||||
status: "skipped",
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
expect(display).toMatchObject({
|
||||
at: d("2026-07-28T08:00:00.000Z"),
|
||||
overdue: true,
|
||||
scheduleId: "mounjaro-sibling",
|
||||
});
|
||||
});
|
||||
|
||||
it("does not let an action from the archived era suppress the live-era occurrence", () => {
|
||||
const liveEraStart = d("2026-07-27T12:00:00.000Z");
|
||||
const display = computeDisplayDue({
|
||||
medication,
|
||||
schedules: [schedule],
|
||||
now: d("2026-07-29T10:00:00.000Z"),
|
||||
userTz: BERLIN,
|
||||
lastIntakeAt: lastTaken,
|
||||
eraStart: liveEraStart,
|
||||
resolvedSlots: [
|
||||
identifiedMark(missedOccurrence, {
|
||||
scheduleId: "mounjaro-weekly",
|
||||
actionAt: d("2026-07-27T11:59:59.000Z"),
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
expect(display).toMatchObject({
|
||||
at: missedOccurrence,
|
||||
overdue: true,
|
||||
scheduleId: "mounjaro-weekly",
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -473,6 +473,44 @@ describe("occurrencesBetween — rolling", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("rolling occurrence identity across a local-day change", () => {
|
||||
it.each([
|
||||
{
|
||||
label: "ordinary Berlin week",
|
||||
lastIntake: "2026-07-21T06:00:00.000Z",
|
||||
now: "2026-07-29T10:00:00.000Z",
|
||||
expected: "2026-07-28T06:00:00.000Z",
|
||||
},
|
||||
{
|
||||
label: "Berlin spring DST week",
|
||||
lastIntake: "2026-03-22T07:00:00.000Z",
|
||||
now: "2026-03-30T10:00:00.000Z",
|
||||
expected: "2026-03-29T06:00:00.000Z",
|
||||
},
|
||||
])(
|
||||
"retains the unresolved prior-day slot for an $label",
|
||||
({ lastIntake, now, expected }) => {
|
||||
const schedule = makeSchedule({
|
||||
id: "mounjaro-weekly",
|
||||
rollingIntervalDays: 7,
|
||||
timesOfDay: ["08:00"],
|
||||
});
|
||||
const ctx = makeCtx({
|
||||
lastIntakeAt: d(lastIntake),
|
||||
medication: { startsOn: d("2026-01-01T00:00:00.000Z") },
|
||||
});
|
||||
|
||||
const occurrence = nextOccurrenceAfter(schedule, d(now), ctx);
|
||||
|
||||
expect(occurrence).toMatchObject({
|
||||
scheduleId: "mounjaro-weekly",
|
||||
at: d(expected),
|
||||
timeOfDay: "08:00",
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
// ────────────────────────────────────────────────────────────────────
|
||||
// One-shot
|
||||
// ────────────────────────────────────────────────────────────────────
|
||||
|
||||
Reference in new issue
Block a user