Compare commits

...

2 commits

Author SHA1 Message Date
Codex Review Integration
e90c5b97e4 test(vendors): keep the map preview out of the pixel baselines
The visual suite mocks `**/api/**` and nothing else, so the address map
preview's iframe reached maps.google.com for real. Whether that frame paints,
and what it paints, depends on the network and on what Google serves that
minute — which is why `vendor-edit` failed in CI at 18178 differing pixels
while passing in a container that could not reach Google. Regenerating the
baseline would not have fixed it; it would have moved the flake.

Aborting the request pins the frame to a blank box, so the shot measures our
layout and nothing else. The committed baselines are unchanged by this — they
were already correct — and a second container run with no --update passes
16/16, which is the evidence the shot is now stable rather than merely green
once.
2026-09-10 17:13:30 -03:00
Codex Review Integration
e222c771b9 test(vendors): update the browser specs and pixel baselines for the new address
`npm run verify` does not run Playwright, so the first push went out with the
browser suite still asserting the UI this ticket removes. Three assertions
were stale: the combined "Address (optional)" input, the "Google Maps URL
(optional)" input, and the detail drawer's separate "Open in Google Maps"
row — now replaced by the Street Address itself being the link, checked
against the derived href. A fourth test created a vendor without an address,
which the new requirement blocks; it fills one, so the test still fails only
for the reason it is about.

Baselines regenerated in mcr.microsoft.com/playwright:v1.61.1-noble, the image
CI uses — macOS font rendering produces different pixels. Exactly three of the
sixteen were rewritten (vendor add, edit, detail); the rest, including every
Work Orders shot, are byte-identical, which is the evidence that this change
stays inside the surfaces it claims.
2026-09-10 16:58:49 -03:00
5 changed files with 31 additions and 6 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

After

Width:  |  Height:  |  Size: 144 KiB

View file

@ -587,10 +587,16 @@ test.describe("Vendor directory prototype parity", () => {
await expect(page.getByRole("textbox", { name: "Email (optional)", exact: true })).toHaveValue(
"dispatch@gateway.test",
);
await expect(page.getByLabel("Address (optional)")).toHaveValue("1 Market St");
await expect(page.getByLabel("Google Maps URL (optional)")).toHaveValue(
"https://maps.google.com/gateway",
// SH-271: one combined "Address (optional)" line became three required
// fields, and the hand-pasted Google Maps URL input is gone — the location
// is derived from the address now.
await expect(page.getByRole("combobox", { name: "Street Address (required)" })).toHaveValue(
"1 Market St",
);
await expect(page.getByLabel("City (required)")).toHaveValue("St. Louis");
await expect(page.getByLabel("State (required)")).toHaveValue("MO");
await expect(page.getByLabel("Google Maps URL (optional)")).toHaveCount(0);
await expect(page.getByLabel("Address (optional)")).toHaveCount(0);
await expect(page.getByLabel("Preferred Contact")).toHaveCount(0);
await expect(page.getByLabel("Technician name (optional)")).toHaveCount(1);
await expect(page.getByLabel("Technician name (optional)")).toHaveValue("");
@ -643,9 +649,15 @@ test.describe("Vendor directory prototype parity", () => {
await expect(detailDrawer.getByRole("heading", { name: "Adam Whyte" })).toBeVisible();
await expect(detailDrawer.getByText("Adam Whyte")).toBeVisible();
await expect(detailDrawer.getByText("72")).toBeVisible();
await expect(
detailDrawer.getByRole("link", { name: "Open in Google Maps" }).first(),
).toHaveAttribute("target", "_blank");
// SH-271: the separate "Open in Google Maps" row is gone — the Street
// Address itself is the link, built from the structured parts.
const streetLink = detailDrawer.getByRole("link", { name: "1 Market St" }).first();
await expect(streetLink).toHaveAttribute("target", "_blank");
await expect(streetLink).toHaveAttribute(
"href",
"https://www.google.com/maps/search/?api=1&query=1%20Market%20St%20St.%20Louis%20MO",
);
await expect(detailDrawer.getByRole("link", { name: "Open in Google Maps" })).toHaveCount(0);
await captureVisual(page, "/tmp/seahaven-vendor-implemented-detail.png");
await detailDrawer.getByRole("button", { name: "Edit" }).click();
@ -693,6 +705,12 @@ test.describe("Vendor directory prototype parity", () => {
).toBeEnabled();
await page.getByRole("combobox", { name: "Company (required)" }).fill("Independent Vendor LLC");
await page.getByLabel("Company Phone (optional)").fill("3145550199");
// SH-271 made the structured address required. This test is about keyboard
// dismissal and free-text company creation, so the address is filled to
// leave those as the only things it is exercising.
await page.getByRole("combobox", { name: "Street Address (required)" }).fill("1 Market St");
await page.getByLabel("City (required)").fill("St. Louis");
await page.getByLabel("State (required)").fill("MO");
await page.getByRole("button", { name: "Add Vendor", exact: true }).last().click();
await expect.poll(() => state.createdBody?.name).toBe("Independent Vendor LLC");

View file

@ -70,6 +70,13 @@ async function mockVendorApi(page: Page, mode: "default" | "empty" | "error" = "
await page.clock.setFixedTime(new Date("2026-08-10T12:00:00.000Z"));
await page.addInitScript((user) => localStorage.setItem("auth", JSON.stringify(user)), TEST_USER);
// The vendor address map preview embeds maps.google.com in an iframe. Its
// content depends on the network, on timing, and on whatever Google serves
// that minute, none of which belongs in a test with "deterministic pixel
// regression" in its name. Aborting the request pins the frame to a blank
// box, so the shot measures our layout and nothing else.
await page.route(/https:\/\/(www\.)?google\.com\/maps/, (route) => route.abort());
await page.route("**/api/**", async (route) => {
const request = route.request();
const url = new URL(request.url());