import { expect, test, type Page, type Route } from "@playwright/test"; const FROZEN_NOW = "2026-08-19T15:00:00.000Z"; const BOARD_ROW = { id: 1, woNumber: "WO-501", workOrderType: 2, siteCode: "STL-01", locationName: "St. Louis HQ", locationId: 10, lifecycleStatusLabel: "In Progress", scheduledDate: "2026-08-19", dispatcherId: "1", dispatcherName: "Pat Dispatcher", pm: "HVAC", rowVersion: "rv-1", }; type Role = "Admin" | "Dispatcher"; async function fulfillJson(route: Route, body: unknown) { await route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify(body) }); } async function mockApi( page: Page, role: Role, createPayloads: unknown[] = [], searchUrls: string[] = [], ) { await page.clock.install({ time: new Date(FROZEN_NOW) }); await page.clock.resume(); await page.addInitScript( (user) => { localStorage.setItem("auth", JSON.stringify(user)); const style = document.createElement("style"); style.textContent = ".tsqd-parent-container { display: none !important; }"; document.documentElement.appendChild(style); }, { token: `wo-pending-${role.toLowerCase()}-e2e-token`, expiration: "2030-01-01T00:00:00.000Z", email: `${role.toLowerCase()}@seahavenind.com`, userRoles: role, phoneNumber: "5551234567", fullname: `Work Order E2E ${role}`, id: "1", }, ); let row = { ...BOARD_ROW }; let createdRow: typeof BOARD_ROW | undefined; await page.route( (url) => url.pathname.startsWith("/api/"), async (route) => { const request = route.request(); const { pathname } = new URL(request.url()); if (pathname.includes("/workorders/board/search")) { searchUrls.push(request.url()); await fulfillJson(route, { items: createdRow ? [createdRow] : [], totalCount: createdRow ? 1 : 0, page: 0, pageSize: 50, }); return; } if (pathname === "/api/workorders/board" && request.method() === "GET") { await fulfillJson(route, { weekStart: "2026-08-17", weekEnd: "2026-08-21", counts: { returned: createdRow ? 2 : 1, total: createdRow ? 2 : 1 }, unscheduled: createdRow ? [createdRow] : [], scheduled: [row], }); return; } if (pathname === "/api/workorders/board" && request.method() === "POST") { const payload = request.postDataJSON() as { lifecycleStatus: number; scheduledDate?: string; }; createPayloads.push(payload); createdRow = { ...BOARD_ROW, id: 900, woNumber: "WO-900", lifecycleStatusLabel: payload.lifecycleStatus === 3 ? "Scheduled" : "Pending", scheduledDate: payload.scheduledDate ?? "", rowVersion: "rv-created", }; await fulfillJson(route, { data: { id: 900, internalWONumber: "WO-900" } }); return; } if (pathname === "/api/workorders/1/board" && request.method() === "PATCH") { const body = request.postDataJSON() as { field: string; value: string }; row = { ...row, lifecycleStatusLabel: body.value, rowVersion: "rv-2" }; await fulfillJson(route, row); return; } if (pathname.includes("/locations/sites") || pathname.includes("/Contact/GetLocations")) { await fulfillJson(route, { data: [{ id: 10, name: "STL-01 ยท St. Louis, MO", siteCode: "STL-01", code: "STL-01" }], }); return; } if (pathname === "/api/locations/10") { await fulfillJson(route, { data: { id: 10, name: "St. Louis HQ", siteCode: "STL-01", contact: "Pat Site", phone: "3145550111", }, }); return; } await fulfillJson(route, { data: [], items: [] }); }, ); } async function expectManualTransitionWithoutPending(page: Page) { const row = page.locator("#wo-row-1"); await expect(row.getByText("WO-501")).toBeVisible(); await row.getByRole("button", { name: "In Progress" }).click(); const menu = page.locator(".MuiPopover-paper").last(); await expect(menu.getByRole("button", { name: "Pending", exact: true })).toHaveCount(0); await expect(menu.getByRole("button", { name: "On Site", exact: true })).toBeEnabled(); await menu.getByRole("button", { name: "On Site", exact: true }).click(); await expect(row.getByRole("button", { name: "On Site" })).toBeVisible(); } test.describe("existing work order status menu", () => { test.setTimeout(60_000); test("Admin can choose a manual status but not Pending", async ({ page }) => { await mockApi(page, "Admin"); await page.goto("/workorders"); await expect(page.getByRole("heading", { name: "Work Orders" })).toBeVisible({ timeout: 20_000, }); await expectManualTransitionWithoutPending(page); }); test("Dispatcher can choose a manual status but not Pending", async ({ page }) => { await mockApi(page, "Dispatcher"); await page.goto("/workorders"); await expect(page.getByRole("heading", { name: "Work Orders" })).toBeVisible({ timeout: 20_000, }); await expectManualTransitionWithoutPending(page); }); test("Admin can select Pending for a new work order when Schedule On has no date", async ({ page, }) => { const createPayloads: unknown[] = []; const searchUrls: string[] = []; await mockApi(page, "Admin", createPayloads, searchUrls); await page.goto("/workorders"); await expect(page.getByRole("heading", { name: "Work Orders" })).toBeVisible({ timeout: 20_000, }); await page.getByRole("button", { name: "New WO" }).click(); await expect(page.getByRole("heading", { name: "Type & schedule" })).toBeVisible(); await expect(page.getByRole("button", { name: "Pick a date" })).toBeVisible(); await page.getByRole("button", { name: "Continue" }).click(); await page.getByRole("button", { name: /select site/i }).click(); await page .getByRole("button", { name: /STL-01/ }) .last() .click(); await page.getByRole("button", { name: "Continue" }).click(); await page.getByRole("button", { name: "Incomplete", exact: true }).last().click(); const menu = page.locator(".MuiPopover-paper").last(); await expect(menu.getByRole("button", { name: "Pending", exact: true })).toBeEnabled(); await menu.getByRole("button", { name: "Pending", exact: true }).click(); await expect( page.getByRole("dialog").getByRole("button", { name: "Pending", exact: true }), ).toBeVisible(); await page.getByRole("button", { name: "Create work order" }).click(); await expect(page.getByRole("heading", { name: "Type & schedule" })).toBeHidden(); await expect .poll(() => createPayloads) .toEqual([expect.objectContaining({ lifecycleStatus: 2 })]); const filtersSheet = page.getByRole("dialog", { name: "Advanced Filters" }); await page.getByRole("button", { name: "Advanced Filters" }).click(); await expect(filtersSheet).toBeVisible(); await filtersSheet.getByRole("button", { name: "Date range" }).click(); await filtersSheet.getByRole("button", { name: "Unscheduled", exact: true }).click(); await filtersSheet.getByRole("button", { name: "Apply filters" }).click(); await expect .poll(() => searchUrls.some((url) => url.includes("unscheduledOnly=true"))) .toBe(true); const createdRow = page.locator("#wo-row-900"); await expect(createdRow.getByText("WO-900")).toBeVisible(); await expect(createdRow.getByRole("button", { name: "Pending" })).toBeVisible(); }); test("Admin gets Scheduled when adding Schedule On after selecting Pending", async ({ page }) => { const createPayloads: unknown[] = []; await mockApi(page, "Admin", createPayloads); await page.goto("/workorders"); await expect(page.getByRole("heading", { name: "Work Orders" })).toBeVisible({ timeout: 20_000, }); await page.getByRole("button", { name: "New WO" }).click(); await expect(page.getByRole("heading", { name: "Type & schedule" })).toBeVisible(); await page.getByRole("button", { name: "Continue" }).click(); await page.getByRole("button", { name: /select site/i }).click(); await page .getByRole("button", { name: /STL-01/ }) .last() .click(); await page.getByRole("button", { name: "Continue" }).click(); await page.getByRole("button", { name: "Incomplete", exact: true }).last().click(); const menu = page.locator(".MuiPopover-paper").last(); await menu.getByRole("button", { name: "Pending", exact: true }).click(); await expect( page.getByRole("dialog").getByRole("button", { name: "Pending", exact: true }), ).toBeVisible(); await page.getByRole("button", { name: "Back" }).click(); await page.getByRole("button", { name: "Back" }).click(); await page.getByRole("button", { name: "Pick a date" }).click(); const dateTab = page.getByRole("button", { name: "Date", exact: true }); if (await dateTab.isVisible()) { await dateTab.click(); } await page.getByRole("button", { name: "20", exact: true }).click(); await expect(page.getByRole("button", { name: /Aug 20/ })).toBeVisible(); await page.getByRole("button", { name: "Continue" }).click(); await page.getByRole("button", { name: "Continue" }).click(); const wizardDialog = page.getByRole("dialog"); const scheduledStatus = wizardDialog.getByRole("button", { name: "Scheduled", exact: true, }); await expect(scheduledStatus).toBeVisible(); await scheduledStatus.click(); const statusMenu = page.locator(".MuiPopover-paper").last(); await expect(statusMenu.getByRole("button", { name: "Pending", exact: true })).toBeDisabled(); await statusMenu.getByRole("button", { name: "Scheduled", exact: true }).click(); await expect(scheduledStatus).toBeVisible(); await page.getByRole("button", { name: "Create work order" }).click(); await expect(page.getByRole("heading", { name: "Type & schedule" })).toBeHidden(); await expect .poll(() => createPayloads) .toEqual([expect.objectContaining({ lifecycleStatus: 3, scheduledDate: "2026-08-20" })]); }); });