diff --git a/frontend/e2e/fixtures/index.ts b/frontend/e2e/fixtures/index.ts index 2c622aa..6c3e5bb 100644 --- a/frontend/e2e/fixtures/index.ts +++ b/frontend/e2e/fixtures/index.ts @@ -259,12 +259,14 @@ export async function createMedicationViaAPI(data: { takenBy?: string[]; notes?: string; expiryDate?: string; - packageType?: "blister" | "bottle"; + packageType?: "blister" | "bottle" | "tube" | "liquid_container"; + medicationForm?: "capsule" | "tablet" | "liquid" | "topical"; packCount?: number; blistersPerPack?: number; pillsPerBlister?: number; looseTablets?: number; totalPills?: number; + packageAmountValue?: number; intakeRemindersEnabled?: boolean; intakes?: { usage: number; @@ -275,15 +277,29 @@ export async function createMedicationViaAPI(data: { }[]; }): Promise { let token = getAuthCookie(); - const isBottle = data.packageType === "bottle"; + const packageType = data.packageType ?? "blister"; + const isAmountBased = packageType === "bottle" || packageType === "tube" || packageType === "liquid_container"; + let defaultMedicationForm: "capsule" | "tablet" | "liquid" | "topical" = "tablet"; + if (packageType === "tube") { + defaultMedicationForm = "topical"; + } else if (packageType === "liquid_container") { + defaultMedicationForm = "liquid"; + } + const medicationForm = data.medicationForm ?? defaultMedicationForm; + const packageAmountValue = + data.packageAmountValue ?? + (packageType === "tube" || packageType === "liquid_container" ? Math.max(1, data.totalPills ?? 30) : 0); const body = { - packageType: isBottle ? "bottle" : "blister", - packCount: isBottle ? 1 : (data.packCount ?? 1), - blistersPerPack: isBottle ? 1 : (data.blistersPerPack ?? 1), - pillsPerBlister: isBottle ? 1 : (data.pillsPerBlister ?? 10), - // For bottles: looseTablets IS the current stock. Default to totalPills if not specified. - looseTablets: isBottle ? (data.looseTablets ?? data.totalPills ?? 0) : (data.looseTablets ?? 0), - totalPills: isBottle ? (data.totalPills ?? null) : null, + packageType, + medicationForm, + packCount: packageType === "tube" ? 1 : (data.packCount ?? 1), + blistersPerPack: isAmountBased ? 1 : (data.blistersPerPack ?? 1), + pillsPerBlister: isAmountBased ? 1 : (data.pillsPerBlister ?? 10), + // Amount-based packages use looseTablets as current stock. + looseTablets: isAmountBased ? (data.looseTablets ?? data.totalPills ?? 0) : (data.looseTablets ?? 0), + totalPills: isAmountBased ? (data.totalPills ?? null) : null, + packageAmountValue, + packageAmountUnit: packageType === "tube" ? "g" : "ml", intakes: [ { usage: 1, diff --git a/frontend/e2e/medication-crud.spec.ts b/frontend/e2e/medication-crud.spec.ts index d605c26..4f04c0e 100644 --- a/frontend/e2e/medication-crud.spec.ts +++ b/frontend/e2e/medication-crud.spec.ts @@ -26,7 +26,7 @@ async function fillAndSaveMedication( opts: { name: string; genericName?: string; - packageType?: "blister" | "bottle"; + packageType?: "blister" | "bottle" | "tube" | "liquid_container"; packs?: string; blistersPerPack?: string; pillsPerBlister?: string; @@ -56,6 +56,18 @@ async function fillAndSaveMedication( if (opts.totalCapacity) await form.getByLabel(/(Total Capacity|form\.totalCapacity|Total \(pills\))/i).fill(opts.totalCapacity); if (opts.currentPills) await form.getByLabel(/(Current Pills|form\.currentPills)/i).fill(opts.currentPills); + } else if (opts.packageType === "tube") { + await packageTypeSelect.selectOption("tube"); + await page.getByRole("tab", { name: /Package/i }).click(); + if (opts.totalCapacity) { + await form.getByLabel(/(Amount per tube|form\.packageAmountPerTube)/i).fill(opts.totalCapacity); + } + } else if (opts.packageType === "liquid_container") { + await packageTypeSelect.selectOption("liquid_container"); + await page.getByRole("tab", { name: /Package/i }).click(); + if (opts.totalCapacity) { + await form.getByLabel(/(Package amount|form\.packageAmount)/i).fill(opts.totalCapacity); + } } else { await packageTypeSelect.selectOption("blister"); await page.getByRole("tab", { name: /Package/i }).click(); @@ -83,7 +95,11 @@ async function fillAndSaveMedication( await form.getByRole("button", { name: /(Intake|form\.blisters\.addIntake)/i }).click(); } const row = form.locator(".blister-row").nth(i); - await row.getByLabel(/(Usage \((pills|tablets)\)|form\.blisters\.usage)/i).fill(intakes[i].usage); + await row + .getByLabel( + /(Usage \((pills|tablets|capsules|ml|applications)\)|form\.blisters\.(usage|usageTablets|usageCapsules|usageMl|usageApplication))/i + ) + .fill(intakes[i].usage); await row.getByLabel(/(Every \(days\)|form\.blisters\.everyDays)/i).fill(intakes[i].every); } @@ -194,6 +210,26 @@ test.describe("Medication CRUD", () => { }); }); + test("should create a tube medication via the form", async ({ page }) => { + await navigateTo(page, "/medications"); + + await fillAndSaveMedication(page, { + name: "Test Tube Cream", + packageType: "tube", + totalCapacity: "50", + }); + }); + + test("should create a liquid-container medication via the form", async ({ page }) => { + await navigateTo(page, "/medications"); + + await fillAndSaveMedication(page, { + name: "Test Liquid Syrup", + packageType: "liquid_container", + totalCapacity: "120", + }); + }); + test("should create medication with notes and expiry date", async ({ page }) => { await navigateTo(page, "/medications"); diff --git a/frontend/e2e/medication-edit.spec.ts b/frontend/e2e/medication-edit.spec.ts index 1ff9246..786cadf 100644 --- a/frontend/e2e/medication-edit.spec.ts +++ b/frontend/e2e/medication-edit.spec.ts @@ -329,7 +329,7 @@ test.describe("Medication Editing", () => { } }); - test("should change package type between blister and bottle", async ({ page }) => { + test("should change package type across all supported profiles", async ({ page }) => { createdMeds.push( await createMedicationViaAPI({ name: "PackType Change Med", @@ -357,15 +357,24 @@ test.describe("Medication Editing", () => { await packageSelect.selectOption("bottle"); await page.getByRole("tab", { name: /Package/i }).click(); await expect(form.getByLabel(/(Total Capacity|form\.totalCapacity|Total \(pills\))/i)).toBeVisible(); + await page.getByRole("tab", { name: /General/i }).click(); - // Fill bottle-specific fields - await form.getByLabel(/(Total Capacity|form\.totalCapacity|Total \(pills\))/i).fill("120"); + // Switch to tube + await packageSelect.selectOption("tube"); + await page.getByRole("tab", { name: /Package/i }).click(); + await expect(form.getByLabel(/(Amount per tube|form\.packageAmountPerTube)/i)).toBeVisible(); + await page.getByRole("tab", { name: /General/i }).click(); + + // Switch to liquid container and persist this final state + await packageSelect.selectOption("liquid_container"); + await page.getByRole("tab", { name: /Package/i }).click(); + await expect(form.getByLabel(/(Package amount|form\.packageAmount)/i)).toBeVisible(); await saveEditAndVerify(page, "PackType Change Med"); - // Verify it's still a bottle after reload + // Verify final package type persisted await clickEditMed(page, "PackType Change Med"); - await expect(page.locator("select.package-type-select")).toHaveValue("bottle"); + await expect(page.locator("select.package-type-select")).toHaveValue("liquid_container"); }); test("should edit multiple fields at once (name, notes, generic, taken-by)", async ({ page }) => { diff --git a/frontend/e2e/medications.spec.ts b/frontend/e2e/medications.spec.ts index cf1bbca..2978a6a 100644 --- a/frontend/e2e/medications.spec.ts +++ b/frontend/e2e/medications.spec.ts @@ -87,25 +87,17 @@ test.describe("Medications Page", () => { expect(hasPacks || hasTotal).toBeTruthy(); }); - test("should toggle package type between blister and bottle", async ({ page }) => { + test("should expose all supported package type options", async ({ page }) => { await openMedicationForm(page); const form = visibleMedForm(page); - await page.getByRole("tab", { name: /Package/i }).click(); + const packageSelect = form.locator("select.package-type-select"); + await expect(packageSelect).toBeVisible(); - // Find the package type radio buttons or selector - const blisterOption = form.getByText(/(Blister Pack|form\.packageType\.blister)/i); - const bottleOption = form.getByText(/(Pill Bottle|form\.packageType\.bottle)/i); + const optionValues = await packageSelect + .locator("option") + .evaluateAll((options) => options.map((option) => (option as HTMLOptionElement).value)); - if (await blisterOption.isVisible().catch(() => false)) { - // Switch to bottle - await bottleOption.click(); - // Bottle-specific fields should appear - await expect(form.getByLabel(/(Total Capacity|form\.totalCapacity)/i)).toBeVisible(); - - // Switch back to blister - await blisterOption.click(); - await expect(form.getByLabel(/(Blisters per pack|form\.blistersPerPack)/i)).toBeVisible(); - } + expect(optionValues).toEqual(expect.arrayContaining(["blister", "bottle", "tube", "liquid_container"])); }); test("should have intake schedule with add button", async ({ page }) => {