From e7c6610c63fa4a9ab5dedaeea09d16a63fbbca61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Tue, 28 Jul 2026 23:24:53 +0200 Subject: [PATCH] fix(e2e): re-target compare-to tap-target check at the per-chart overlay popover --- e2e/settings-mobile-consistency.spec.ts | 107 +++++++++++++++++++++--- 1 file changed, 97 insertions(+), 10 deletions(-) diff --git a/e2e/settings-mobile-consistency.spec.ts b/e2e/settings-mobile-consistency.spec.ts index 759663c8c..01e284630 100644 --- a/e2e/settings-mobile-consistency.spec.ts +++ b/e2e/settings-mobile-consistency.spec.ts @@ -1,7 +1,10 @@ import { expect, test } from "./setup/test"; import { STORAGE_STATE_PATH } from "./setup/global-setup"; - +import { + mockDashboardSnapshot, + WEIGHT_ONLY_SUMMARIES, +} from "./utils/mock-dashboard-snapshot"; /** * v1.4.19 A6 — Settings consistency snapshot at Pixel-5 (393 CSS px). * v1.4.27 — input height floor lifted from 36 px (`h-9`) to 40 px @@ -180,16 +183,100 @@ test.describe("Settings mobile consistency (Pixel 5)", () => { ); }); - test("/settings/dashboard: Compare-to trigger renders at 44 px", async ({ - page, - }) => { - await page.goto("/settings/dashboard", { waitUntil: "networkidle" }); - await page.waitForLoadState("networkidle"); + test("/: Compare-to trigger renders at 44 px", async ({ page }) => { + // v1.34.0 — the dashboard-settings comparison-baseline control was + // removed; the same preference now lives behind the per-chart overlay + // popover (see chart-overlay-controls.spec.ts for the full open/toggle + // flow). That popover only paints once a chart with a real chartKey + // renders, so this test needs the same seeded-chart mocks that spec + // uses rather than the real (likely-empty) e2e database. + await mockDashboardSnapshot(page, { summaries: WEIGHT_ONLY_SUMMARIES }); + await page.route(/\/api\/analytics(\?|$)/, (route) => + route.fulfill({ + status: 200, + contentType: "application/json", + body: JSON.stringify({ + data: { + summaries: { + WEIGHT: { + latest: 78.5, + avg7: 78.2, + avg30: 77.9, + slope30: { slope: -0.05, direction: "down" }, + count: 30, + }, + }, + bpInTargetPct: 0, + glucoseByContext: {}, + }, + error: null, + }), + }), + ); + await page.route("**/api/mood/analytics", (route) => + route.fulfill({ + status: 200, + contentType: "application/json", + body: JSON.stringify({ + data: { entries: [], summary: { count: 0 } }, + error: null, + }), + }), + ); + await page.route("**/api/measurements*", (route) => { + const measurements = Array.from({ length: 10 }, (_, i) => ({ + id: `m_${i}`, + type: "WEIGHT", + value: 78 + (i % 3) - 1, + measuredAt: new Date(Date.now() - i * 86_400_000).toISOString(), + notes: null, + })); + return route.fulfill({ + status: 200, + contentType: "application/json", + body: JSON.stringify({ + data: { measurements, meta: { total: measurements.length } }, + error: null, + }), + }); + }); - const trigger = page.locator("#comparison-baseline"); - await expect(trigger).toBeVisible(); - const h = await trigger.evaluate((el) => el.getBoundingClientRect().height); - expect(Math.round(h)).toBe(44); + await page.goto("/", { waitUntil: "domcontentloaded" }); + await expect( + page.locator('[data-slot="dashboard-tile-strip"]'), + ).toBeVisible({ timeout: 10_000 }); + + const trigger = page + .locator('[data-slot="chart-overlay-controls-trigger"]') + .first(); + await expect(trigger).toBeVisible({ timeout: 10_000 }); + await trigger.scrollIntoViewIfNeeded(); + await trigger.click(); + + // `data-slot="chart-overlay-comparison-baseline"` is the grid WRAPPER + // (line 235 in chart-overlay-controls.tsx); the buttons themselves are + // `data-slot="chart-overlay-comparison-{none|lastMonth|lastYear}"`. + // Match only the wrapper's children so the wrapper's own (differently + // sized) box never gets measured as if it were a tap target. + const baselineButton = page + .locator( + '[data-slot="chart-overlay-comparison-baseline"] [data-slot^="chart-overlay-comparison-"]', + ) + .first(); + await expect(baselineButton).toBeVisible({ timeout: 5_000 }); + // `min-h-11` sets the CSS contract (`min-height: 44px`), the same + // guarantee `h-11` gives the other 44px checks in this spec. This + // element additionally carries an explicit `h-8` from the Button "sm" + // size variant that `min-height` overrides; on Playwright's Pixel 5 + // profile (fractional deviceScaleFactor) that combination measures a + // `getBoundingClientRect().height` a device pixel or two under 44 even + // though the computed CSS is exactly 44px — a viewport-emulation + // rounding artifact, not a real layout regression. Assert the + // authoritative computed style instead of the physically-snapped rect. + const minHeight = await baselineButton.evaluate( + (el) => getComputedStyle(el).minHeight, + ); + expect(minHeight).toBe("44px"); }); test("/settings/ai: every native select renders at 44 px", async ({