fix(query): refetch a query whose first load was in flight at invalidation

TanStack restarts an in-flight fetch on invalidation only when the query
already holds data. A query still on its first load gets the in-flight
promise back, and that fetch's success clears the invalidated flag, so an
answer read before the write sticks with nothing scheduled to correct it.

The vault hit this when an upload settled just as a typed search switched
the list to a fresh key: the list stayed on "No matching documents" while
the stored row existed. invalidateKeys now waits for such a first load to
end and invalidates that query once more.
This commit is contained in:
Marc-André Bombeck committed 2026-11-05 13:05:57 +01:00
1 parent 63f9d2f60e
commit 2e28d4ed4c
6 files changed
+130 -4

No files matched your search

@@ -39,7 +39,10 @@ import {
// populated medications list; per-test mockReturnValue calls override.
const mockUseQuery = vi.fn();
const mockInvalidateQueries = vi.fn().mockResolvedValue(undefined);
const mockQueryClient = { invalidateQueries: mockInvalidateQueries };
const mockQueryClient = {
invalidateQueries: mockInvalidateQueries,
getQueryCache: () => ({ findAll: () => [] }),
};
vi.mock("@tanstack/react-query", () => ({
useQuery: (opts: unknown) => mockUseQuery(opts),
useQueryClient: () => mockQueryClient,
@@ -411,6 +414,7 @@ describe("submit invalidation — the quick-add is a capture-picker surface, not
const invalidateQueries = vi.fn().mockResolvedValue(undefined);
const queryClient = {
invalidateQueries,
getQueryCache: () => ({ findAll: () => [] }),
} as unknown as QueryClientType;
await invalidateMedicationReads(queryClient);
@@ -89,6 +89,7 @@ const t = (key: string, params?: Record<string, string | number>) =>
function fakeQueryClient(): QueryClientType {
return {
invalidateQueries: vi.fn().mockResolvedValue(undefined),
getQueryCache: () => ({ findAll: () => [] }),
} as unknown as QueryClientType;
}
@@ -40,6 +40,7 @@ const invalidateSpy = vi.fn();
vi.mock("@tanstack/react-query", () => ({
useQueryClient: () => ({
invalidateQueries: invalidateSpy,
getQueryCache: () => ({ findAll: () => [] }),
// v1.32.22 — the writer reads/seeds the optimistic-concurrency token
// via the query cache; no token seeded → tokenless (unconditional) write.
getQueryData: () => undefined,