diff --git a/e2e/settings-integrations-mobile.spec.ts b/e2e/settings-integrations-mobile.spec.ts index 92397f634..b06f1bb41 100644 --- a/e2e/settings-integrations-mobile.spec.ts +++ b/e2e/settings-integrations-mobile.spec.ts @@ -182,11 +182,13 @@ test.describe("/settings/integrations Pixel-5 layout", () => { fallback.locator('[data-testid="integration-status-pill"]'), ).toHaveAttribute("data-state", "stalled"); - // Card anatomy is uniform now that Nightscout, the OAuth cards and Apple - // Health all carry the divider. + // Card anatomy is uniform because no integration card paints a rule under + // its header any more. The `
` existed only in this folder — nine cards + // carrying a separator no other Settings card has — and the card's own gap + // does the separating now. await expect( page.locator('[data-testid="integration-card-divider"]'), - ).toHaveCount(9); + ).toHaveCount(0); // Withings is connected in this fixture; WHOOP is a BYO-keys card that // stays dormant until an operator adds credentials, so assert the one @@ -251,8 +253,18 @@ test.describe("Apple Health guidance", () => { const card = page.getByTestId("apple-health-card"); await expect(card).toBeVisible(); + // The product name is a proper noun and stays assertable; the sentence + // around it is not. The description SLOT is the stable target — this spec + // is about the card rendering its explainer, not about its wording, and + // the wording is pinned by `apple-health-card.test.tsx` against the same + // i18n bundle it renders from. await expect(card).toContainText("HealthLog iOS app"); - await expect(card).toContainText("not a web or OAuth connection"); + const description = card.locator('[data-slot="settings-card-description"]'); + await expect(description).toBeVisible(); + await expect(description).not.toHaveText(""); + // A raw key means the bundle lookup failed, which is the failure this + // assertion can actually see from a browser. + await expect(description).not.toContainText("settings.appleHealth"); await expect(page.getByTestId("apple-health-status")).toHaveAttribute( "data-state", "pending-setup", diff --git a/src/components/settings/__tests__/one-piece-anatomy.test.tsx b/src/components/settings/__tests__/one-piece-anatomy.test.tsx index fbc6f5918..daaaaafc9 100644 --- a/src/components/settings/__tests__/one-piece-anatomy.test.tsx +++ b/src/components/settings/__tests__/one-piece-anatomy.test.tsx @@ -85,6 +85,16 @@ describe("SettingsCardHeader — one description sentence, one text run", () => const html = render(); expect(html).toMatch(/]*class="text-lg font-semibold"/); }); + + it("names the description slot so a browser test can target it", () => { + // A spec that asserted the sentence's bytes broke on the text diet while + // the thing it was actually about — the card rendering its explainer — + // never changed. This attribute is the stable target that replaced it. + const html = render( + , + ); + expect(html).toContain('data-slot="settings-card-description"'); + }); }); describe("SettingsCardActions — one row, one shape", () => { diff --git a/src/components/settings/_card-header.tsx b/src/components/settings/_card-header.tsx index ee622b7f6..29c04fb95 100644 --- a/src/components/settings/_card-header.tsx +++ b/src/components/settings/_card-header.tsx @@ -94,9 +94,17 @@ export function SettingsCardHeader({ {/* One sentence, one text run. This slot deliberately carries no `space-y-*`: the vertical rhythm was the licence call sites used - to stack explainer paragraphs into a muted `text-xs` slot. */} + to stack explainer paragraphs into a muted `text-xs` slot. + The `data-slot` is what a browser test targets — asserting the + sentence's bytes couples the suite to wording, and a text diet + then breaks specs that were never about the words. */} {description ? ( -
{description}
+
+ {description} +
) : null}