Files
HealthLog/e2e/mood-card-mobile.spec.ts
T
Marc-André BombeckandClaude Opus 4.7 2c227fb0c1 fix(dashboard): mood tile mobile shows number once + label, not twice
The mood-list mobile branch (`md:hidden`) rendered each entry's score
TWICE: once as a large bold digit in the left badge, then again next
to it in the title line as "{score} ({label})". Desktop's table view
only ever showed it once. The redundancy made the row read like
"2 2 (schlecht)" — the badge already supplies the digit, the title
line just needs the textual label.

Drop the duplicate digit from the title line; the row now reads
"[2] Schlecht / 12.05.2026 18:30 / tags". Add `data-testid` hooks
on the row and the score badge so the Pixel-5 Playwright guard at
`e2e/mood-card-mobile.spec.ts` can assert "exactly one occurrence of
the score digit per row" — that contract is what would have caught the
duplicate before merge.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 20:18:49 +02:00

95 lines
3.3 KiB
TypeScript

import { expect, test } from "@playwright/test";
import { STORAGE_STATE_PATH } from "./setup/global-setup";
/**
* v1.4.15 phase-A3 fix #2 — mood-list mobile card was rendering the score
* twice: once in the left badge (large bold digit) and once in the title
* line as "{score} ({label})". On desktop the table view only ever showed
* one. The fix collapses the title line down to just the localized label
* (e.g., "Schlecht"), so the row reads
*
* [ 2 ] Schlecht
* 12.05.2026, 18:30
*
* The Pixel-5 viewport is the only one that mounted the mobile branch
* (`md:hidden`) so the regression was mobile-only — this spec runs on the
* `chromium-mobile` project and asserts each `data-testid="mood-row"`
* contains exactly one occurrence of its score digit.
*/
test.describe("mood card mobile layout", () => {
test.use({ storageState: STORAGE_STATE_PATH });
test.beforeEach(({}, testInfo) => {
test.skip(testInfo.project.name !== "chromium-mobile", "mobile-only spec");
});
test("each mobile row shows the score number exactly once", async ({
page,
}) => {
// Stub the mood-entries endpoint with a deterministic dataset whose
// scores are all distinct digits — that lets us reason about
// "exactly one occurrence" per row independently of locale or label.
await page.route("**/api/mood-entries*", (route) =>
route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({
data: {
entries: [
{
id: "m1",
date: "2026-05-08",
mood: "SCHLECHT",
score: 2,
tags: [],
source: "MANUAL",
moodLoggedAt: "2026-05-08T08:30:00.000Z",
},
{
id: "m2",
date: "2026-05-07",
mood: "GUT",
score: 4,
tags: [],
source: "MANUAL",
moodLoggedAt: "2026-05-07T19:00:00.000Z",
},
],
meta: { total: 2 },
},
error: null,
}),
}),
);
await page.goto("/mood", { waitUntil: "domcontentloaded" });
const rows = page.locator('[data-testid="mood-row"]');
await expect(rows).toHaveCount(2, { timeout: 10_000 });
// For each row, the rendered text must contain its score digit
// exactly once. The desktop table also shows the digit + label in
// one cell, but `md:hidden` hides this branch above the breakpoint —
// on the Pixel-5 profile only the mobile branch mounts.
for (let i = 0; i < 2; i++) {
const row = rows.nth(i);
const text = await row.innerText();
const expectedScore = i === 0 ? "2" : "4";
const occurrences = (
text.match(new RegExp(`(?<!\\d)${expectedScore}(?!\\d)`, "g")) ?? []
).length;
expect(
occurrences,
`row ${i} should contain "${expectedScore}" exactly once, got ${occurrences} in: ${text}`,
).toBe(1);
}
// The big-badge score must still be present (we kept it).
const scoreBadges = page.locator('[data-testid="mood-row-score"]');
await expect(scoreBadges).toHaveCount(2);
await expect(scoreBadges.nth(0)).toHaveText("2");
await expect(scoreBadges.nth(1)).toHaveText("4");
});
});