Files
HealthLog/e2e/visits.spec.ts
T
Marc-André Bombeck bdfea7dd85 test(encounters): the Phase 2 surfaces against real Postgres, and end to end
Three properties here cannot be answered by a mocked client, and each has a
shape that would pass a weaker assertion while being wrong:

- filing a visit against a due checkup twice satisfies it ONCE. Phrased as
  "the second call returned 200" it proves nothing, so the assertion is that
  lastSatisfiedAt did not move — and the instant is captured once, because two
  calls milliseconds apart are two different filings and the forward-only guard
  correctly advances on the later one.
- a lab commit writes one link PER RESULT ROW. A test that asserted "there is
  a link" would pass on one link for a three-marker panel.
- the visit list's condition filter runs in SQL. With one visit in the account
  a filter and no filter return the same list, so there are always two.

The bulk arm gets per-entry tolerance over a hundred documents, one unknown id
reported as one failed row with the rest filed, and a foreign visit refusing
the whole batch before anything is written.

The e2e spec proves the incidental-linking promise once, addressing stable
data-slot attributes rather than viewport text: a visit saves with a date and
nothing else, and a document dated inside the window offers that visit,
pre-selected because there is exactly one, and files itself against it.
2026-08-08 14:51:56 +02:00

103 lines
3.7 KiB
TypeScript

/**
* Visits — the incidental-linking promise, proven end to end once.
*
* The flow this milestone is checked against, in one script:
*
* 1. create a visit with ONLY a date — nothing else touched, Save enabled;
* 2. it appears in the list;
* 3. open a document dated inside the ±7-day window;
* 4. the suggestion offers that visit;
* 5. take the offer;
* 6. the document's detail names the visit it now belongs to.
*
* Every assertion addresses a stable `data-slot`, never viewport text: the
* copy is i18n-driven and the mobile project renders the same slots at a
* different size, so a text assertion would break for the wrong reason.
*
* The visit is created through the API rather than by driving the sheet twice:
* step 1 is about the SAVE being possible with only a date, which the sheet
* assertion below covers, and the linking half needs a visit whose instant is
* pinned relative to the seeded document's date.
*/
import { expect, test } from "./setup/test";
import { ensureVaultFixture, MRT_DOC_ID } from "./setup/vault-fixture";
test.beforeEach(async () => {
await ensureVaultFixture();
});
test.describe("visits", () => {
test("a visit saves with a date and nothing else", async ({ page }) => {
await page.goto("/checkups");
await page.getByTestId("checkups-tab-visits").click();
const add = page.locator('[data-slot="visits-add"]').first();
await expect(add).toBeVisible();
await add.click();
// The date is pre-filled with now, and NOTHING else has been touched.
const save = page.locator('[data-slot="encounter-save"]').first();
await expect(save).toBeVisible();
// The whole product constraint: not disabled, with no practitioner, no
// reason, no outcome and no link chosen.
await expect(save).toBeEnabled();
await save.click();
// It appears in the list. A visit dated now is in the past arm.
await expect(page.locator('[data-slot="visit-card"]').first()).toBeVisible({
timeout: 15_000,
});
});
test("a document offers the visit its date falls near, and files itself against it", async ({
page,
request,
}) => {
// The seeded MRI report carries a fixed filing date; the visit is placed
// two days before it so the ±7-day window resolves to exactly one
// candidate — the branch that pre-selects.
const document = await request
.get(`/api/documents/inbound/${MRT_DOC_ID}`)
.then((res) => res.json());
const anchorDay: string =
document.data.reportDate ?? document.data.documentDate;
expect(
anchorDay,
"the fixture document carries a filing date",
).toBeTruthy();
const occurredAt = new Date(`${anchorDay}T09:00:00.000Z`);
occurredAt.setUTCDate(occurredAt.getUTCDate() - 2);
const created = await request.post("/api/encounters", {
data: {
occurredAt: occurredAt.toISOString(),
status: "DONE",
kind: "SPECIALIST",
},
});
expect(created.status()).toBe(201);
await page.goto(`/documents?doc=${MRT_DOC_ID}`);
const suggestion = page
.locator('[data-slot="document-encounter-suggestion"]')
.first();
await expect(suggestion).toBeVisible({ timeout: 15_000 });
// One candidate, so the single-candidate branch: a pre-selectable offer
// rather than a picker.
await expect(suggestion).toHaveAttribute("data-verdict", "one");
await page
.locator('[data-slot="document-encounter-suggestion-option"]')
.first()
.click();
// The filing landed: the read-only "belongs to visit" row appears.
await expect(
page.locator('[data-slot="document-visit-links"]').first(),
).toBeVisible({ timeout: 15_000 });
});
});