From 86113848b541ffa07ac6566062e258bc93f2b778 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Fri, 16 Oct 2026 05:23:06 +0200 Subject: [PATCH] fix(medications): refresh the episode and document details after filing a link --- .../medication-related-section.test.tsx | 58 +++++++++++++++++++ .../detail/medication-related-section.tsx | 6 +- 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 src/components/medications/__tests__/medication-related-section.test.tsx diff --git a/src/components/medications/__tests__/medication-related-section.test.tsx b/src/components/medications/__tests__/medication-related-section.test.tsx new file mode 100644 index 000000000..f03dcb3ed --- /dev/null +++ b/src/components/medications/__tests__/medication-related-section.test.tsx @@ -0,0 +1,58 @@ +import { describe, expect, it, vi } from "vitest"; +import { renderToStaticMarkup } from "react-dom/server"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; + +import { I18nProvider } from "@/lib/i18n/context"; +import { queryKeys } from "@/lib/query-keys"; + +const captured = vi.hoisted(() => ({ + onSaved: undefined as (() => void) | undefined, +})); + +vi.mock("@/components/links/related-records", () => ({ + RelatedRecordsList: () => null, + RelationLinkPickers: (props: { onSaved: () => void }) => { + captured.onSaved = props.onSaved; + return null; + }, +})); + +vi.mock("@/hooks/use-record-capabilities", () => ({ + useRecordCapabilities: () => ({ inSharedRecord: false }), +})); + +import { MedicationRelatedSection } from "@/components/medications/detail/medication-related-section"; + +/** + * A link filed from the medication is listed on the other end too, so a save + * must stale every detail that reads it back: the medication itself, the + * episode, the document and the visit. + */ +describe("MedicationRelatedSection", () => { + it("invalidates every end a saved link is read back on", () => { + const qc = new QueryClient(); + const spy = vi.spyOn(qc, "invalidateQueries"); + renderToStaticMarkup( + + + + + , + ); + expect(captured.onSaved).toBeTypeOf("function"); + captured.onSaved?.(); + const keys = spy.mock.calls.map((call) => call[0]?.queryKey); + expect(keys).toEqual( + expect.arrayContaining([ + queryKeys.medicationDetail("med-1"), + queryKeys.illness(), + queryKeys.documents(), + queryKeys.encounters(), + ]), + ); + }); +}); diff --git a/src/components/medications/detail/medication-related-section.tsx b/src/components/medications/detail/medication-related-section.tsx index a2b487a2d..ff5774539 100644 --- a/src/components/medications/detail/medication-related-section.tsx +++ b/src/components/medications/detail/medication-related-section.tsx @@ -46,9 +46,13 @@ export function MedicationRelatedSection({ related={related} anchor={startsOn} onSaved={() => { - // The other end lists the medication too. + // The other end lists the medication too: every kind the + // pickers file (episode, document, visit) reads it back on its + // own detail, so each one's prefix goes stale. for (const queryKey of [ queryKeys.medicationDetail(medicationId), + queryKeys.illness(), + queryKeys.documents(), queryKeys.encounters(), ]) { void qc.invalidateQueries({ queryKey });