From 48b8071a67584b31e927511d6416ae3b54f8187b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Sun, 26 Jul 2026 10:37:35 +0200 Subject: [PATCH] test(medications): pin the container-correction wire contract Submitting the correction dialog is out of reach for the SSR component tests, so the two behaviours that only show up on submit are pinned against the module source: a date rides along only when it changed, and a cleared field sends null rather than an empty string. The route side of the same contract is covered by a real request test. --- .../inventory-section-dates.test.tsx | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/components/medications/__tests__/inventory-section-dates.test.tsx b/src/components/medications/__tests__/inventory-section-dates.test.tsx index a35c71485..3cc8b63c9 100644 --- a/src/components/medications/__tests__/inventory-section-dates.test.tsx +++ b/src/components/medications/__tests__/inventory-section-dates.test.tsx @@ -11,11 +11,21 @@ * * Project convention is SSR-only component tests (`renderToStaticMarkup`). */ +import { readFileSync } from "node:fs"; +import { resolve } from "node:path"; import { describe, expect, it, vi } from "vitest"; import { renderToStaticMarkup } from "react-dom/server"; import { I18nProvider } from "@/lib/i18n/context"; +const src = readFileSync( + resolve( + process.cwd(), + "src/components/medications/sections/inventory-section.tsx", + ), + "utf8", +); + // The Radix Dialog / Select portal at runtime, so their bodies never // materialise in static markup. Collapse the primitives to plain // wrappers (same trick as the AddInventoryDialog suite). @@ -204,6 +214,27 @@ describe(" — editable dates", () => { const html = renderDialog(); expect(html).toContain('id="inventory-adjust-remaining"'); }); + + // Submitting is out of SSR reach, so the wire contract is pinned + // against the source (same approach as the register-dialog suite). + it("sends each date only when it actually changed", () => { + // Absent means untouched on the server: saving a unit correction + // must not rewrite a date the user never opened. + expect(src).toMatch( + /\.\.\.\(expiry !== initialExpiry && \{\s*\n?\s*printedExpiry: fromLocalDayInput\(expiry\),/, + ); + expect(src).toMatch( + /\.\.\.\(opened !== initialOpened && \{\s*\n?\s*markAsFirstUseAt: fromLocalDayInput\(opened\),/, + ); + }); + + it("sends a cleared date as null, not as an empty string", () => { + // null is the deliberate "there is no such date"; the route reads it + // as a clear, which is the way back out of a wrong auto-open. + expect(src).toMatch( + /function fromLocalDayInput\(day: string\): string \| null \{\s*\n\s*if \(!day\) return null;/, + ); + }); }); describe(" — printed expiry on create", () => {