test(documents): clinician doc list + share picker/QR + i18n x6

This commit is contained in:
Marc-André Bombeck committed 2026-07-07 21:19:58 +02:00
1 parent fdc0f83a47
commit e734c161f4
3 files changed
+106 -5

No files matched your search

@@ -5,6 +5,7 @@
* carries the descriptive "not a clinical assessment / not a diagnosis"
* disclaimer, the provenance header renders, and the view holds no app chrome.
*/
import type React from "react";
import { describe, it, expect } from "vitest";
import { renderToStaticMarkup } from "react-dom/server";
@@ -59,7 +60,15 @@ function makeReport(
} as DoctorReportData;
}
function render(report: DoctorReportData) {
function render(
report: DoctorReportData,
extra?: Partial<
Pick<
React.ComponentProps<typeof ClinicianView>,
"documents" | "token" | "locale"
>
>,
) {
const { t } = getServerTranslator("en");
return renderToStaticMarkup(
<ClinicianView
@@ -68,6 +77,7 @@ function render(report: DoctorReportData) {
expiresAt="2026-03-01T00:00:00.000Z"
report={report}
sections={{ ...DEFAULT_DOCTOR_REPORT_PREFS }}
{...extra}
/>,
);
}
@@ -107,4 +117,70 @@ describe("<ClinicianView>", () => {
expect(html).not.toContain('data-slot="sidebar"');
expect(html).not.toContain("coach");
});
it("renders no document section when the frozen set is empty", () => {
const html = render(makeReport(), { documents: [], token: "hls_abc" });
expect(html).not.toContain("Documents</h2>");
});
it("renders Class A inline: image → <img>, PDF → <iframe>, both at the serve route", () => {
const html = render(makeReport(), {
token: "hls_tok",
documents: [
{
id: "img-1",
title: "Skin photo",
kind: "IMAGING",
documentDate: "2026-01-10",
byteSize: 20480,
mimeType: "image/jpeg",
servingClass: "inline",
},
{
id: "pdf-1",
title: "Blood panel",
kind: "LAB_RESULT",
documentDate: "2026-01-12",
byteSize: 51200,
mimeType: "application/pdf",
servingClass: "inline",
},
],
});
// Section header present.
expect(html).toContain("Documents");
// Image → <img> pointed at the token-scoped serve route.
expect(html).toContain('src="/c/hls_tok/d/img-1"');
expect(html).toContain("<img");
// PDF → <iframe> pointed at the same route family.
expect(html).toContain('src="/c/hls_tok/d/pdf-1"');
expect(html).toContain("<iframe");
// Titles render as escaped text.
expect(html).toContain("Skin photo");
expect(html).toContain("Blood panel");
});
it("renders Class B as a download link with no inline preview frame", () => {
const html = render(makeReport(), {
token: "hls_tok",
documents: [
{
id: "doc-b",
title: "Referral letter",
kind: "REFERRAL",
documentDate: null,
byteSize: 8192,
mimeType: "application/msword",
servingClass: "attachment",
},
],
});
// A download anchor at the serve route.
expect(html).toContain('href="/c/hls_tok/d/doc-b"');
expect(html).toContain("Download");
// No inline preview for an attachment-class document.
expect(html).not.toContain("<iframe");
expect(html).not.toContain('<img src="/c/hls_tok/d/doc-b"');
expect(html).toContain("Referral letter");
});
});
+3 -4
View File
@@ -114,10 +114,9 @@ function DocumentEntry({
const title = doc.title ?? t("clinicianView.documents.untitled");
const Icon =
DOCUMENT_KIND_ICONS[doc.kind as InboundDocumentKindValue] ?? undefined;
const meta = [
doc.documentDate,
formatBytes(doc.byteSize, locale),
].filter(Boolean) as string[];
const meta = [doc.documentDate, formatBytes(doc.byteSize, locale)].filter(
Boolean,
) as string[];
const isImage = doc.mimeType.startsWith("image/");
const isInline = doc.servingClass === "inline";
@@ -35,6 +35,7 @@ const FIXTURE_LINKS = [
rangeEnd: null,
resourceTypes: ["Patient", "Observation"],
allowFhirApi: true,
documentCount: 2,
expiresAt: "2099-01-01T00:00:00.000Z",
createdAt: "2026-06-01T00:00:00.000Z",
revokedAt: null,
@@ -49,6 +50,7 @@ const FIXTURE_LINKS = [
rangeEnd: null,
resourceTypes: [],
allowFhirApi: false,
documentCount: 0,
expiresAt: "2099-01-01T00:00:00.000Z",
createdAt: "2026-05-01T00:00:00.000Z",
revokedAt: "2026-05-15T00:00:00.000Z",
@@ -122,4 +124,28 @@ describe("<SharingSection> — owner share-link surface (C7)", () => {
const html = render("de");
expect(html).toContain("Neuer Freigabe-Link");
});
it("offers the document picker trigger and surfaces the ≤50 cap", () => {
const html = render();
// The attach-documents affordance is present on the create form.
expect(html).toContain('data-testid="share-attach-open"');
expect(html).toContain("Attach documents");
// The cap the picker enforces client-side is surfaced in the count copy.
expect(html).toContain("of 50 selected");
});
it("surfaces the frozen-set warning so the write-once contract is explicit", () => {
const html = render();
// The set cannot be edited after creation — the UI must say so.
expect(html).toContain("fixed once you create the link");
});
it("shows a document-count badge on a link that carries documents", () => {
const html = render();
expect(html).toContain('data-testid="share-doc-count-badge"');
// The active fixture carries two documents.
const activeStart = html.indexOf('data-testid="share-active-list"');
const activeSlice = html.slice(activeStart);
expect(activeSlice).toContain('data-testid="share-doc-count-badge"');
});
});