import { expect, test, type APIRequestContext, type Page } from "@playwright/test"; async function reset(request: APIRequestContext) { expect((await request.post("/api/v1/demo/login", { data: { role: "operations_manager" } })).ok()).toBeTruthy(); expect((await request.post("/api/v1/demo/reset")).ok()).toBeTruthy(); expect((await request.post("/api/v1/demo/login", { data: { role: "operations_manager" } })).ok()).toBeTruthy(); } async function login(page: Page) { await page.goto("/login"); await page.getByRole("button", { name: "Verken als Operationsmanager" }).click(); await expect(page).toHaveURL(/\/dashboard$/); } test.describe.configure({ mode: "serial" }); test("booking creation explains when the end does not follow the start", async ({ page }) => { await login(page); await page.goto("/bookings/new"); const start = page.getByLabel("Start"); const end = page.getByLabel("Einde"); const startValue = await start.inputValue(); await end.fill(startValue); await expect(page.getByRole("alert")).toHaveText("Het einde moet na de start van de boeking vallen."); await expect(end).toHaveAttribute("aria-invalid", "true"); await expect(page.getByRole("button", { name: "Boeking aanmaken" })).toBeDisabled(); }); test("operator can create and cancel a booking through the UI", async ({ page, request }) => { await reset(request); await login(page); await page.goto("/bookings/new"); await page.getByLabel("Klant zoeken").fill("CUS-0001"); const customer = page.locator(".booking-create-form select").nth(0); await expect.poll(() => customer.locator("option").count()).toBeGreaterThan(1); await customer.selectOption({ index: 1 }); const vehicle = page.locator(".booking-create-form select").nth(1); await expect.poll(() => vehicle.locator("option").count()).toBeGreaterThan(1); await vehicle.selectOption({ index: 1 }); await page.getByRole("button", { name: "Boeking aanmaken" }).click(); await expect(page).toHaveURL(/\/bookings\/BK-/); await expect(page.getByText("gereserveerd", { exact: true })).toBeVisible(); await expect(page.getByRole("heading", { name: "Vereisten controleren" })).toBeVisible(); await expect(page.getByRole("heading", { name: "Voertuig uitchecken" })).toHaveCount(0); await page.getByLabel("Controlebewijs").fill("Rijbewijs en huurvoorwaarden gecontroleerd"); await page.getByRole("button", { name: "Vereisten bevestigen" }).click(); await expect(page.getByRole("heading", { name: "Voertuig uitchecken" })).toBeVisible(); await page.getByLabel("Reden", { exact: true }).fill("Klant annuleert de geplande rit"); await page.getByRole("button", { name: "Annulering bevestigen" }).click(); await expect(page.getByText("geannuleerd", { exact: true })).toBeVisible(); }); test("manager can create, edit and deactivate an operational user", async ({ page, request }) => { await reset(request); await login(page); await page.goto("/users"); await page.getByLabel("Naam").fill("E2E Planner"); await page.getByLabel("E-mail").fill("e2e.planner@example.test"); await page.getByLabel("Tijdelijk wachtwoord").fill("secure-e2e-password"); await page.getByRole("button", { name: "Gebruiker toevoegen" }).click(); let row = page.getByRole("row", { name: /E2E Planner/ }); await expect(row).toBeVisible(); await row.getByRole("button", { name: "Bewerken" }).click(); const editor = page.locator(".user-edit"); await editor.getByLabel("Naam").fill("E2E Senior Planner"); await editor.getByLabel("Rol").selectOption("operations_manager"); await editor.getByLabel("Nieuw wachtwoord").fill("updated-e2e-password"); await editor.getByRole("button", { name: "Wijzigingen opslaan" }).click(); row = page.getByRole("row", { name: /E2E Senior Planner/ }); await expect(row.getByText("Operationeel beheerder")).toBeVisible(); await row.getByRole("button", { name: "Deactiveren" }).click(); await expect(row.getByText("inactief", { exact: true })).toBeVisible(); }); test("manager can assign data-quality work from the queue", async ({ page, request }) => { await reset(request); await login(page); await page.goto("/data-quality?status=open"); const firstRow = page.locator(".data-table tbody tr").first(); const issueRef = (await firstRow.locator(".row-link").textContent())?.trim() ?? ""; expect(issueRef).not.toBe(""); await firstRow.getByRole("checkbox").check(); const assignee = page.getByLabel("Toewijzen aan"); await assignee.selectOption({ index: 1 }); const selectedLabel = await assignee.locator("option:checked").textContent(); await page.getByRole("button", { name: "Werkvoorraad bijwerken" }).click(); const updatedRow = page.locator(".data-table tbody tr").filter({ has: page.getByRole("link", { name: issueRef, exact: true }), }); await expect(updatedRow).toContainText(selectedLabel ?? ""); }); test("manager can record maintenance and release a safe vehicle", async ({ page, request }) => { await reset(request); const vehicles = await (await request.get("/api/v1/vehicles?status=available")).json(); let selected = vehicles[0]; for (const candidate of vehicles) { const detail = await (await request.get(`/api/v1/vehicles/${candidate.public_ref}`)).json(); if (!detail.attention && !detail.bookings.some((booking: { status: string }) => booking.status === "active")) { selected = candidate; break; } } await login(page); await page.goto(`/vehicles/${selected.public_ref}`); await page.getByRole("tab", { name: "Onderhoud" }).click(); await page.getByRole("button", { name: "Onderhoud registreren" }).click(); await page.getByLabel("Uitgevoerd werk").fill("Periodiek onderhoud en veiligheidscontrole voltooid"); await page.getByRole("button", { name: "Onderhoud opslaan" }).click(); await expect(page.getByText("onderhoud", { exact: true }).first()).toBeVisible(); await page.getByLabel("Reden voor vrijgave").fill("Veiligheidscontrole afgerond zonder open punten"); await page.getByRole("button", { name: "Voertuig vrijgeven" }).click(); await expect(page.getByText("beschikbaar", { exact: true }).first()).toBeVisible(); });