Files
Daniel Volz ac47fc001d fix: adapt e2e medication flows to all package profiles (#380)
* test: adapt e2e medication flows to all package profiles

* fix(frontend): resolve frontend build lint blockers
2026-03-04 21:15:18 +01:00

156 lines
5.9 KiB
TypeScript

import { expect, type Page } from "@playwright/test";
import { authFile, navigateTo, test } from "./fixtures";
/**
* Medications Page E2E Tests
*
* Verifies the medication list, add/edit form, CRUD operations,
* and form validation.
*/
test.describe("Medications Page", () => {
test.use({ storageState: authFile });
const visibleMedForm = (page: Page) => page.locator("form.form-grid:visible").first();
async function openMedicationForm(page: Page) {
await navigateTo(page, "/medications");
const nameField = visibleMedForm(page).getByLabel(/(Commercial Name|form\.commercialName)/i);
if (await nameField.isVisible().catch(() => false)) return;
const newEntryButton = page.getByRole("button", { name: /(new (entry|medication)|form\.newEntry)/i });
if (await newEntryButton.isVisible().catch(() => false)) {
await newEntryButton.click();
await expect(nameField).toBeVisible({ timeout: 5000 });
}
}
test("should display medications page", async ({ page }) => {
await navigateTo(page, "/medications");
// Medications tab should be active
await expect(page.locator('button.pill.primary:has-text("Medications")')).toBeVisible();
});
test("should show medication list or empty state", async ({ page }) => {
await navigateTo(page, "/medications");
// Should show either medication entries or the new medication form
const listTitle = page.locator("h2").filter({ hasText: /(Medication list|form\.medicationList)/i });
const formTitle = page.locator("h2").filter({ hasText: /(New (entry|medication)|form\.newEntry)/i });
const hasList = await listTitle.isVisible().catch(() => false);
const hasForm = await formTitle.isVisible().catch(() => false);
expect(hasList || hasForm).toBeTruthy();
});
test("should display the medication form with required fields", async ({ page }) => {
await openMedicationForm(page);
const form = visibleMedForm(page);
const commercialName = form.getByLabel(/(Commercial Name|form\.commercialName)/i);
await expect(commercialName).toBeVisible();
// Package type selector should exist
await expect(form.getByText(/(Package Type|form\.packageType)/i)).toBeVisible();
// Tabbed form should expose navigation to Package/Schedule sections
await expect(page.getByRole("tab", { name: /Package/i })).toBeVisible();
await expect(page.getByRole("tab", { name: /Schedule/i })).toBeVisible();
});
test("should fill in medication details", async ({ page }) => {
await openMedicationForm(page);
const form = visibleMedForm(page);
const nameField = form.getByLabel(/(Commercial Name|form\.commercialName)/i);
await nameField.fill("Test Aspirin");
await expect(nameField).toHaveValue("Test Aspirin");
const genericField = form.getByLabel(/(Generic Name|form\.genericName)/i);
await genericField.fill("Acetylsalicylic acid");
await expect(genericField).toHaveValue("Acetylsalicylic acid");
});
test("should have stock inventory fields", async ({ page }) => {
await openMedicationForm(page);
const form = visibleMedForm(page);
await page.getByRole("tab", { name: /Package/i }).click();
// Package tab should expose stock-related fields for at least one package mode.
const packsField = form.getByLabel(/(^Packs$|form\.packs)/i).first();
const totalField = form.getByText(/(Total \(pills\)|Total Capacity|form\.totalCapacity)/i).first();
const hasPacks = await packsField.isVisible().catch(() => false);
const hasTotal = await totalField.isVisible().catch(() => false);
expect(hasPacks || hasTotal).toBeTruthy();
});
test("should expose all supported package type options", async ({ page }) => {
await openMedicationForm(page);
const form = visibleMedForm(page);
const packageSelect = form.locator("select.package-type-select");
await expect(packageSelect).toBeVisible();
const optionValues = await packageSelect
.locator("option")
.evaluateAll((options) => options.map((option) => (option as HTMLOptionElement).value));
expect(optionValues).toEqual(expect.arrayContaining(["blister", "bottle", "tube", "liquid_container"]));
});
test("should have intake schedule with add button", async ({ page }) => {
await openMedicationForm(page);
const form = visibleMedForm(page);
await page.getByRole("tab", { name: /Schedule/i }).click();
// Intake schedule section
await expect(page.getByRole("tab", { name: /Schedule/i, selected: true })).toBeVisible();
// Should have at least one intake entry
await expect(
form.getByText(/(Usage \(pills\)|Every \(days\)|form\.blisters\.usage|form\.blisters\.everyDays)/i).first()
).toBeVisible();
// Should have an add intake button
const addIntake = form.getByRole("button", { name: /(Intake|form\.blisters\.addIntake)/i });
await expect(addIntake).toBeVisible();
});
test("should have save and cancel buttons", async ({ page }) => {
await openMedicationForm(page);
const form = visibleMedForm(page);
// Fill in a name to make the form dirty
await form.getByLabel(/(Commercial Name|form\.commercialName)/i).fill("Test");
// Save button
const saveButton = page.getByRole("button", { name: /Save|Add Medication/i });
await expect(saveButton).toBeVisible();
});
test("should prevent navigation with unsaved changes", async ({ page }) => {
await openMedicationForm(page);
const form = visibleMedForm(page);
// Fill in the form to create unsaved changes
await form.getByLabel(/(Commercial Name|form\.commercialName)/i).fill("Unsaved Medication");
// Try to navigate away
await page.locator('button.pill:has-text("Dashboard")').click();
// Should show unsaved changes warning modal
const modal = page.locator(".confirm-modal-overlay, .modal-overlay");
const hasWarning = await modal.isVisible().catch(() => false);
if (hasWarning) {
// Cancel to stay on page
const cancelBtn = page.getByRole("button", { name: /Cancel|Stay/i });
if (await cancelBtn.isVisible().catch(() => false)) {
await cancelBtn.click();
}
}
});
});