M15: synchronize contracts and acceptance
This commit is contained in:
@@ -5,12 +5,20 @@ async function resetDemoData(request: APIRequestContext) {
|
||||
await request.post("/api/v1/demo/reset");
|
||||
}
|
||||
|
||||
async function switchRole(page: Page) {
|
||||
await page.locator(".operator-menu > summary").click();
|
||||
await page.getByRole("button", { name: "Switch role" }).click();
|
||||
}
|
||||
|
||||
test.describe.configure({ mode: "serial" });
|
||||
|
||||
// This file's assertions were authored against the English UI copy; nl-BE is now the
|
||||
// app's default for a fresh session, so force English explicitly rather than rewriting
|
||||
// every assertion (the equivalent Dutch/French coverage lives in the i18n-specific specs).
|
||||
test.beforeEach(async ({ page }) => {
|
||||
test.beforeEach(async ({ page, request }) => {
|
||||
// Keep reset's Set-Cookie deletion in the standalone request fixture. Sharing the
|
||||
// browser cookie jar here can race that deletion against the UI login below.
|
||||
await resetDemoData(request);
|
||||
await page.addInitScript(() => localStorage.setItem("fleetops.language", "en-GB"));
|
||||
await page.goto("/login");
|
||||
await page.getByRole("button", { name: "Explore as Operations Manager" }).click();
|
||||
@@ -44,7 +52,13 @@ test("vehicles page: status filter and attention-only checkbox both work", async
|
||||
expect(statuses.every((s) => s.includes("maintenance"))).toBeTruthy();
|
||||
|
||||
await page.getByLabel("Status").selectOption("");
|
||||
await page.getByLabel("Attention only").check();
|
||||
await expect(page).not.toHaveURL(/status=maintenance/);
|
||||
await expect(page.getByLabel("Attention only")).not.toBeChecked();
|
||||
// Updating the URL replaces this controlled input. Click it, then assert against the
|
||||
// newly-rendered control rather than asking Playwright to verify the detached node.
|
||||
await page.getByLabel("Attention only").click();
|
||||
await expect(page).toHaveURL(/attention_only=true/);
|
||||
await expect(page.getByLabel("Attention only")).toBeChecked();
|
||||
await expect(page.locator(".data-table tbody tr").first()).toBeVisible();
|
||||
const attentionCells = await page.locator(".data-table tbody tr td:nth-child(6)").allTextContents();
|
||||
expect(attentionCells.every((c) => c.includes("Needs attention"))).toBeTruthy();
|
||||
@@ -158,14 +172,16 @@ test("data quality page: status and rule-type filters work", async ({ page }) =>
|
||||
test("data quality issue detail: defer and reject buttons work", async ({ page, request }) => {
|
||||
await resetDemoData(request);
|
||||
await page.goto("/data-quality?status=open&rule_type=missing_required_field");
|
||||
await page.goto("/data-quality");
|
||||
await page
|
||||
.getByRole("combobox", { name: "Rule type", exact: true })
|
||||
.selectOption("missing_required_field");
|
||||
await expect(page.getByRole("combobox", { name: "Rule type", exact: true })).toHaveValue(
|
||||
"missing_required_field",
|
||||
);
|
||||
const firstLink = page.locator(".data-table tbody tr").first().locator("a");
|
||||
const ref = await firstLink.textContent();
|
||||
await expect(firstLink).toBeVisible();
|
||||
const ref = (await firstLink.textContent())?.trim() ?? "";
|
||||
expect(ref).not.toBe("");
|
||||
await firstLink.click();
|
||||
await expect(page.getByRole("heading", { name: ref ?? "" })).toBeVisible();
|
||||
await expect(page).toHaveURL(new RegExp(`/data-quality/${ref}$`));
|
||||
await expect(page.getByRole("heading", { name: ref })).toBeVisible();
|
||||
await page.getByRole("button", { name: "Defer" }).click();
|
||||
await expect(page.locator(".badge.status-deferred")).toBeVisible();
|
||||
});
|
||||
@@ -193,8 +209,12 @@ test("data quality: resolving a booking overlap blocks one booking", async ({ pa
|
||||
await page.getByRole("button", { name: /^Block BK-DEMO-OVERLAP-A$/ }).click();
|
||||
|
||||
await expect(page.getByText("Resolved").first()).toBeVisible();
|
||||
const booking = await page.request.get("/api/v1/bookings/BK-DEMO-OVERLAP-A");
|
||||
expect((await booking.json()).status).toBe("blocked");
|
||||
await expect
|
||||
.poll(async () => {
|
||||
const booking = await page.request.get("/api/v1/bookings/BK-DEMO-OVERLAP-A");
|
||||
return (await booking.json()).status;
|
||||
})
|
||||
.toBe("blocked");
|
||||
});
|
||||
|
||||
test("data quality: applying the recommended status resolves a vehicle conflict", async ({
|
||||
@@ -308,12 +328,12 @@ test("knowledge page: form submits and clears input", async ({ page }) => {
|
||||
const input = page.getByPlaceholder(/What must I do when a vehicle returns with damage/);
|
||||
await input.fill("What must I do when a vehicle returns with damage?");
|
||||
await page.getByRole("button", { name: "Ask" }).click();
|
||||
await expect(page.getByText("Grounded in cited procedures")).toBeVisible();
|
||||
await expect(page.getByText("Grounded in cited procedures")).toBeVisible({ timeout: 15_000 });
|
||||
await expect(input).toHaveValue("");
|
||||
});
|
||||
|
||||
test("switch role button logs out and returns to login", async ({ page }) => {
|
||||
await page.getByRole("button", { name: "Switch role" }).click();
|
||||
await switchRole(page);
|
||||
await expect(page).toHaveURL(/\/login$/);
|
||||
});
|
||||
|
||||
@@ -327,7 +347,7 @@ test("session survives a page refresh and restores the correct role", async ({ p
|
||||
|
||||
test("logout invalidates the server session so a refresh returns to login", async ({ page }) => {
|
||||
await page.goto("/dashboard");
|
||||
await page.getByRole("button", { name: "Switch role" }).click();
|
||||
await switchRole(page);
|
||||
await expect(page).toHaveURL(/\/login$/);
|
||||
|
||||
// Directly re-requesting a protected route after logout must not restore access from a
|
||||
@@ -348,7 +368,7 @@ test("direct navigation to a protected route without a session redirects to logi
|
||||
test("rental employee role has a restricted nav and cannot reach manager-only pages", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.getByRole("button", { name: "Switch role" }).click();
|
||||
await switchRole(page);
|
||||
await page.getByRole("button", { name: "Explore as Rental Employee" }).click();
|
||||
await expect(page).toHaveURL(/\/dashboard$/);
|
||||
|
||||
@@ -400,7 +420,7 @@ test("automation page shows the aggregate n8n integration status, not just the l
|
||||
test("rental employee direct API access to manager-only endpoints is rejected", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.getByRole("button", { name: "Switch role" }).click();
|
||||
await switchRole(page);
|
||||
await page.getByRole("button", { name: "Explore as Rental Employee" }).click();
|
||||
await expect(page).toHaveURL(/\/dashboard$/);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user