diff --git a/src/hooks/__tests__/use-measurement-reminders-refetch.test.ts b/src/hooks/__tests__/use-measurement-reminders-refetch.test.ts index 56f32ef2f..4c4f01db1 100644 --- a/src/hooks/__tests__/use-measurement-reminders-refetch.test.ts +++ b/src/hooks/__tests__/use-measurement-reminders-refetch.test.ts @@ -1,7 +1,8 @@ import { describe, it, expect, vi } from "vitest"; -import type { QueryClient } from "@tanstack/react-query"; +import { QueryClient, QueryObserver } from "@tanstack/react-query"; import { invalidateReminderReads } from "@/hooks/use-measurement-reminders"; +import { queryKeys } from "@/lib/query-keys"; /** * v1.32.19 — a Vorsorge reminder marked done (or created / edited / deleted) @@ -16,6 +17,7 @@ import { invalidateReminderReads } from "@/hooks/use-measurement-reminders"; function fakeQueryClient(): QueryClient { return { invalidateQueries: vi.fn().mockResolvedValue(undefined), + getQueryCache: () => ({ findAll: () => [] }), } as unknown as QueryClient; } @@ -47,4 +49,25 @@ describe("invalidateReminderReads — the Vorsorge daily-rail freshness contract expect(inactiveKeys).toContain(JSON.stringify(["dashboard", "snapshot"])); expect(inactiveKeys).toContain(JSON.stringify(["daily", "digest"])); }); + + it("refetches the Today rail while it is on screen", async () => { + // The dashboard: the check-up tile and the Today rail are both mounted, + // where the inactive pass alone fetches nothing. + const client = new QueryClient({ + defaultOptions: { queries: { retry: false, staleTime: Infinity } }, + }); + let reads = 0; + const observer = new QueryObserver(client, { + queryKey: queryKeys.dailyDigest(), + queryFn: async () => ++reads, + }); + const unsubscribe = observer.subscribe(() => {}); + await vi.waitFor(() => expect(reads).toBe(1)); + + await invalidateReminderReads(client); + + expect(reads).toBe(2); + unsubscribe(); + client.clear(); + }); }); diff --git a/src/hooks/use-measurement-reminders.ts b/src/hooks/use-measurement-reminders.ts index b42a564c8..b2376dddc 100644 --- a/src/hooks/use-measurement-reminders.ts +++ b/src/hooks/use-measurement-reminders.ts @@ -17,7 +17,11 @@ import { } from "@tanstack/react-query"; import { apiDelete, apiGet, apiPatch, apiPost } from "@/lib/api/api-fetch"; -import { queryKeys, refetchInactiveDailyReads } from "@/lib/query-keys"; +import { + invalidateKeys, + queryKeys, + refetchInactiveDailyReads, +} from "@/lib/query-keys"; /** * v1.32.19 — the read fan-out every Vorsorge reminder mutation runs on @@ -31,11 +35,21 @@ import { queryKeys, refetchInactiveDailyReads } from "@/lib/query-keys"; * (`refetchOnMount: false`) — the reminder lingered on the Today rail until * the 120 s poll. Force the inactive daily reads to refetch alongside the * reminders invalidation so the rail clears at once, the same freshness - * contract the medication intake surfaces use. + * contract the medication intake surfaces use. The inactive pass fetches + * nothing for a read that is on screen, though: marked done from the + * dashboard tile, the check-up stayed due on the Today rail above it. So + * the two daily reads are invalidated the ordinary way as well, which + * refetches them where they are mounted. A check-up marked done is also + * listed on its day. */ export function invalidateReminderReads(qc: QueryClient): Promise { return Promise.all([ - qc.invalidateQueries({ queryKey: queryKeys.measurementReminders() }), + invalidateKeys(qc, [ + queryKeys.measurementReminders(), + queryKeys.dailyDigest(), + queryKeys.dashboardSnapshot(), + queryKeys.dayRoot(), + ]), refetchInactiveDailyReads(qc), ]); }