mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-10 05:12:14 +00:00
test(documents): share entry point seeds the create flow with the document
Unit: the shared ShareLinkCreateForm mounts bare (Settings default) and seeded (document flow) — a pre-attached document rides in as a chip with the label pre-filled. e2e: the document detail Share action opens the create flow with that document pre-attached and reaches the one-time QR reveal; marked slow (two stacked sheets + a real create).
This commit is contained in:
1 parent
d4009a3587
commit
46c85e8671
2 files changed
+129
No files matched your search
@@ -30,6 +30,7 @@ import { STORAGE_STATE_PATH } from "./setup/global-setup";
|
||||
import {
|
||||
ensureShareDocFixture,
|
||||
ensureVaultFixture,
|
||||
MRT_DOC_ID,
|
||||
SHARE_DOC_PREFIX,
|
||||
SHARE_JPEG_DOC_ID,
|
||||
SHARE_PDF_DOC_ID,
|
||||
@@ -233,6 +234,50 @@ test.describe("clinician document sharing", () => {
|
||||
await clinician.context().close();
|
||||
});
|
||||
|
||||
test("the document detail Share action opens the create flow with that document pre-attached", async ({
|
||||
page,
|
||||
}) => {
|
||||
// Opens two stacked sheets (detail → share) and drives a real create with
|
||||
// the one-time QR render — heavier than the default 30s budget on a loaded
|
||||
// runner. Runs on the desktop and 390px mobile projects.
|
||||
test.slow();
|
||||
|
||||
// Deep-link straight to the document detail sheet.
|
||||
await page.goto(`/documents?doc=${MRT_DOC_ID}`);
|
||||
const detail = page.getByRole("dialog").filter({ hasText: "MRT Knie" });
|
||||
await expect(detail).toBeVisible();
|
||||
|
||||
// The Share action sits beside Download in the footer.
|
||||
await detail.getByRole("button", { name: "Share" }).click();
|
||||
|
||||
// The share flow opens with the document already attached and its title
|
||||
// pre-filled as the link label — no context switch to Settings.
|
||||
const shareSheet = page
|
||||
.getByRole("dialog")
|
||||
.filter({ hasText: "Share this document" });
|
||||
await expect(shareSheet).toBeVisible();
|
||||
await expect(shareSheet.locator("#share-label")).toHaveValue("MRT Knie");
|
||||
const chips = shareSheet
|
||||
.getByTestId("share-attached-chips")
|
||||
.getByRole("listitem");
|
||||
await expect(chips).toHaveCount(1);
|
||||
await expect(chips.first()).toContainText("MRT Knie");
|
||||
|
||||
// Create the link — the one-time reveal (with the scannable QR) lands in
|
||||
// the same sheet, carrying the one attached document.
|
||||
await shareSheet.getByRole("button", { name: "Create link" }).click();
|
||||
const reveal = shareSheet.getByTestId("share-token-reveal");
|
||||
await expect(reveal).toBeVisible();
|
||||
await expect(
|
||||
shareSheet.getByTestId("share-created-doc-count"),
|
||||
).toContainText("1");
|
||||
const qrImg = shareSheet.getByTestId("share-qr-block").getByRole("img");
|
||||
await expect(qrImg).toBeVisible();
|
||||
const box = await qrImg.boundingBox();
|
||||
expect(box, "QR image has a rendered box").not.toBeNull();
|
||||
expect(box!.width).toBeGreaterThanOrEqual(160);
|
||||
});
|
||||
|
||||
test("picker enforces the document cap at the limit", async ({ page }) => {
|
||||
await page.goto("/settings/sharing");
|
||||
await page.locator("#share-label").fill(`${SHARE_DOC_PREFIX} cap`);
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* The shared clinician share-link CREATE flow. It is mounted from two places
|
||||
* — Settings → Sharing and the document detail sheet's Share action — so the
|
||||
* test pins the two behaviours the document entry point relies on:
|
||||
* 1. Mounted bare (the Settings default) it renders the create form with the
|
||||
* 90-day-capped expiry, the attach affordance, the frozen-set warning,
|
||||
* and no pre-attached document.
|
||||
* 2. Mounted with `initialDocuments` + `initialLabel` (the document flow) it
|
||||
* pre-fills the label and seeds the attached-document chip, so sharing a
|
||||
* document lands on a create form already scoped to it.
|
||||
*
|
||||
* SSR-static render only (no jsdom), matching the sibling settings tests. The
|
||||
* TanStack hooks are mocked; the QR (`qrcode`) only ever renders in an effect
|
||||
* after a create, so it never runs under `renderToStaticMarkup`.
|
||||
*/
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { renderToStaticMarkup } from "react-dom/server";
|
||||
|
||||
vi.mock("@tanstack/react-query", () => ({
|
||||
// The always-mounted ShareDocumentPicker reads via useQuery; the form
|
||||
// itself creates via useMutation.
|
||||
useQuery: () => ({ data: undefined, isPending: false, isError: false }),
|
||||
useMutation: () => ({ mutate: vi.fn(), isPending: false }),
|
||||
useQueryClient: () => ({ invalidateQueries: vi.fn() }),
|
||||
}));
|
||||
|
||||
import { I18nProvider } from "@/lib/i18n/context";
|
||||
import { ShareLinkCreateForm } from "../share-link-create-form";
|
||||
import type { PickedDocument } from "../share-document-picker";
|
||||
|
||||
function render(
|
||||
props: {
|
||||
initialDocuments?: PickedDocument[];
|
||||
initialLabel?: string;
|
||||
} = {},
|
||||
locale: "en" | "de" = "en",
|
||||
) {
|
||||
return renderToStaticMarkup(
|
||||
<I18nProvider initialLocale={locale}>
|
||||
<ShareLinkCreateForm {...props} />
|
||||
</I18nProvider>,
|
||||
);
|
||||
}
|
||||
|
||||
describe("<ShareLinkCreateForm> — shared create flow", () => {
|
||||
it("renders the create form with the 90-day-capped expiry and attach affordance", () => {
|
||||
const html = render();
|
||||
expect(html).toContain('max="90"');
|
||||
expect(html).toContain("Create link");
|
||||
expect(html).toContain('data-testid="share-attach-open"');
|
||||
expect(html).toContain("Choose documents");
|
||||
});
|
||||
|
||||
it("surfaces the frozen-set warning so the write-once contract is explicit", () => {
|
||||
const html = render();
|
||||
expect(html).toContain("fixed once you create the link");
|
||||
});
|
||||
|
||||
it("does not reveal a token before a create succeeds", () => {
|
||||
const html = render();
|
||||
expect(html).not.toContain('data-testid="share-token-reveal"');
|
||||
});
|
||||
|
||||
it("mounts bare with no pre-attached document (the Settings default)", () => {
|
||||
const html = render();
|
||||
expect(html).not.toContain('data-testid="share-attached-chips"');
|
||||
expect(html).toContain("0 of 50 selected");
|
||||
});
|
||||
|
||||
it("seeds the label and the attached-document chip from the document flow", () => {
|
||||
const html = render({
|
||||
initialDocuments: [{ id: "doc-1", title: "Blood panel 2026" }],
|
||||
initialLabel: "Blood panel 2026",
|
||||
});
|
||||
// Label pre-filled with the document title.
|
||||
expect(html).toContain('value="Blood panel 2026"');
|
||||
// The document rides in as a removable chip, and the count reflects it.
|
||||
expect(html).toContain('data-testid="share-attached-chips"');
|
||||
expect(html).toContain("Blood panel 2026");
|
||||
expect(html).toContain("1 of 50 selected");
|
||||
// A seeded set surfaces the EXIF note the picker path also shows.
|
||||
expect(html).toContain("Camera metadata");
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user