test(share): pin every catalogue leaf to a clinician-view renderer

Eleven leaves stayed invisible for eleven releases because nothing
connected the two lists. The picker-to-aggregator guard was satisfied and
kept being satisfied; the page was not on either end of it.

`DISPOSITIONS` is `Record<StructuredLeafId, …>`, so an eighteenth
structured leaf fails `pnpm typecheck` until someone writes down whether
it renders or why it cannot. Per leaf the suite then renders the real
view over a real fixture and asserts the marker appears; re-renders with
that leaf alone removed from the frozen selection, payload untouched, and
asserts it is gone; and for a refusal, reads the list that enforces it
rather than trusting the note.

Once over the whole set: a carried leaf with nothing behind it says so, a
leaf whose module is off says something else, and a leaf the link never
carried says nothing at all.

The `share-downloads` row is asserted here too. Its test id had zero
references anywhere in the tree, so the two buttons a practice clicks
could have lost a link, pointed at the wrong path, or vanished from a
documents-only share unnoticed.

Break-proofs, each confirmed red then restored: drop a section element
(that leaf's render case); gate `LeafSection` on data instead of scope
(thirteen withholding cases); collapse the switched-off arm (the
distinction case); empty `SHARE_LINK_FORBIDDEN_LEAVES` (the refusal
case); add an eighteenth leaf (typecheck).
This commit is contained in:
Marc-André Bombeck committed 2026-08-24 01:07:14 +02:00
1 parent 7a9aa141a6
commit ac6fd187d6
1 file changed
+561
@@ -0,0 +1,561 @@
/**
* Structural guard: every structured leaf the catalogue declares either
* reaches the clinician view, or has a written, enforced reason why it cannot.
*
* Eleven leaves were selectable on a share link and invisible on the page it
* served. Each of them had a control, a gating path in the aggregator and a
* renderer in the PDF, so `doctor-report-control-gating-guard.test.ts` was
* satisfied and stayed satisfied: it connects the picker to the aggregator,
* and nothing connected either to the page. The two lists sat beside each
* other for eleven releases without a test that could see both.
*
* This file is that connection. It is a pair guard in the same sense: one end
* is `STRUCTURED_LEAF_GROUP`, the other is HTML rendered by the real
* `<ClinicianView>` over a real fixture. It proves four things per leaf.
*
* 1. `DISPOSITIONS` is `Record<StructuredLeafId, …>`, so an eighteenth
* structured leaf cannot be added to the catalogue without deciding here
* whether it renders — and saying so — or `pnpm typecheck` fails. That is
* the lock, and it is the compiler's, not this suite's.
* 2. A leaf marked `rendered` actually renders: its fixture's own marker
* appears in the page HTML.
* 3. Removing exactly that leaf from the frozen selection removes the
* marker, with the payload left untouched. This is the both-ends half —
* a section that reads only "is there data" would pass (2) and fail (3),
* and several did before `LeafScope`.
* 4. A leaf marked `refused` is refused where the disposition says it is,
* by reading `SHARE_LINK_FORBIDDEN_LEAVES` rather than taking the note's
* word for it.
*
* Plus, once over the whole set: a leaf on the link with no data behind it
* says so in words, and one whose module is off says something different. A
* blank card must never be the answer to either.
*
* Mutation checks are recorded per assertion below.
*/
import { describe, it, expect } from "vitest";
import { renderToStaticMarkup } from "react-dom/server";
import { ClinicianView } from "@/components/clinician/clinician-view";
import { getServerTranslator } from "@/lib/i18n/server-translator";
import { computeGlucoseClinicalMetrics } from "@/lib/analytics/glucose-metrics";
import { SHARE_LINK_FORBIDDEN_LEAVES } from "@/lib/validations/clinician-share-link";
import {
ALL_LEAF_IDS,
STRUCTURED_LEAF_IDS,
type ReportLeafId,
type StructuredLeafId,
} from "@/lib/report-selection/catalogue";
import { selectionFromLeaves } from "@/lib/report-selection/selection";
import type { DoctorReportData } from "@/lib/doctor-report-data";
/** The payload floor every fixture starts from: a link that carries nothing. */
function emptyReport(): DoctorReportData {
return {
period: {
days: 30,
since: "2026-01-01T00:00:00.000Z",
start: "2026-01-01T00:00:00.000Z",
end: "2026-01-31T00:00:00.000Z",
},
patient: {
username: null,
dateOfBirth: null,
gender: null,
heightCm: null,
},
practiceName: null,
measurements: {},
stats: {},
glucoseStats: {},
glucoseRanges: {},
glucoseClinical: computeGlucoseClinicalMetrics([], {
now: new Date("2026-01-31T00:00:00.000Z"),
}),
glucoseUnit: "mg/dL",
bmi: null,
compliance: {},
medications: [],
mood: null,
wellnessScores: null,
} as unknown as DoctorReportData;
}
function render(
report: DoctorReportData,
leaves: readonly ReportLeafId[],
unavailableLeaves: readonly ReportLeafId[] = [],
): string {
const { t } = getServerTranslator("en");
return renderToStaticMarkup(
ClinicianView({
t: (key, vars) => t(key, vars),
label: "Clinic",
expiresAt: "2026-03-01T00:00:00.000Z",
report,
selection: selectionFromLeaves(leaves),
unavailableLeaves,
}),
);
}
/**
* Every leaf that has a card on the page, read off the `data-leaf` attributes.
*
* A card can speak for more than one leaf — the medications card carries the
* drug list and the adherence rate together — so the attribute is a
* space-separated list and a substring match on `data-leaf="LEAF"` would miss
* exactly those.
*/
function renderedLeaves(html: string): Set<string> {
const found = new Set<string>();
for (const match of html.matchAll(/data-leaf="([^"]*)"/g)) {
for (const leaf of match[1].split(" ")) {
if (leaf) found.add(leaf);
}
}
return found;
}
/** The markup of the card speaking for `leaf`, or "" when there is none. */
function cardFor(html: string, leaf: string): string {
for (const match of html.matchAll(
/<section data-leaf="([^"]*)"[\s\S]*?<\/section>/g,
)) {
if (match[1].split(" ").includes(leaf)) return match[0];
}
return "";
}
type Disposition =
| {
kind: "rendered";
/** Payload that gives this leaf something to show. */
data: Partial<DoctorReportData>;
/** A string the page carries only when this leaf rendered. */
marker: string;
}
| {
kind: "refused";
/** Why no renderer exists. Asserted, not trusted — see the suite below. */
reason: string;
};
/**
* Every structured leaf, and what the clinician view does with it.
*
* `Record<StructuredLeafId, …>` is exhaustive over the closed union by the
* compiler, mirroring how `STRUCTURED_LEAF_GROUP` forces a group decision in
* the same commit as a new leaf. Adding one here is the same shape of work:
* name the fixture and the marker, or name the refusal.
*/
const DISPOSITIONS: Record<StructuredLeafId, Disposition> = {
PATIENT_IDENTITY: {
kind: "rendered",
data: {
patient: {
username: "shared-account",
dateOfBirth: "1979-04-02T00:00:00.000Z",
gender: "FEMALE",
heightCm: 171,
fullName: "A. Patient",
},
},
marker: "A. Patient",
},
EMERGENCY: {
kind: "rendered",
data: {
emergency: {
bloodType: "O_NEG",
organDonor: "YES",
advanceDirective: "EXISTS",
contacts: "Next of kin, 555 0100",
contactsUnreadable: false,
implants: "Pacemaker, fitted 2021",
implantsUnreadable: false,
note: null,
noteUnreadable: false,
},
},
marker: "Pacemaker, fitted 2021",
},
INSURANCE: {
kind: "refused",
reason:
"Refused at share-link creation by SHARE_LINK_FORBIDDEN_LEAVES, so no " +
"link can carry the leaf and the aggregator never fills the insurer " +
"fields. A renderer here would be a path to a decision already made.",
},
GLUCOSE_PANEL: {
kind: "rendered",
data: {
glucoseStats: {
FASTING: { avg: 96, min: 88, max: 104, count: 21, latest: 94 },
},
},
marker: "Glucose (fasting)",
},
LAB_RESULTS: {
kind: "rendered",
data: {
labResults: [
{
panel: null,
analyte: "Ferritin",
value: 42,
valueText: null,
unit: "ng/mL",
referenceLow: 30,
referenceHigh: 400,
catalogReferenceLow: 30,
catalogReferenceHigh: 400,
sourceReferenceText: null,
referenceOrigin: "catalog",
referenceDivergesFromCatalog: false,
takenAt: "2026-01-20T09:00:00.000Z",
count: 1,
},
],
},
marker: "Ferritin",
},
MEDICATION_LIST: {
kind: "rendered",
data: {
medications: [{ name: "Ramipril", dose: "5 mg", schedules: [] }],
},
marker: "Ramipril",
},
MEDICATION_ADMINISTRATIONS: {
kind: "rendered",
data: {
medicationAdministrations: [
{
medicationName: "Ramipril",
effectiveAt: "2026-01-30T07:10:00.000Z",
status: "completed",
doseText: "5 mg",
dose: null,
injectionSite: null,
atcCode: null,
rxNormCode: null,
deliveryForm: "ORAL",
},
],
},
marker: "Logged doses",
},
MEDICATION_COMPLIANCE: {
kind: "rendered",
data: {
compliance: {
Metformin: { total: 60, taken: 57, skipped: 1, missed: 2 },
},
},
marker: "Metformin",
},
GLP1_THERAPY: {
kind: "rendered",
data: {
glp1: {
medications: [
{
name: "Semaglutide",
currentDose: {
value: 1,
unit: "mg",
since: "2026-01-05T00:00:00.000Z",
},
doseHistory: [],
lastInjection: null,
compliance: { taken: 4, total: 4 },
},
],
weightDeltaKg: null,
weightStartKg: null,
weightEndKg: null,
sideEffects: [],
},
},
marker: "Semaglutide",
},
ALLERGIES: {
kind: "rendered",
data: {
allergies: [
{
substance: "Penicillin",
category: "MEDICATION",
type: "ALLERGY",
severity: "SEVERE",
status: "ACTIVE",
reaction: null,
reactionUnreadable: false,
},
],
},
marker: "Penicillin",
},
ILLNESS_EPISODES: {
kind: "rendered",
data: {
illnessEpisodes: [
{
label: "Sinusitis",
type: "INFECTION",
lifecycle: "ACUTE",
onsetAt: "2026-01-08T00:00:00.000Z",
resolvedAt: "2026-01-19T00:00:00.000Z",
},
],
},
marker: "Sinusitis",
},
VISITS: {
kind: "rendered",
data: {
visits: [
{
occurredAt: "2026-01-14T08:30:00.000Z",
kind: "SPECIALIST",
status: "DONE",
practitionerName: "Cardiology outpatients",
practitionerSpecialty: null,
reason: "Palpitations",
outcome: null,
conditionLabels: [],
},
],
},
marker: "Palpitations",
},
IMMUNIZATIONS: {
kind: "rendered",
data: {
immunizations: [
{
occurredAt: "2025-11-03T00:00:00.000Z",
antigenSlug: null,
vaccineName: "Seasonal influenza",
lotNumber: "LOT-7781",
site: null,
practitionerName: null,
series: [],
},
],
},
marker: "Seasonal influenza",
},
FAMILY_HISTORY: {
kind: "rendered",
data: {
familyHistory: [
{
relationship: "MOTHER",
condition: "Type 2 diabetes",
ageAtOnset: 54,
},
],
},
marker: "Type 2 diabetes",
},
MOOD: {
kind: "rendered",
data: {
mood: {
avg: 3.4,
min: 2,
max: 5,
count: 22,
distribution: { 1: 0, 2: 3, 3: 9, 4: 7, 5: 3 },
},
},
marker: "Mood trajectory",
},
CYCLE: {
kind: "rendered",
data: {
cycle: {
lastPeriodStart: "2026-01-09",
recentCycles: [
{ startDate: "2026-01-09", lengthDays: 29, periodLengthDays: 5 },
],
observedCycleCount: 1,
averageCycleLengthDays: 29,
cycleLengthVariabilityDays: null,
averagePeriodLengthDays: 5,
currentPhase: "LUTEAL",
},
},
marker: "Menstrual cycle",
},
ANAMNESIS: {
kind: "rendered",
data: {
anamnesis: {
conditions: "Hypothyroidism",
conditionsUnreadable: false,
smokingStatus: null,
alcoholPattern: null,
shiftSchedule: null,
unreadableFacts: [],
},
},
marker: "Hypothyroidism",
},
};
const RENDERED = STRUCTURED_LEAF_IDS.filter(
(leaf) => DISPOSITIONS[leaf].kind === "rendered",
);
const REFUSED = STRUCTURED_LEAF_IDS.filter(
(leaf) => DISPOSITIONS[leaf].kind === "refused",
);
describe("clinician view — every catalogue leaf has a renderer or a reason", () => {
it("reads a plausible catalogue", () => {
// Sanity floor: a degraded import would satisfy every loop below
// vacuously, which is the failure mode a pair guard dies of.
expect(STRUCTURED_LEAF_IDS).toHaveLength(17);
expect(Object.keys(DISPOSITIONS).sort()).toEqual(
[...STRUCTURED_LEAF_IDS].sort(),
);
expect(RENDERED.length).toBeGreaterThan(0);
});
it("enforces every refusal where the disposition says it lives", () => {
// Mutation: change INSURANCE to `rendered` and this fails on the count;
// remove it from SHARE_LINK_FORBIDDEN_LEAVES and it fails on membership.
expect(REFUSED).toEqual(["INSURANCE"]);
for (const leaf of REFUSED) {
expect(
(SHARE_LINK_FORBIDDEN_LEAVES as readonly string[]).includes(leaf),
`${leaf} claims to be refused at share-link creation but is not on ` +
"SHARE_LINK_FORBIDDEN_LEAVES, so a link can carry it and nothing " +
"will render it",
).toBe(true);
}
});
for (const leaf of RENDERED) {
const disposition = DISPOSITIONS[leaf];
if (disposition.kind !== "rendered") continue;
it(`renders ${leaf} when the link carries it`, () => {
// Mutation: drop the section's element from `<ClinicianView>` and this
// goes red for that leaf alone.
const html = render(
{ ...emptyReport(), ...disposition.data },
ALL_LEAF_IDS,
);
expect(html).toContain(disposition.marker);
});
it(`withholds ${leaf} when the link does not carry it`, () => {
// The payload is IDENTICAL; only the frozen selection changes. Mutation:
// gate the section on its data rather than on the scope and this goes
// red while the test above stays green.
const html = render(
{ ...emptyReport(), ...disposition.data },
ALL_LEAF_IDS.filter((id) => id !== leaf),
);
expect(html).not.toContain(disposition.marker);
expect(renderedLeaves(html).has(leaf)).toBe(false);
});
}
});
describe("clinician view — an absence names itself", () => {
const EMPTY_COPY = "Included in this link, but nothing is recorded here.";
const OFF_COPY = "switched off in the account it comes from";
it("says so for every rendered leaf carried with nothing behind it", () => {
// One render with everything selected and an empty payload: each card is
// present and each says why it is blank. Mutation: return null from
// `LeafSection` on `empty` and every one of these goes red.
const html = render(emptyReport(), ALL_LEAF_IDS);
const present = renderedLeaves(html);
for (const leaf of RENDERED) {
expect(present.has(leaf), `${leaf} renders no card at all`).toBe(true);
expect(cardFor(html, leaf), `${leaf} renders a blank card`).toContain(
EMPTY_COPY,
);
}
});
it("says something DIFFERENT when the owner's module is off", () => {
// The distinction the payload cannot carry: shared-and-empty against
// shared-and-switched-off. Mutation: drop the `unavailable` arm of
// `LeafSection` and the two collapse into one sentence.
const html = render(emptyReport(), ALL_LEAF_IDS, ["LAB_RESULTS"]);
expect(cardFor(html, "LAB_RESULTS")).toContain(OFF_COPY);
expect(cardFor(html, "LAB_RESULTS")).not.toContain(EMPTY_COPY);
// And it is not the blanket answer: a leaf whose module is on still gets
// the empty sentence.
expect(cardFor(html, "MOOD")).toContain(EMPTY_COPY);
expect(cardFor(html, "MOOD")).not.toContain(OFF_COPY);
});
it("renders nothing at all for a leaf the link never carried", () => {
// The third state, and the one that must stay silent: no card, no
// sentence, no acknowledgement that the leaf exists.
const html = render(emptyReport(), ["WEIGHT"]);
const present = renderedLeaves(html);
for (const leaf of STRUCTURED_LEAF_IDS) {
expect(
present.has(leaf),
`${leaf} is announced on a link that withheld it`,
).toBe(false);
}
expect(html).not.toContain(EMPTY_COPY);
expect(html).not.toContain(OFF_COPY);
});
});
describe("clinician view — the machine-format downloads", () => {
// `data-testid="share-downloads"` had zero references anywhere in the tree:
// the two buttons a practice actually clicks were unasserted, so the row
// could have lost a link, pointed at the wrong path, or stopped rendering
// for a documents-only share without a single test noticing.
function renderWithToken(token: string, documentOnly = false): string {
const { t } = getServerTranslator("en");
return renderToStaticMarkup(
ClinicianView({
t: (key, vars) => t(key, vars),
label: "Clinic",
expiresAt: "2026-03-01T00:00:00.000Z",
report: documentOnly ? null : emptyReport(),
selection: selectionFromLeaves(["WEIGHT"]),
documentOnly,
token,
}),
);
}
it("offers both formats, scoped to the link's own token", () => {
const html = renderWithToken("hls_abc");
expect(html).toContain('data-testid="share-downloads"');
expect(html).toContain('href="/c/hls_abc/report.pdf"');
expect(html).toContain('href="/c/hls_abc/fhir"');
expect(html).toContain("Download as PDF");
expect(html).toContain("Download as FHIR");
});
it("percent-encodes the token into the download hrefs", () => {
// The token reaches the DOM as a URL segment; it is server-minted hex
// today, and the encoding is what keeps that from being load-bearing.
expect(renderWithToken("hls_a/b?c")).toContain(
'href="/c/hls_a%2Fb%3Fc/report.pdf"',
);
});
it("offers no download on a documents-only link", () => {
// There is no record behind such a link — both routes answer the same
// flat 404 — so a button that produced one would be a lie in the markup.
const html = renderWithToken("hls_abc", true);
expect(html).not.toContain('data-testid="share-downloads"');
expect(html).not.toContain("/report.pdf");
expect(html).not.toContain("/fhir");
});
});