diff --git a/tests/mobile-admin/stops-visual.spec.ts b/tests/mobile-admin/stops-visual.spec.ts new file mode 100644 index 0000000..080cac9 --- /dev/null +++ b/tests/mobile-admin/stops-visual.spec.ts @@ -0,0 +1,39 @@ +// tests/mobile-admin/stops-visual.spec.ts +import { test, expect } from "@playwright/test"; + +test.use({ viewport: { width: 390, height: 844 } }); // iPhone 13 + +test.beforeEach(async ({ page }) => { + // Sign in as a test admin (requires the seed admin from db/seed.ts). + await page.goto("/login"); + await page.fill('input[name="email"]', "test-admin@example.com"); + await page.fill('input[name="password"]', "test-password"); + await page.click('button[type="submit"]'); + await page.waitForURL(/\/admin/); +}); + +test("stops list — iPhone 13", async ({ page }) => { + await page.goto("/admin/v2/stops"); + await page.waitForLoadState("networkidle"); + + // The page must render the v2 shell scaffolding. A 48pt-tall date + // picker sits in the action slot; the stops list is grouped by + // time-of-day (Morning / Afternoon / Evening / Anytime). + await expect(page.locator('input[type="date"]')).toBeVisible(); + + await expect(page).toHaveScreenshot("stops-list-iphone13.png", { + fullPage: true, + maxDiffPixels: 200, + }); +}); + +test("stops list — empty state (date with no stops)", async ({ page }) => { + // Pick a date deep in the past so no stops are scheduled. + await page.goto("/admin/v2/stops?date=2000-01-01"); + await page.waitForLoadState("networkidle"); + + // The empty state copy is the source of truth. + await expect( + page.getByText("No stops scheduled", { exact: true }), + ).toBeVisible(); +});