fix(measurements): paint Sys/Dia badge on mobile blood-pressure rows

The mobile card list checked m.type against the short forms BP_SYS /
BP_DIA, which never appear in API payloads — the canonical enum is
BLOOD_PRESSURE_SYS / BLOOD_PRESSURE_DIA. The badge condition was
therefore permanently false and the disambiguation tag never rendered
on Pixel 5. Route the label through MEASUREMENT_TYPE_LABEL_KEYS so the
mobile branch shares the desktop table's single source of truth, and
add a regression test that asserts both labels paint in both branches
under EN and DE.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marc-André BombeckandClaude Opus 4.7 committed 2026-05-10 14:15:56 +02:00
1 parent 14eff96474
commit ef74241a68
2 files changed
+112 -4

No files matched your search

@@ -0,0 +1,109 @@
import { describe, expect, it, vi } from "vitest";
import { renderToStaticMarkup } from "react-dom/server";
/**
* v1.4.19 — Sys/Dia badge enum-mismatch regression guard.
*
* The mobile-list BP-type badge must check the canonical
* `BLOOD_PRESSURE_SYS` / `BLOOD_PRESSURE_DIA` enum values (matching
* `prisma/schema.prisma` and `MEASUREMENT_TYPE_LABEL_KEYS`). An earlier
* implementation checked `BP_SYS` / `BP_DIA` — short forms that never
* appear in the API payload — so the badge silently never painted on
* mobile. The desktop table was unaffected because it routes through
* `MEASUREMENT_TYPE_LABEL_KEYS[m.type]`.
*
* This guard renders the mobile list with one systolic + one diastolic
* row and asserts both labels show up.
*/
const baseMeasurements = [
{
id: "m-sys-1",
type: "BLOOD_PRESSURE_SYS",
value: 117,
unit: "mmHg",
source: "MANUAL",
measuredAt: "2026-05-09T08:30:00.000Z",
notes: null,
},
{
id: "m-dia-1",
type: "BLOOD_PRESSURE_DIA",
value: 78,
unit: "mmHg",
source: "MANUAL",
measuredAt: "2026-05-09T08:30:00.000Z",
notes: null,
},
];
vi.mock("next/navigation", () => ({
useRouter: () => ({ push: vi.fn(), replace: vi.fn() }),
usePathname: () => "/measurements",
}));
vi.mock("@tanstack/react-query", () => ({
useQuery: () => ({
data: { measurements: baseMeasurements, meta: { total: 2 } },
isLoading: false,
}),
useQueryClient: () => ({ invalidateQueries: vi.fn() }),
useMutation: () => ({
mutate: vi.fn(),
mutateAsync: vi.fn(),
isPending: false,
isError: false,
error: null,
}),
}));
vi.mock("@/hooks/use-auth", () => ({
useAuth: () => ({
user: { id: "u1", username: "marc", role: "USER" },
isAuthenticated: true,
isLoading: false,
}),
}));
import { I18nProvider } from "@/lib/i18n/context";
import { MeasurementList } from "../measurement-list";
function render(locale: "en" | "de" = "en") {
return renderToStaticMarkup(
<I18nProvider initialLocale={locale}>
<MeasurementList />
</I18nProvider>,
);
}
function countOccurrences(haystack: string, needle: string): number {
let count = 0;
let idx = 0;
while ((idx = haystack.indexOf(needle, idx)) !== -1) {
count += 1;
idx += needle.length;
}
return count;
}
describe("MeasurementList — Sys/Dia disambiguation badge (mobile list)", () => {
// Both desktop table + mobile card list render in static markup
// (responsive switching is purely CSS), so each label must appear
// twice — once per branch — when the badge is wired correctly.
it("renders the Sys badge in BOTH desktop table and mobile list", () => {
const html = render("en");
expect(countOccurrences(html, ">Sys<")).toBe(2);
});
it("renders the Dia badge in BOTH desktop table and mobile list", () => {
const html = render("en");
expect(countOccurrences(html, ">Dia<")).toBe(2);
});
it("renders Sys + Dia in both branches under the German locale too", () => {
const html = render("de");
expect(countOccurrences(html, ">Sys<")).toBe(2);
expect(countOccurrences(html, ">Dia<")).toBe(2);
});
});
@@ -475,14 +475,13 @@ export function MeasurementList({ onEdit, onAddFirst }: MeasurementListProps) {
</div>
)}
<div className="min-w-0">
{(m.type === "BP_SYS" || m.type === "BP_DIA") && (
{(m.type === "BLOOD_PRESSURE_SYS" ||
m.type === "BLOOD_PRESSURE_DIA") && (
<Badge
variant="outline"
className="mr-1.5 h-5 px-1 text-[10px]"
>
{m.type === "BP_SYS"
? t("measurements.typeBpSys")
: t("measurements.typeBpDia")}
{t(TYPE_LABEL_KEYS[m.type])}
</Badge>
)}
<span className="font-semibold tabular-nums">