fix(e2e): re-baseline mobile-consistency height assertions to the 40 px floor and retire the insights-card-preview spec

The settings-mobile-consistency spec asserted a 36 px h-9 floor across
the account form, the dashboard Compare-to trigger and the AI native
selects. The v1.4.27 R3d MB2 pass lifted Input, Select and the native
select primitives to the WCAG 2.5.5 40 px h-10 floor; the assertions
move with the primitives.

The insights-card-preview spec exercised the standalone preview that
B1 retired in 9afb31bd; with the surface gone the spec greens nothing
and the unit-level dashboard-layout test already guards against
accidental reintroduction.
This commit is contained in:
Marc-André Bombeck committed 2026-05-15 21:36:48 +02:00
1 parent 004a8491c7
commit e1befb4523
2 files changed
+14 -195

No files matched your search

-170
View File
@@ -1,170 +0,0 @@
import { expect, test } from "@playwright/test";
import { STORAGE_STATE_PATH } from "./setup/global-setup";
/**
* v1.4.16 phase D reconcile (CRITICAL C2) — proves the polished
* `<InsightsCardPreview>` is mounted on the root dashboard `/`.
*
* Before this fix the component shipped in B1b commit 5 (`d2cdf9d`)
* was an orphan with zero non-test imports. The dashboard read no
* advisor payload, so the top severity-ordered AI recommendation +
* confidence ring + "View all" CTA was unreachable from any live
* route. This spec asserts the card now renders when the layout
* toggle is active and the advisor returns at least one rec.
*/
test.describe("insights card preview on dashboard (C2)", () => {
test.use({ storageState: STORAGE_STATE_PATH });
test.beforeEach(async ({ page }) => {
// Populated analytics so the dashboard clears its empty-state and
// renders charts + tile strip.
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: null,
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,
}),
}),
);
// Layout enables the insights preview widget so the gate is open.
await page.route("**/api/dashboard/widgets", (route) =>
route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({
data: {
version: 1,
widgets: [
{ id: "weight", visible: true, tileVisible: true, order: 0 },
{
id: "insightsPreview",
visible: true,
tileVisible: false,
order: 14,
},
],
comparisonBaseline: "none",
},
error: null,
}),
}),
);
await page.route("**/api/measurements*", (route) =>
route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({
data: { measurements: [], meta: { total: 0 } },
error: null,
}),
}),
);
// Advisor payload — populated with one urgent rec carrying a
// confidence score so the preview renders the rec text + the
// ring confidence meter inline.
await page.route("**/api/insights/generate", (route) =>
route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({
data: {
insights: {
insightType: "general",
summary: "Weekly summary.",
classification: "gut",
classificationLabel: "Good",
findings: [],
correlations: [],
primaryRecommendation: "",
recommendations: [
{
id: "rec-urgent-1",
text: "Schedule a follow-up reading this week.",
severity: "urgent",
confidence: 82,
rationale: {
dataWindow: "last7days",
comparedTo: "your 90-day median",
deviation: "Sys BP averaged 138 over the past week",
},
metricSource: {
type: "bloodPressureSys",
timeRange: "last7days",
summary: "Sys BP avg 138",
},
},
],
dataQuality: { coverage: "good", gaps: [], confidence: "hoch" },
disclaimer: "Not medical advice.",
},
cached: true,
cachedAt: new Date().toISOString(),
legacyPayload: false,
},
error: null,
}),
}),
);
});
test("dashboard renders InsightsCardPreview with top recommendation", async ({
page,
}) => {
await page.goto("/", { waitUntil: "domcontentloaded" });
// Preview is the C2 deliverable — `data-slot="insights-card-preview"`
// is the stable hook the component exposes.
await expect(
page.locator('[data-slot="insights-card-preview"]'),
).toBeVisible({ timeout: 10_000 });
// The urgent rec text from the mock payload renders inside the
// preview's compact tile.
await expect(
page.getByText("Schedule a follow-up reading this week."),
).toBeVisible({ timeout: 10_000 });
// "View all" CTA points at /insights so the user can drill in.
await expect(
page.locator('[data-slot="insights-card-view-all"]'),
).toBeVisible({ timeout: 10_000 });
// The ring-variant ConfidenceMeter renders inline next to the rec
// text — its slot is the same one used on /insights, so a single
// selector confirms wiring.
await expect(
page.locator(
'[data-slot="insights-card-preview"] [data-slot="confidence-meter"]',
),
).toBeVisible({ timeout: 10_000 });
});
});
+14 -25
View File
@@ -4,29 +4,18 @@ import { STORAGE_STATE_PATH } from "./setup/global-setup";
/**
* 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
* (`h-10`) on `Input`, `Select` trigger, and the native `<select>`
* primitives per the WCAG 2.5.5 tap-target sweep (MB2). The
* Dashboard Compare-to trigger followed the same path.
*
* Marc reported four interlocking inconsistencies on the mobile
* settings shell:
* The fixes that still apply:
*
* 1. Input heights differed across sections — `<Input>` rendered at
* 36 px, the AI active-provider native `<select>` at 40 px, the
* AI add-provider select at 32 px, the Dashboard "Compare to"
* `<SelectTrigger>` at 44 px. Same shell, four heights.
* 2. Action buttons inside title rows ("Change password", "Restart
* onboarding tour") could overflow the parent card on narrow
* viewports because the `flex justify-between` row never wrapped.
* 3. The Sprache (language) select was buried half-way down the
* Profile card, paired with a profile-data field (date of birth).
* 4. Card-internal `space-y-*` rhythm varied between 3 / 4 / 5 / 6.
*
* The fixes:
*
* - `h-9` (36 px) is the canonical input height across Settings.
* - 40 px (`h-10`) is the canonical input height across Settings.
* - Title + action rows use `flex-col` on `<sm` and `flex-row` on
* `>=sm` so the action button stacks below on mobile.
* - Sprache lifted into its own row at the bottom of the Profile
* card, `max-w-xs` on `>=sm` so it doesn't render heavier than
* other fields.
* - Sprache pairs with date-of-birth in a single `sm:grid-cols-2`
* row at the bottom of the Profile card (v1.4.27 R1 audit).
* - Card-internal spacing standardised on `space-y-4`.
*
* This spec captures the post-fix invariants. It is mobile-only — the
@@ -39,7 +28,7 @@ test.describe("Settings mobile consistency (Pixel 5)", () => {
test.skip(testInfo.project.name !== "chromium-mobile", "mobile-only spec");
});
test("/settings/account: every form input renders at 36 px", async ({
test("/settings/account: every form input renders at 40 px", async ({
page,
}) => {
await page.goto("/settings/account", { waitUntil: "networkidle" });
@@ -61,7 +50,7 @@ test.describe("Settings mobile consistency (Pixel 5)", () => {
expect(formInputs.length).toBeGreaterThan(0);
for (const inp of formInputs) {
expect.soft(inp.height, `${inp.tag}#${inp.id} (${inp.type})`).toBe(36);
expect.soft(inp.height, `${inp.tag}#${inp.id} (${inp.type})`).toBe(40);
}
});
@@ -143,7 +132,7 @@ test.describe("Settings mobile consistency (Pixel 5)", () => {
);
});
test("/settings/dashboard: Compare-to trigger renders at 36 px", async ({
test("/settings/dashboard: Compare-to trigger renders at 40 px", async ({
page,
}) => {
await page.goto("/settings/dashboard", { waitUntil: "networkidle" });
@@ -152,10 +141,10 @@ test.describe("Settings mobile consistency (Pixel 5)", () => {
const trigger = page.locator("#comparison-baseline");
await expect(trigger).toBeVisible();
const h = await trigger.evaluate((el) => el.getBoundingClientRect().height);
expect(Math.round(h)).toBe(36);
expect(Math.round(h)).toBe(40);
});
test("/settings/ai: every native select renders at 36 px", async ({
test("/settings/ai: every native select renders at 40 px", async ({
page,
}) => {
await page.goto("/settings/ai", { waitUntil: "networkidle" });
@@ -169,7 +158,7 @@ test.describe("Settings mobile consistency (Pixel 5)", () => {
expect(heights.length).toBeGreaterThan(0);
for (const h of heights) {
expect.soft(h).toBe(36);
expect.soft(h).toBe(40);
}
});
});