diff --git a/web/app/composables/api/useNotificationAPI.nuxt.test.ts b/web/app/composables/api/useNotificationAPI.nuxt.test.ts index ef7eec22..18cfbdd5 100644 --- a/web/app/composables/api/useNotificationAPI.nuxt.test.ts +++ b/web/app/composables/api/useNotificationAPI.nuxt.test.ts @@ -1,5 +1,5 @@ import type { EntryKey, UseInfiniteQueryData } from "@pinia/colada" -import { afterEach, beforeEach, describe, it } from "vitest" +import { afterEach, beforeEach, describe, it, vi } from "vitest" import { clearQueryCache, disposeMockEndpoints, @@ -305,6 +305,48 @@ describe("useNotificationAPI", { concurrent: false }, () => { }) describe("markNotificationsRead", () => { + it("preserves the error when preparing the optimistic update fails", async ({ + expect, + }) => { + const listCalls = mockEndpoint("GET", "/api/notifications", () => + makePage([]), + ) + const countCalls = mockEndpoint( + "GET", + "/api/notifications/count", + () => ({ count: 0 }), + ) + const putCalls = mockEndpoint( + "PUT", + "/api/notifications/read-status", + () => ({}), + ) + const page = makePage([makeNotification("n1", false)]) + seedPages(LIST_KEY_A, page) + const api = makeNotificationAPI() + const queryCache = runInApp(() => useQueryCache()) + const error = new Error("Cache unavailable") + const getQueryData = vi + .spyOn(queryCache, "getQueryData") + .mockImplementationOnce(() => { + throw error + }) + + try { + await expect( + api.markNotificationsRead.mutateAsync({ ids: ["n1"] }), + ).rejects.toBe(error) + expect(getQueryData).toHaveBeenCalledExactlyOnceWith(LIST_KEY_A) + expect(putCalls).toHaveLength(0) + expect(listCalls).toHaveLength(0) + expect(countCalls).toHaveLength(0) + } finally { + getQueryData.mockRestore() + } + + expect(getPages(LIST_KEY_A)).toEqual(makePages(page)) + }) + it.for([ { name: "one notification", ids: ["n1"], remaining: ["n2"] }, { name: "all notifications", ids: [], remaining: [] }, diff --git a/web/app/composables/api/useNotificationAPI.ts b/web/app/composables/api/useNotificationAPI.ts index fcc02869..73fd8d5a 100644 --- a/web/app/composables/api/useNotificationAPI.ts +++ b/web/app/composables/api/useNotificationAPI.ts @@ -18,7 +18,7 @@ export default function () { function useFetchManyNotifications( paramsRef: MaybeRefOrGetter, ) { - return useInfiniteQuery(() => { + return useInfiniteQuery(() => { const { limit, read } = toValue(paramsRef) return { @@ -136,6 +136,10 @@ export default function () { }, onSuccess: invalidateNotifications, onError(_err, _data, { oldNotifs, newNotifs }) { + if (!newNotifs) { + return + } + const entries = queryCache.getEntries({ key: NOTIFICATION_QUERY_KEYS.listRoot, // switching filters can populate another cache while the