mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 13:01:00 +00:00
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:
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">
|
||||
|
||||
Reference in new issue
Block a user