Files
HealthLog/src/lib/medications/__tests__/default-medication.test.ts
T
Marc-André Bombeck eae46ed535 fix(medications): preselect only a dose offered today, graded by the account's thresholds
The intake pickers chose their default from every active medication, so a
course that had ended but was not archived could be the preselected dose.
The default now reads the server's intakeActionable answer; the medications
page dialog still lists ended courses for back-filling a past dose, they are
just never the default.

Both pickers also graded "due" against the fixed 120 / 240-minute defaults
while the cards beside them used the account's own late and missed
thresholds. They read the same thresholds now.
2026-10-01 09:48:48 +02:00

117 lines
3.2 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
pickDefaultMedicationId,
resolveMedicationSelectionId,
type DefaultMedicationOption,
} from "@/lib/medications/default-medication";
function medication(
id: string,
overrides: Partial<DefaultMedicationOption> = {},
): DefaultMedicationOption {
return {
id,
name: `Medication ${id}`,
active: true,
intakeActionable: true,
schedules: [],
lastTakenAt: null,
todayEventCount: 0,
...overrides,
};
}
const currentWindow = {
windowStart: "08:00",
windowEnd: "11:00",
daysOfWeek: null,
};
describe("pickDefaultMedicationId", () => {
it("prefers a current-window medication over the first array item", () => {
const now = new Date("2026-05-12T08:00:00.000Z");
expect(
pickDefaultMedicationId(
[
medication("first", { name: "Alpha" }),
medication("due", {
name: "Zulu",
schedules: [currentWindow],
nextDueAt: "2026-05-12T07:00:00.000Z",
nextDueOverdue: false,
}),
],
now,
),
).toBe("due");
});
it("keeps the alphabetical fallback stable when next due is in the future", () => {
const now = new Date("2026-05-12T08:00:00.000Z");
const options = [
medication("z", {
name: "Zolpidem",
schedules: [currentWindow],
nextDueAt: "2026-05-13T07:00:00.000Z",
nextDueOverdue: false,
}),
medication("r", { name: "Ramipril" }),
];
expect(pickDefaultMedicationId(options, now)).toBe("r");
expect(pickDefaultMedicationId([...options].reverse(), now)).toBe("r");
});
it("never preselects an ended course, even when it is the only active one", () => {
// Still active (not archived) but the course ended: the server answers
// `intakeActionable: false`, the list keeps it for back-filling, and the
// default lands on the medication that offers a dose today.
const options = [
medication("ended", {
name: "Amoxicillin",
active: true,
intakeActionable: false,
}),
medication("current", { name: "Ramipril" }),
];
expect(pickDefaultMedicationId(options)).toBe("current");
expect(
pickDefaultMedicationId([
medication("ended", { active: true, intakeActionable: false }),
]),
).toBeNull();
});
});
describe("resolveMedicationSelectionId", () => {
it("preserves an explicit user selection when due data changes on re-render", () => {
const now = new Date("2026-05-12T08:00:00.000Z");
const initial = [
medication("manual", { name: "Alpha" }),
medication("due", {
name: "Zulu",
schedules: [currentWindow],
nextDueAt: "2026-05-12T07:00:00.000Z",
nextDueOverdue: false,
}),
];
expect(resolveMedicationSelectionId(initial, null, now)).toBe("due");
const rerendered = [
medication("other-due", {
name: "Beta",
schedules: [currentWindow],
nextDueAt: "2026-05-12T07:00:00.000Z",
nextDueOverdue: true,
}),
...initial,
];
expect(resolveMedicationSelectionId(rerendered, "manual", now)).toBe(
"manual",
);
});
});