From fcd3dd2d0789f8d5834d6b5033042199a1ef7b27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Sat, 25 Jul 2026 19:57:31 +0200 Subject: [PATCH] fix(export): make each scope-picker mount addressable on its own MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Settings → Gesundheitsakte mounts the one scope picker twice: the export panel at the top, the share-link create form under `#sharing`. Sharing the component is deliberate, but it also meant every test id inside it resolved to two elements on that page, so nothing in the picker could be addressed without guessing which one you got. The picker now takes a required `surface` and every id under it ends with that surface — `report-group-row-vitals-export` and `report-group-row-vitals-share` are two controls and read as two controls. The summary line beside each picker follows the same rule. A third mount picks a value and stays addressable by construction. --- .../__tests__/report-selection-panel.test.tsx | 18 +++++++++++------- .../__tests__/sharing-reselect.test.tsx | 12 ++++++------ .../settings/report-selection/group-row.tsx | 11 +++++++++-- .../settings/report-selection/leaf-grid.tsx | 9 +++++++-- .../report-selection/report-scope-picker.tsx | 17 +++++++++++++++-- .../report-selection/scope-summary.tsx | 10 ++++++++-- .../report-selection/selection-panel.tsx | 8 ++++++-- .../settings/report-selection/surface.ts | 16 ++++++++++++++++ .../settings/share-link-create-form.tsx | 3 ++- 9 files changed, 80 insertions(+), 24 deletions(-) create mode 100644 src/components/settings/report-selection/surface.ts diff --git a/src/components/settings/__tests__/report-selection-panel.test.tsx b/src/components/settings/__tests__/report-selection-panel.test.tsx index 830e1762d..3484046ff 100644 --- a/src/components/settings/__tests__/report-selection-panel.test.tsx +++ b/src/components/settings/__tests__/report-selection-panel.test.tsx @@ -95,7 +95,7 @@ function withSavedSelection(user: AuthUser, leaves: string[]): AuthUser { */ function leafChecked(html: string, leaf: string): boolean { const row = html.match( - new RegExp(`data-testid="report-leaf-${leaf}"[\\s\\S]*?`), + new RegExp(`data-testid="report-leaf-${leaf}-export"[\\s\\S]*?`), )?.[0]; if (!row) return false; return /data-state="checked"/.test(row); @@ -104,7 +104,9 @@ function leafChecked(html: string, leaf: string): boolean { /** The "n/total" chip a collapsed group row carries. */ function groupChip(html: string, group: string): string | null { const row = html.match( - new RegExp(`data-testid="report-group-row-${group}"[\\s\\S]*?`), + new RegExp( + `data-testid="report-group-row-${group}-export"[\\s\\S]*?`, + ), )?.[0]; return row?.match(/data-slot="tag-chip"[^>]*>([^<]*) — the first run", () => { it("opens the picker expanded and names the template it applied", () => { const html = renderPanel(buildUser(null)); expect(html).toContain('data-testid="health-record-included-data-panel"'); - expect(html).toContain('data-testid="report-scope-picker"'); + expect(html).toContain('data-testid="report-scope-picker-export"'); expect(html).toContain("Standard doctor's report"); }); @@ -169,7 +171,7 @@ describe(" — the first run", () => { it("leaves every fenced leaf unchecked and renders the tier", () => { const html = renderPanel(buildUser(null)); - expect(html).toContain('data-testid="report-sensitive-tier"'); + expect(html).toContain('data-testid="report-sensitive-tier-export"'); for (const leaf of [ "MOOD", "CYCLE", @@ -185,13 +187,15 @@ describe(" — the first run", () => { it("gives the fenced tier no group checkbox", () => { const html = renderPanel(buildUser(null)); - expect(html).toContain('data-testid="report-group-check-vitals"'); - expect(html).not.toContain('data-testid="report-group-check-sensitive"'); + expect(html).toContain('data-testid="report-group-check-vitals-export"'); + expect(html).not.toContain( + 'data-testid="report-group-check-sensitive-export"', + ); }); it("states the scope in one line", () => { const html = renderPanel(buildUser(null)); - expect(html).toContain('data-testid="report-scope-summary"'); + expect(html).toContain('data-testid="report-scope-summary-export"'); expect(html).toContain("14 entries from 7 areas"); }); }); diff --git a/src/components/settings/__tests__/sharing-reselect.test.tsx b/src/components/settings/__tests__/sharing-reselect.test.tsx index d4bd1da15..aa1e206b4 100644 --- a/src/components/settings/__tests__/sharing-reselect.test.tsx +++ b/src/components/settings/__tests__/sharing-reselect.test.tsx @@ -60,23 +60,23 @@ describe("share-link create form — re-mint seeding", () => { it("offers the scope picker, with the insurance leaf absent from it", () => { const html = render(); - expect(html).toContain('data-testid="report-scope-picker"'); - expect(html).toContain('data-testid="report-group-row-identity"'); + expect(html).toContain('data-testid="report-scope-picker-share"'); + expect(html).toContain('data-testid="report-group-row-identity-share"'); // The server refuses the leaf with a 422; a control that cannot be // honoured has no business rendering, so the identity group is one leaf // wide here and two wide in the export panel. const row = html.match( - /data-testid="report-group-row-identity"[\s\S]*?<\/div>/, + /data-testid="report-group-row-identity-share"[\s\S]*?<\/div>/, )?.[0]; expect(row).toBeDefined(); expect(row).toContain(">1/1<"); // The fenced tier renders its leaves unconditionally; none is checked. - expect(html).toContain('data-testid="report-leaf-MOOD"'); - expect(html).not.toContain('data-testid="report-leaf-INSURANCE"'); + expect(html).toContain('data-testid="report-leaf-MOOD-share"'); + expect(html).not.toContain('data-testid="report-leaf-INSURANCE-share"'); }); it("hides the scope picker entirely for a documents-only share", () => { const html = render(); - expect(html).not.toContain('data-testid="report-scope-picker"'); + expect(html).not.toContain('data-testid="report-scope-picker-share"'); }); }); diff --git a/src/components/settings/report-selection/group-row.tsx b/src/components/settings/report-selection/group-row.tsx index a20cf0df2..c1a68d902 100644 --- a/src/components/settings/report-selection/group-row.tsx +++ b/src/components/settings/report-selection/group-row.tsx @@ -25,9 +25,11 @@ import type { import type { GroupCheckState } from "@/lib/report-selection/panel-state"; import { LeafGrid } from "./leaf-grid"; +import type { ReportScopeSurface } from "./surface"; export function GroupRow({ t, + surface, id, labelKey, leaves, @@ -41,6 +43,7 @@ export function GroupRow({ onToggleOpen, }: { t: (key: string, vars?: Record) => string; + surface: ReportScopeSurface; id: ReportGroupId; labelKey: string; leaves: readonly ReportLeafId[]; @@ -55,7 +58,10 @@ export function GroupRow({ }) { const label = t(labelKey); return ( - +
{label} @@ -94,6 +100,7 @@ export function GroupRow({
) => string; + surface: ReportScopeSurface; leaves: readonly ReportLeafId[]; selected: ReadonlySet; onToggle: (leaf: ReportLeafId) => void; @@ -33,7 +38,7 @@ export function LeafGrid({ return (