import { expect, test, type Page, type Route } from "@playwright/test"; const TEST_USER = { token: "vendor-visual-token", expiration: "2030-01-01T00:00:00.000Z", email: "admin@seahavenind.com", userRoles: "Admin", phoneNumber: "5551234567", fullname: "Vendor Visual Admin", id: "1", }; const activeVendors = [ { Id: 1, CompanyId: 101, CompanyName: "Gateway Plumbing", ContactName: "Adam Whyte", Email: "dispatch@gateway.test", Phone: "314-555-0198", CompanyPhone: "314-555-0100", Address: "1 Market St", City: "St. Louis", State: "MO", Zip: "63101", TradeSpecialties: "Plumbing, Backflow Preventers", GoogleMapsUrl: "https://maps.google.com/gateway", Notes: "Preferred after-hours vendor", TotalJobs: 72, IsActive: true, PreferredContact: "Email", }, { Id: 2, CompanyId: 102, CompanyName: "Metro HVAC", ContactName: "Maya Chen", Email: "maya@metro.test", Phone: "314-555-0112", CompanyPhone: "314-555-0110", Address: "2 Pine St", City: "Clayton", State: "MO", Zip: "63105", TradeSpecialties: "HVAC", GoogleMapsUrl: "", Notes: "", TotalJobs: 18, IsActive: true, }, ]; const inactiveVendors = [ { ...activeVendors[0], Id: 3, CompanyId: 103, CompanyName: "Drain Cleaning Bros", ContactName: "Drew Banks", TotalJobs: 151, IsActive: false, }, ]; async function fulfillJson(route: Route, body: unknown, status = 200) { await route.fulfill({ status, contentType: "application/json", body: JSON.stringify(body) }); } async function mockVendorApi(page: Page, mode: "default" | "empty" | "error" = "default") { await page.clock.setFixedTime(new Date("2026-08-10T12:00:00.000Z")); await page.addInitScript((user) => localStorage.setItem("auth", JSON.stringify(user)), TEST_USER); await page.route("**/api/**", async (route) => { const request = route.request(); const url = new URL(request.url()); if (!url.pathname.startsWith("/api/")) { await route.continue(); return; } if (url.pathname.includes("/DropdownOptions/ByCategory/Trade")) { await fulfillJson(route, { data: [ { id: 1, value: "Plumbing" }, { id: 2, value: "HVAC" }, ], }); return; } if (url.pathname.endsWith("/api/Vendor/facets")) { await fulfillJson(route, { data: { companies: activeVendors.map((vendor) => ({ companyId: vendor.CompanyId, name: vendor.CompanyName, })), trades: ["Plumbing", "Backflow Preventers", "HVAC"], locations: [ { city: "St. Louis", state: "MO", label: "St. Louis, MO" }, { city: "Clayton", state: "MO", label: "Clayton, MO" }, ], jobBuckets: [ { id: "under-50", label: "Under 50" }, { id: "50-99", label: "50–99" }, { id: "100-149", label: "100–149" }, { id: "150-plus", label: "150+" }, ], }, }); return; } if (url.pathname.endsWith("/api/Vendor/GetVendorList")) { const isCount = url.searchParams.get("pageSize") === "1"; if (mode === "error" && !isCount) { await fulfillJson(route, { message: "Vendor directory unavailable" }, 500); return; } const source = mode === "empty" ? [] : url.searchParams.get("isActive") === "false" ? inactiveVendors : activeVendors; await fulfillJson(route, { Data: isCount ? source.slice(0, 1) : source, TotalCount: source.length, PageNumber: 1, PageSize: Number(url.searchParams.get("pageSize") ?? 12), }); return; } if (url.pathname.startsWith("/api/vendor-company-roster")) { await fulfillJson(route, { companyId: 101, rowVersion: "rv-visual", name: "Gateway Plumbing", companyPhone: "314-555-0100", email: "dispatch@gateway.test", address: "1 Market St", city: "St. Louis", state: "MO", zip: "63101", googleMapsUrl: "https://maps.google.com/gateway", notes: "Preferred after-hours vendor", technicians: [ { id: 1, contactName: "Adam Whyte", phone: "314-555-0198", email: "dispatch@gateway.test", preferredContact: "Email", tradeSpecialties: "Plumbing, Backflow Preventers", isActive: true, totalJobs: 72, }, ], }); return; } await fulfillJson(route, { data: {} }); }); } async function openVendorPage(page: Page, mode: "default" | "empty" | "error" = "default") { await mockVendorApi(page, mode); await page.goto("/vendors"); await page.evaluate(() => document.fonts.ready); await page.addStyleTag({ content: ` *, *::before, *::after { transition: none !important; animation: none !important; } .MuiDrawer-paper { transform: none !important; } .Toastify__toast-container { display: none !important; } .tsqd-parent-container { display: none !important; } `, }); } async function expectStableScreenshot(page: Page, name: string) { await page.waitForTimeout(250); await page.evaluate( () => new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(() => resolve())), ), ); await page.screenshot({ animations: "disabled", caret: "hide" }); await expect(page).toHaveScreenshot(name); } test.describe("Vendor deterministic pixel regression", () => { test("list", async ({ page }) => { await openVendorPage(page); await expect(page.getByText("Gateway Plumbing")).toBeVisible(); await expectStableScreenshot(page, "vendor-list.png"); }); test("filter", async ({ page }) => { await openVendorPage(page); await page.getByRole("button", { name: "Open vendor filters" }).click(); await expect(page.getByRole("heading", { name: "Filters" })).toBeVisible(); await expectStableScreenshot(page, "vendor-filter.png"); }); test("add", async ({ page }) => { await openVendorPage(page); await page.getByRole("button", { name: "Add Vendor", exact: true }).click(); await expect(page.getByRole("dialog", { name: /Add Vendor/ })).toBeVisible(); await expectStableScreenshot(page, "vendor-add.png"); }); test("detail", async ({ page }) => { await openVendorPage(page); await page.getByRole("button", { name: "View vendor Gateway Plumbing" }).click(); await expect(page.getByRole("button", { name: "Close drawer" })).toBeVisible(); await expectStableScreenshot(page, "vendor-detail.png"); }); test("edit", async ({ page }) => { await openVendorPage(page); await page.getByRole("button", { name: "Edit vendor Gateway Plumbing" }).click(); await expect(page.getByRole("button", { name: "Save changes" })).toBeVisible(); await expectStableScreenshot(page, "vendor-edit.png"); }); test("inactive", async ({ page }) => { await openVendorPage(page); await page.getByRole("tab", { name: "Inactive (1)" }).click(); await expect(page.getByText("Drain Cleaning Bros")).toBeVisible(); await expectStableScreenshot(page, "vendor-inactive.png"); }); test("empty", async ({ page }) => { await openVendorPage(page, "empty"); await expect(page.getByText("No active technicians found")).toBeVisible(); await expectStableScreenshot(page, "vendor-empty.png"); }); test("error", async ({ page }) => { await openVendorPage(page, "error"); await expect(page.getByRole("main").getByRole("alert")).toContainText( /server error|vendor directory unavailable/i, ); await expectStableScreenshot(page, "vendor-error.png"); }); test("mobile", async ({ page }) => { await page.setViewportSize({ width: 390, height: 844 }); await openVendorPage(page); await expect(page.getByText("Gateway Plumbing")).toBeVisible(); await expectStableScreenshot(page, "vendor-mobile.png"); await page.getByRole("button", { name: "Toggle navigation" }).click(); await expect(page.getByRole("navigation", { name: "Primary navigation" })).toBeVisible(); await expectStableScreenshot(page, "vendor-mobile-navigation.png"); }); });