From dfdc37eec1b11bb4b3ae0075adc1aa485e8bdb3b Mon Sep 17 00:00:00 2001 From: jhodgkin Date: Mon, 13 Jul 2026 00:06:04 -0600 Subject: [PATCH] Add e2e coverage for the new-device badge Cross-checks the rendered .device-badge.new count against the API's isNew count rather than forcing a synthetic new-device scenario -- that would permanently pollute the production seen_macs table on every test run. Full end-to-end verification (synthetic device injected via devices-raw.json, confirmed isNew: true, confirmed 0 false positives across the other 71 real devices) was done manually against the live deployment and cleaned up afterward; this test guards the UI/API consistency going forward. 16/16 e2e tests green across 9 spec files. Co-Authored-By: Claude Sonnet 5 --- e2e/tests/new-device-badge.spec.ts | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 e2e/tests/new-device-badge.spec.ts diff --git a/e2e/tests/new-device-badge.spec.ts b/e2e/tests/new-device-badge.spec.ts new file mode 100644 index 0000000..27eddf5 --- /dev/null +++ b/e2e/tests/new-device-badge.spec.ts @@ -0,0 +1,28 @@ +import { test, expect } from "@playwright/test"; + +const USERNAME = process.env.LOCAL_USERNAME ?? "admin"; +const PASSWORD = process.env.LOCAL_PASSWORD ?? ""; + +test("'new' badge count matches the API's isNew count", async ({ page }) => { + test.skip(!PASSWORD, "LOCAL_PASSWORD not set"); + + await page.goto("/"); + await page.getByPlaceholder("Username").fill(USERNAME); + await page.getByPlaceholder("Password").fill(PASSWORD); + await page.getByRole("button", { name: "Sign in" }).click(); + await expect(page.locator(".device-table tbody tr").first()).toBeVisible({ timeout: 15_000 }); + + // Cross-check against the API directly rather than forcing a synthetic + // "new device" scenario -- that would permanently pollute the production + // seen_macs table on every test run. Whatever's genuinely new right now is + // enough to verify the UI reflects the API correctly. page.request (not + // the bare `request` fixture) shares the browser context's session cookie. + const res = await page.request.get("/api/devices"); + const { devices } = await res.json(); + const apiNewCount = devices.filter((d: { isNew: boolean }) => d.isNew).length; + + await expect(async () => { + const badgeCount = await page.locator(".device-badge.new").count(); + expect(badgeCount).toBe(apiNewCount); + }).toPass({ timeout: 10_000 }); +});