@tanstack/query-core 4.24.10 → 5.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/build/lib/focusManager.d.ts +1 -3
  2. package/build/lib/focusManager.esm.js +19 -36
  3. package/build/lib/focusManager.esm.js.map +1 -1
  4. package/build/lib/focusManager.js +19 -38
  5. package/build/lib/focusManager.js.map +1 -1
  6. package/build/lib/focusManager.mjs +19 -36
  7. package/build/lib/focusManager.mjs.map +1 -1
  8. package/build/lib/hydration.esm.js +21 -23
  9. package/build/lib/hydration.esm.js.map +1 -1
  10. package/build/lib/hydration.js +21 -25
  11. package/build/lib/hydration.js.map +1 -1
  12. package/build/lib/hydration.mjs +21 -23
  13. package/build/lib/hydration.mjs.map +1 -1
  14. package/build/lib/index.d.ts +1 -2
  15. package/build/lib/index.esm.js +1 -1
  16. package/build/lib/index.js +2 -8
  17. package/build/lib/index.js.map +1 -1
  18. package/build/lib/index.mjs +1 -1
  19. package/build/lib/infiniteQueryBehavior.d.ts +3 -7
  20. package/build/lib/infiniteQueryBehavior.esm.js +52 -75
  21. package/build/lib/infiniteQueryBehavior.esm.js.map +1 -1
  22. package/build/lib/infiniteQueryBehavior.js +50 -77
  23. package/build/lib/infiniteQueryBehavior.js.map +1 -1
  24. package/build/lib/infiniteQueryBehavior.mjs +52 -75
  25. package/build/lib/infiniteQueryBehavior.mjs.map +1 -1
  26. package/build/lib/infiniteQueryObserver.d.ts +4 -4
  27. package/build/lib/infiniteQueryObserver.esm.js +18 -26
  28. package/build/lib/infiniteQueryObserver.esm.js.map +1 -1
  29. package/build/lib/infiniteQueryObserver.js +18 -28
  30. package/build/lib/infiniteQueryObserver.js.map +1 -1
  31. package/build/lib/infiniteQueryObserver.mjs +18 -26
  32. package/build/lib/infiniteQueryObserver.mjs.map +1 -1
  33. package/build/lib/mutation.d.ts +11 -22
  34. package/build/lib/mutation.esm.js +73 -105
  35. package/build/lib/mutation.esm.js.map +1 -1
  36. package/build/lib/mutation.js +73 -107
  37. package/build/lib/mutation.js.map +1 -1
  38. package/build/lib/mutation.mjs +73 -105
  39. package/build/lib/mutation.mjs.map +1 -1
  40. package/build/lib/mutationCache.d.ts +4 -6
  41. package/build/lib/mutationCache.esm.js +23 -32
  42. package/build/lib/mutationCache.esm.js.map +1 -1
  43. package/build/lib/mutationCache.js +23 -34
  44. package/build/lib/mutationCache.js.map +1 -1
  45. package/build/lib/mutationCache.mjs +23 -32
  46. package/build/lib/mutationCache.mjs.map +1 -1
  47. package/build/lib/mutationObserver.d.ts +4 -9
  48. package/build/lib/mutationObserver.esm.js +43 -72
  49. package/build/lib/mutationObserver.esm.js.map +1 -1
  50. package/build/lib/mutationObserver.js +43 -74
  51. package/build/lib/mutationObserver.js.map +1 -1
  52. package/build/lib/mutationObserver.mjs +43 -72
  53. package/build/lib/mutationObserver.mjs.map +1 -1
  54. package/build/lib/notifyManager.esm.js +7 -17
  55. package/build/lib/notifyManager.esm.js.map +1 -1
  56. package/build/lib/notifyManager.js +7 -19
  57. package/build/lib/notifyManager.js.map +1 -1
  58. package/build/lib/notifyManager.mjs +7 -17
  59. package/build/lib/notifyManager.mjs.map +1 -1
  60. package/build/lib/onlineManager.d.ts +1 -3
  61. package/build/lib/onlineManager.esm.js +16 -30
  62. package/build/lib/onlineManager.esm.js.map +1 -1
  63. package/build/lib/onlineManager.js +16 -32
  64. package/build/lib/onlineManager.js.map +1 -1
  65. package/build/lib/onlineManager.mjs +16 -30
  66. package/build/lib/onlineManager.mjs.map +1 -1
  67. package/build/lib/queriesObserver.d.ts +3 -10
  68. package/build/lib/queriesObserver.esm.js +47 -71
  69. package/build/lib/queriesObserver.esm.js.map +1 -1
  70. package/build/lib/queriesObserver.js +49 -75
  71. package/build/lib/queriesObserver.js.map +1 -1
  72. package/build/lib/queriesObserver.mjs +47 -71
  73. package/build/lib/queriesObserver.mjs.map +1 -1
  74. package/build/lib/query.d.ts +14 -21
  75. package/build/lib/query.esm.js +140 -194
  76. package/build/lib/query.esm.js.map +1 -1
  77. package/build/lib/query.js +139 -195
  78. package/build/lib/query.js.map +1 -1
  79. package/build/lib/query.mjs +140 -194
  80. package/build/lib/query.mjs.map +1 -1
  81. package/build/lib/queryCache.d.ts +12 -7
  82. package/build/lib/queryCache.esm.js +21 -45
  83. package/build/lib/queryCache.esm.js.map +1 -1
  84. package/build/lib/queryCache.js +20 -46
  85. package/build/lib/queryCache.js.map +1 -1
  86. package/build/lib/queryCache.mjs +21 -45
  87. package/build/lib/queryCache.mjs.map +1 -1
  88. package/build/lib/queryClient.d.ts +18 -46
  89. package/build/lib/queryClient.esm.js +137 -216
  90. package/build/lib/queryClient.esm.js.map +1 -1
  91. package/build/lib/queryClient.js +136 -217
  92. package/build/lib/queryClient.js.map +1 -1
  93. package/build/lib/queryClient.mjs +137 -216
  94. package/build/lib/queryClient.mjs.map +1 -1
  95. package/build/lib/queryObserver.d.ts +4 -29
  96. package/build/lib/queryObserver.esm.js +176 -258
  97. package/build/lib/queryObserver.esm.js.map +1 -1
  98. package/build/lib/queryObserver.js +176 -260
  99. package/build/lib/queryObserver.js.map +1 -1
  100. package/build/lib/queryObserver.mjs +176 -258
  101. package/build/lib/queryObserver.mjs.map +1 -1
  102. package/build/lib/removable.d.ts +3 -3
  103. package/build/lib/removable.esm.js +10 -14
  104. package/build/lib/removable.esm.js.map +1 -1
  105. package/build/lib/removable.js +10 -16
  106. package/build/lib/removable.js.map +1 -1
  107. package/build/lib/removable.mjs +10 -14
  108. package/build/lib/removable.mjs.map +1 -1
  109. package/build/lib/retryer.d.ts +5 -5
  110. package/build/lib/retryer.esm.js +27 -44
  111. package/build/lib/retryer.esm.js.map +1 -1
  112. package/build/lib/retryer.js +27 -46
  113. package/build/lib/retryer.js.map +1 -1
  114. package/build/lib/retryer.mjs +27 -44
  115. package/build/lib/retryer.mjs.map +1 -1
  116. package/build/lib/subscribable.esm.js +4 -7
  117. package/build/lib/subscribable.esm.js.map +1 -1
  118. package/build/lib/subscribable.js +4 -9
  119. package/build/lib/subscribable.js.map +1 -1
  120. package/build/lib/subscribable.mjs +4 -7
  121. package/build/lib/subscribable.mjs.map +1 -1
  122. package/build/lib/tests/utils.d.ts +3 -12
  123. package/build/lib/types.d.ts +111 -99
  124. package/build/lib/utils.d.ts +8 -18
  125. package/build/lib/utils.esm.js +39 -132
  126. package/build/lib/utils.esm.js.map +1 -1
  127. package/build/lib/utils.js +42 -144
  128. package/build/lib/utils.js.map +1 -1
  129. package/build/lib/utils.mjs +39 -132
  130. package/build/lib/utils.mjs.map +1 -1
  131. package/build/umd/index.development.js +868 -1398
  132. package/build/umd/index.development.js.map +1 -1
  133. package/build/umd/index.production.js +1 -1
  134. package/build/umd/index.production.js.map +1 -1
  135. package/package.json +1 -1
  136. package/src/focusManager.ts +17 -24
  137. package/src/index.ts +1 -11
  138. package/src/infiniteQueryBehavior.ts +54 -94
  139. package/src/infiniteQueryObserver.ts +10 -12
  140. package/src/mutation.ts +68 -92
  141. package/src/mutationCache.ts +27 -27
  142. package/src/mutationObserver.ts +60 -97
  143. package/src/onlineManager.ts +14 -14
  144. package/src/queriesObserver.ts +50 -54
  145. package/src/query.ts +106 -110
  146. package/src/queryCache.ts +42 -41
  147. package/src/queryClient.ts +155 -434
  148. package/src/queryObserver.ts +155 -192
  149. package/src/removable.ts +13 -13
  150. package/src/retryer.ts +5 -5
  151. package/src/tests/focusManager.test.tsx +25 -25
  152. package/src/tests/hydration.test.tsx +167 -81
  153. package/src/tests/infiniteQueryBehavior.test.tsx +209 -17
  154. package/src/tests/infiniteQueryObserver.test.tsx +6 -2
  155. package/src/tests/mutationCache.test.tsx +127 -127
  156. package/src/tests/mutationObserver.test.tsx +1 -31
  157. package/src/tests/mutations.test.tsx +62 -43
  158. package/src/tests/onlineManager.test.tsx +12 -4
  159. package/src/tests/queriesObserver.test.tsx +41 -77
  160. package/src/tests/query.test.tsx +175 -243
  161. package/src/tests/queryCache.test.tsx +170 -93
  162. package/src/tests/queryClient.test.tsx +229 -378
  163. package/src/tests/queryObserver.test.tsx +23 -147
  164. package/src/tests/utils.test.tsx +84 -29
  165. package/src/tests/utils.ts +9 -18
  166. package/src/types.ts +187 -140
  167. package/src/utils.ts +31 -124
  168. package/build/lib/logger.d.ts +0 -8
  169. package/build/lib/logger.esm.js +0 -4
  170. package/build/lib/logger.esm.js.map +0 -1
  171. package/build/lib/logger.js +0 -8
  172. package/build/lib/logger.js.map +0 -1
  173. package/build/lib/logger.mjs +0 -4
  174. package/build/lib/logger.mjs.map +0 -1
  175. package/build/lib/logger.native.d.ts +0 -6
  176. package/build/lib/logger.native.esm.js +0 -12
  177. package/build/lib/logger.native.esm.js.map +0 -1
  178. package/build/lib/logger.native.js +0 -16
  179. package/build/lib/logger.native.js.map +0 -1
  180. package/build/lib/logger.native.mjs +0 -12
  181. package/build/lib/logger.native.mjs.map +0 -1
  182. package/src/logger.native.ts +0 -11
  183. package/src/logger.ts +0 -9
@@ -3,8 +3,8 @@ import type {
3
3
  QueryClient,
4
4
  InfiniteQueryObserverResult,
5
5
  } from '@tanstack/query-core'
6
- import { InfiniteQueryObserver } from '@tanstack/query-core'
7
- import { createQueryClient, queryKey } from './utils'
6
+ import { InfiniteQueryObserver, CancelledError } from '@tanstack/query-core'
7
+ import { createQueryClient, queryKey, sleep } from './utils'
8
8
 
9
9
  describe('InfiniteQueryBehavior', () => {
10
10
  let queryClient: QueryClient
@@ -24,6 +24,8 @@ describe('InfiniteQueryBehavior', () => {
24
24
  const observer = new InfiniteQueryObserver(queryClient, {
25
25
  queryKey: key,
26
26
  retry: false,
27
+ defaultPageParam: 1,
28
+ getNextPageParam: () => 2,
27
29
  })
28
30
 
29
31
  let observerResult:
@@ -37,28 +39,29 @@ describe('InfiniteQueryBehavior', () => {
37
39
  await waitFor(() => {
38
40
  return expect(observerResult).toMatchObject({
39
41
  isError: true,
40
- error: 'Missing queryFn',
42
+ error: new Error('Missing queryFn'),
41
43
  })
42
44
  })
43
45
 
44
46
  unsubscribe()
45
47
  })
46
48
 
47
- test('InfiniteQueryBehavior should not refetch the first page if another page refetched', async () => {
49
+ test('InfiniteQueryBehavior should apply the maxPages option to limit the number of pages', async () => {
48
50
  const key = queryKey()
49
51
  let abortSignal: AbortSignal | null = null
50
52
 
51
- const queryFnSpy = jest
52
- .fn()
53
- .mockImplementation(({ pageParam = 1, signal }) => {
54
- abortSignal = signal
55
- return pageParam
56
- })
53
+ const queryFnSpy = jest.fn().mockImplementation(({ pageParam, signal }) => {
54
+ abortSignal = signal
55
+ return pageParam
56
+ })
57
57
 
58
58
  const observer = new InfiniteQueryObserver<number>(queryClient, {
59
59
  queryKey: key,
60
60
  queryFn: queryFnSpy,
61
61
  getNextPageParam: (lastPage) => lastPage + 1,
62
+ getPreviousPageParam: (firstPage) => firstPage - 1,
63
+ maxPages: 2,
64
+ defaultPageParam: 1,
62
65
  })
63
66
 
64
67
  let observerResult:
@@ -73,13 +76,13 @@ describe('InfiniteQueryBehavior', () => {
73
76
  await waitFor(() =>
74
77
  expect(observerResult).toMatchObject({
75
78
  isFetching: false,
76
- data: { pages: [1] },
79
+ data: { pages: [1], pageParams: [1] },
77
80
  }),
78
81
  )
79
82
 
80
83
  expect(queryFnSpy).toHaveBeenNthCalledWith(1, {
81
84
  queryKey: key,
82
- pageParam: undefined,
85
+ pageParam: 1,
83
86
  meta: undefined,
84
87
  signal: abortSignal,
85
88
  })
@@ -98,16 +101,182 @@ describe('InfiniteQueryBehavior', () => {
98
101
 
99
102
  expect(observerResult).toMatchObject({
100
103
  isFetching: false,
101
- data: { pages: [1, 2] },
104
+ data: { pages: [1, 2], pageParams: [1, 2] },
102
105
  })
103
106
 
104
107
  queryFnSpy.mockClear()
105
108
 
106
- // Refetch the second page
107
- await queryClient.refetchQueries({
108
- refetchPage: (_page, index) => index === 1,
109
+ // Fetch the page before the first page
110
+ await observer.fetchPreviousPage()
111
+
112
+ expect(queryFnSpy).toHaveBeenNthCalledWith(1, {
113
+ queryKey: key,
114
+ pageParam: 0,
115
+ meta: undefined,
116
+ signal: abortSignal,
117
+ })
118
+
119
+ // Only first two pages should be in the data
120
+ expect(observerResult).toMatchObject({
121
+ isFetching: false,
122
+ data: { pages: [0, 1], pageParams: [0, 1] },
109
123
  })
110
124
 
125
+ queryFnSpy.mockClear()
126
+
127
+ // Fetch the page before
128
+ await observer.fetchPreviousPage()
129
+
130
+ expect(queryFnSpy).toHaveBeenNthCalledWith(1, {
131
+ queryKey: key,
132
+ pageParam: -1,
133
+ meta: undefined,
134
+ signal: abortSignal,
135
+ })
136
+
137
+ expect(observerResult).toMatchObject({
138
+ isFetching: false,
139
+ data: { pages: [-1, 0], pageParams: [-1, 0] },
140
+ })
141
+
142
+ queryFnSpy.mockClear()
143
+
144
+ // Fetch the page after
145
+ await observer.fetchNextPage()
146
+
147
+ expect(queryFnSpy).toHaveBeenNthCalledWith(1, {
148
+ queryKey: key,
149
+ pageParam: 1,
150
+ meta: undefined,
151
+ signal: abortSignal,
152
+ })
153
+
154
+ expect(observerResult).toMatchObject({
155
+ isFetching: false,
156
+ data: { pages: [0, 1] },
157
+ })
158
+
159
+ queryFnSpy.mockClear()
160
+
161
+ // Refetch the infinite query
162
+ await observer.refetch()
163
+
164
+ // Only 2 pages should be refetched
165
+ expect(queryFnSpy).toHaveBeenCalledTimes(2)
166
+
167
+ expect(queryFnSpy).toHaveBeenNthCalledWith(1, {
168
+ queryKey: key,
169
+ pageParam: 0,
170
+ meta: undefined,
171
+ signal: abortSignal,
172
+ })
173
+
174
+ expect(queryFnSpy).toHaveBeenNthCalledWith(2, {
175
+ queryKey: key,
176
+ pageParam: 1,
177
+ meta: undefined,
178
+ signal: abortSignal,
179
+ })
180
+
181
+ unsubscribe()
182
+ })
183
+
184
+ test('InfiniteQueryBehavior should support query cancellation', async () => {
185
+ const key = queryKey()
186
+ let abortSignal: AbortSignal | null = null
187
+
188
+ const queryFnSpy = jest.fn().mockImplementation(({ pageParam, signal }) => {
189
+ abortSignal = signal
190
+ sleep(10)
191
+ return pageParam
192
+ })
193
+
194
+ const observer = new InfiniteQueryObserver<number>(queryClient, {
195
+ queryKey: key,
196
+ queryFn: queryFnSpy,
197
+ getNextPageParam: (lastPage) => lastPage + 1,
198
+ getPreviousPageParam: (firstPage) => firstPage - 1,
199
+ defaultPageParam: 1,
200
+ })
201
+
202
+ let observerResult:
203
+ | InfiniteQueryObserverResult<unknown, unknown>
204
+ | undefined
205
+
206
+ const unsubscribe = observer.subscribe((result) => {
207
+ observerResult = result
208
+ })
209
+
210
+ const query = observer.getCurrentQuery()
211
+ query.cancel()
212
+
213
+ // Wait for the first page to be cancelled
214
+ await waitFor(() =>
215
+ expect(observerResult).toMatchObject({
216
+ isFetching: false,
217
+ isError: true,
218
+ error: new CancelledError(),
219
+ data: undefined,
220
+ }),
221
+ )
222
+
223
+ expect(queryFnSpy).toHaveBeenCalledTimes(1)
224
+
225
+ expect(queryFnSpy).toHaveBeenNthCalledWith(1, {
226
+ queryKey: key,
227
+ pageParam: 1,
228
+ meta: undefined,
229
+ signal: abortSignal,
230
+ })
231
+
232
+ unsubscribe()
233
+ })
234
+
235
+ test('InfiniteQueryBehavior should not refetch pages if the query is cancelled', async () => {
236
+ const key = queryKey()
237
+ let abortSignal: AbortSignal | null = null
238
+
239
+ let queryFnSpy = jest.fn().mockImplementation(({ pageParam, signal }) => {
240
+ abortSignal = signal
241
+ return pageParam
242
+ })
243
+
244
+ const observer = new InfiniteQueryObserver<number>(queryClient, {
245
+ queryKey: key,
246
+ queryFn: queryFnSpy,
247
+ getNextPageParam: (lastPage) => lastPage + 1,
248
+ getPreviousPageParam: (firstPage) => firstPage - 1,
249
+ defaultPageParam: 1,
250
+ })
251
+
252
+ let observerResult:
253
+ | InfiniteQueryObserverResult<unknown, unknown>
254
+ | undefined
255
+
256
+ const unsubscribe = observer.subscribe((result) => {
257
+ observerResult = result
258
+ })
259
+
260
+ // Wait for the first page to be fetched
261
+ await waitFor(() =>
262
+ expect(observerResult).toMatchObject({
263
+ isFetching: false,
264
+ data: { pages: [1], pageParams: [1] },
265
+ }),
266
+ )
267
+
268
+ queryFnSpy.mockClear()
269
+
270
+ // Fetch the second page
271
+ await observer.fetchNextPage()
272
+
273
+ expect(observerResult).toMatchObject({
274
+ isFetching: false,
275
+ data: { pages: [1, 2], pageParams: [1, 2] },
276
+ })
277
+
278
+ expect(queryFnSpy).toHaveBeenCalledTimes(1)
279
+
111
280
  expect(queryFnSpy).toHaveBeenNthCalledWith(1, {
112
281
  queryKey: key,
113
282
  pageParam: 2,
@@ -115,10 +284,33 @@ describe('InfiniteQueryBehavior', () => {
115
284
  signal: abortSignal,
116
285
  })
117
286
 
287
+ queryFnSpy = jest.fn().mockImplementation(({ pageParam = 1, signal }) => {
288
+ abortSignal = signal
289
+ sleep(10)
290
+ return pageParam
291
+ })
292
+
293
+ // Refetch the query
294
+ observer.refetch()
295
+ expect(observerResult).toMatchObject({
296
+ isFetching: true,
297
+ isError: false,
298
+ })
299
+
300
+ // Cancel the query
301
+ const query = observer.getCurrentQuery()
302
+ query.cancel()
303
+
118
304
  expect(observerResult).toMatchObject({
119
- data: { pages: [1, 2] },
305
+ isFetching: false,
306
+ isError: true,
307
+ error: new CancelledError(),
308
+ data: { pages: [1, 2], pageParams: [1, 2] },
120
309
  })
121
310
 
311
+ // Pages should not have been fetched
312
+ expect(queryFnSpy).toHaveBeenCalledTimes(0)
313
+
122
314
  unsubscribe()
123
315
  })
124
316
  })
@@ -23,6 +23,8 @@ describe('InfiniteQueryObserver', () => {
23
23
  pages: data.pages.map((x) => `${x}`),
24
24
  pageParams: data.pageParams,
25
25
  }),
26
+ defaultPageParam: 1,
27
+ getNextPageParam: () => 2,
26
28
  })
27
29
  let observerResult
28
30
  const unsubscribe = observer.subscribe((result) => {
@@ -31,7 +33,7 @@ describe('InfiniteQueryObserver', () => {
31
33
  await sleep(1)
32
34
  unsubscribe()
33
35
  expect(observerResult).toMatchObject({
34
- data: { pages: ['1'], pageParams: [undefined] },
36
+ data: { pages: ['1'], pageParams: [1] },
35
37
  })
36
38
  })
37
39
 
@@ -50,6 +52,8 @@ describe('InfiniteQueryObserver', () => {
50
52
  pages: data.pages.map((x) => `${x}`),
51
53
  pageParams: data.pageParams,
52
54
  }),
55
+ defaultPageParam: 1,
56
+ getNextPageParam: () => 2,
53
57
  })
54
58
  let observerResult
55
59
  const unsubscribe = observer.subscribe((result) => {
@@ -58,7 +62,7 @@ describe('InfiniteQueryObserver', () => {
58
62
  await sleep(1)
59
63
  unsubscribe()
60
64
  expect(observerResult).toMatchObject({
61
- data: { pages: ['1'], pageParams: [undefined] },
65
+ data: { pages: ['1'], pageParams: [1] },
62
66
  })
63
67
  expect(queryFn).toBeCalledWith(expect.objectContaining({ meta }))
64
68
  })
@@ -11,16 +11,24 @@ describe('mutationCache', () => {
11
11
  const testClient = createQueryClient({ mutationCache: testCache })
12
12
 
13
13
  try {
14
- await executeMutation(testClient, {
15
- mutationKey: key,
16
- variables: 'vars',
17
- mutationFn: () => Promise.reject('error'),
18
- onMutate: () => 'context',
19
- })
14
+ await executeMutation(
15
+ testClient,
16
+ {
17
+ mutationKey: key,
18
+ mutationFn: () => Promise.reject(new Error('error')),
19
+ onMutate: () => 'context',
20
+ },
21
+ 'vars',
22
+ )
20
23
  } catch {}
21
24
 
22
25
  const mutation = testCache.getAll()[0]
23
- expect(onError).toHaveBeenCalledWith('error', 'vars', 'context', mutation)
26
+ expect(onError).toHaveBeenCalledWith(
27
+ new Error('error'),
28
+ 'vars',
29
+ 'context',
30
+ mutation,
31
+ )
24
32
  })
25
33
 
26
34
  test('should be awaited', async () => {
@@ -35,16 +43,19 @@ describe('mutationCache', () => {
35
43
  const testClient = createQueryClient({ mutationCache: testCache })
36
44
 
37
45
  try {
38
- await executeMutation(testClient, {
39
- mutationKey: key,
40
- variables: 'vars',
41
- mutationFn: () => Promise.reject('error'),
42
- onError: async () => {
43
- states.push(3)
44
- await sleep(1)
45
- states.push(4)
46
+ await executeMutation(
47
+ testClient,
48
+ {
49
+ mutationKey: key,
50
+ mutationFn: () => Promise.reject(new Error('error')),
51
+ onError: async () => {
52
+ states.push(3)
53
+ await sleep(1)
54
+ states.push(4)
55
+ },
46
56
  },
47
- })
57
+ 'vars',
58
+ )
48
59
  } catch {}
49
60
 
50
61
  expect(states).toEqual([1, 2, 3, 4])
@@ -58,12 +69,15 @@ describe('mutationCache', () => {
58
69
  const testClient = createQueryClient({ mutationCache: testCache })
59
70
 
60
71
  try {
61
- await executeMutation(testClient, {
62
- mutationKey: key,
63
- variables: 'vars',
64
- mutationFn: () => Promise.resolve({ data: 5 }),
65
- onMutate: () => 'context',
66
- })
72
+ await executeMutation(
73
+ testClient,
74
+ {
75
+ mutationKey: key,
76
+ mutationFn: () => Promise.resolve({ data: 5 }),
77
+ onMutate: () => 'context',
78
+ },
79
+ 'vars',
80
+ )
67
81
  } catch {}
68
82
 
69
83
  const mutation = testCache.getAll()[0]
@@ -85,16 +99,19 @@ describe('mutationCache', () => {
85
99
  const testCache = new MutationCache({ onSuccess })
86
100
  const testClient = createQueryClient({ mutationCache: testCache })
87
101
 
88
- await executeMutation(testClient, {
89
- mutationKey: key,
90
- variables: 'vars',
91
- mutationFn: () => Promise.resolve({ data: 5 }),
92
- onSuccess: async () => {
93
- states.push(3)
94
- await sleep(1)
95
- states.push(4)
102
+ await executeMutation(
103
+ testClient,
104
+ {
105
+ mutationKey: key,
106
+ mutationFn: () => Promise.resolve({ data: 5 }),
107
+ onSuccess: async () => {
108
+ states.push(3)
109
+ await sleep(1)
110
+ states.push(4)
111
+ },
96
112
  },
97
- })
113
+ 'vars',
114
+ )
98
115
 
99
116
  expect(states).toEqual([1, 2, 3, 4])
100
117
  })
@@ -107,12 +124,15 @@ describe('mutationCache', () => {
107
124
  const testClient = createQueryClient({ mutationCache: testCache })
108
125
 
109
126
  try {
110
- await executeMutation(testClient, {
111
- mutationKey: key,
112
- variables: 'vars',
113
- mutationFn: () => Promise.resolve({ data: 5 }),
114
- onMutate: () => 'context',
115
- })
127
+ await executeMutation(
128
+ testClient,
129
+ {
130
+ mutationKey: key,
131
+ mutationFn: () => Promise.resolve({ data: 5 }),
132
+ onMutate: () => 'context',
133
+ },
134
+ 'vars',
135
+ )
116
136
  } catch {}
117
137
 
118
138
  const mutation = testCache.getAll()[0]
@@ -130,16 +150,19 @@ describe('mutationCache', () => {
130
150
  const testCache = new MutationCache({ onMutate })
131
151
  const testClient = createQueryClient({ mutationCache: testCache })
132
152
 
133
- await executeMutation(testClient, {
134
- mutationKey: key,
135
- variables: 'vars',
136
- mutationFn: () => Promise.resolve({ data: 5 }),
137
- onMutate: async () => {
138
- states.push(3)
139
- await sleep(1)
140
- states.push(4)
153
+ await executeMutation(
154
+ testClient,
155
+ {
156
+ mutationKey: key,
157
+ mutationFn: () => Promise.resolve({ data: 5 }),
158
+ onMutate: async () => {
159
+ states.push(3)
160
+ await sleep(1)
161
+ states.push(4)
162
+ },
141
163
  },
142
- })
164
+ 'vars',
165
+ )
143
166
 
144
167
  expect(states).toEqual([1, 2, 3, 4])
145
168
  })
@@ -150,11 +173,14 @@ describe('mutationCache', () => {
150
173
  const testCache = new MutationCache()
151
174
  const testClient = createQueryClient({ mutationCache: testCache })
152
175
  const key = ['mutation', 'vars']
153
- await executeMutation(testClient, {
154
- mutationKey: key,
155
- variables: 'vars',
156
- mutationFn: () => Promise.resolve(),
157
- })
176
+ await executeMutation(
177
+ testClient,
178
+ {
179
+ mutationKey: key,
180
+ mutationFn: () => Promise.resolve(),
181
+ },
182
+ 'vars',
183
+ )
158
184
  const [mutation] = testCache.getAll()
159
185
  expect(testCache.find({ mutationKey: key })).toEqual(mutation)
160
186
  expect(
@@ -162,7 +188,9 @@ describe('mutationCache', () => {
162
188
  ).toEqual(mutation)
163
189
  expect(testCache.find({ mutationKey: ['unknown'] })).toEqual(undefined)
164
190
  expect(
165
- testCache.find({ predicate: (m) => m.options.variables === 'vars' }),
191
+ testCache.find({
192
+ predicate: (m) => m.options.mutationKey?.[0] === key[0],
193
+ }),
166
194
  ).toEqual(mutation)
167
195
  })
168
196
  })
@@ -171,45 +199,60 @@ describe('mutationCache', () => {
171
199
  test('should filter correctly', async () => {
172
200
  const testCache = new MutationCache()
173
201
  const testClient = createQueryClient({ mutationCache: testCache })
174
- await executeMutation(testClient, {
175
- mutationKey: ['a', 1],
176
- variables: 1,
177
- mutationFn: () => Promise.resolve(),
178
- })
179
- await executeMutation(testClient, {
180
- mutationKey: ['a', 2],
181
- variables: 2,
182
- mutationFn: () => Promise.resolve(),
183
- })
184
- await executeMutation(testClient, {
185
- mutationKey: ['b'],
186
- mutationFn: () => Promise.resolve(),
187
- })
202
+ await executeMutation(
203
+ testClient,
204
+ {
205
+ mutationKey: ['a', 1],
206
+ mutationFn: () => Promise.resolve(),
207
+ },
208
+ 1,
209
+ )
210
+ await executeMutation(
211
+ testClient,
212
+ {
213
+ mutationKey: ['a', 2],
214
+ mutationFn: () => Promise.resolve(),
215
+ },
216
+ 2,
217
+ )
218
+ await executeMutation(
219
+ testClient,
220
+ {
221
+ mutationKey: ['b'],
222
+ mutationFn: () => Promise.resolve(),
223
+ },
224
+ 3,
225
+ )
188
226
 
189
227
  const [mutation1, mutation2] = testCache.getAll()
190
228
  expect(
191
229
  testCache.findAll({ mutationKey: ['a'], exact: false }),
192
230
  ).toHaveLength(2)
193
231
  expect(testCache.find({ mutationKey: ['a', 1] })).toEqual(mutation1)
194
- expect(testCache.findAll({ mutationKey: ['unknown'] })).toEqual([])
195
232
  expect(
196
- testCache.findAll({ predicate: (m) => m.options.variables === 2 }),
233
+ testCache.findAll({
234
+ predicate: (m) => m.options.mutationKey?.[1] === 2,
235
+ }),
197
236
  ).toEqual([mutation2])
237
+ expect(testCache.findAll({ mutationKey: ['unknown'] })).toEqual([])
198
238
  })
199
239
  })
200
240
 
201
241
  describe('garbage collection', () => {
202
- test('should remove unused mutations after cacheTime has elapsed', async () => {
242
+ test('should remove unused mutations after gcTime has elapsed', async () => {
203
243
  const testCache = new MutationCache()
204
244
  const testClient = createQueryClient({ mutationCache: testCache })
205
245
  const onSuccess = jest.fn()
206
- await executeMutation(testClient, {
207
- mutationKey: ['a', 1],
208
- variables: 1,
209
- cacheTime: 10,
210
- mutationFn: () => Promise.resolve(),
211
- onSuccess,
212
- })
246
+ await executeMutation(
247
+ testClient,
248
+ {
249
+ mutationKey: ['a', 1],
250
+ gcTime: 10,
251
+ mutationFn: () => Promise.resolve(),
252
+ onSuccess,
253
+ },
254
+ 1,
255
+ )
213
256
 
214
257
  expect(testCache.getAll()).toHaveLength(1)
215
258
  await sleep(10)
@@ -222,9 +265,8 @@ describe('mutationCache', () => {
222
265
  test('should not remove mutations if there are active observers', async () => {
223
266
  const queryClient = createQueryClient()
224
267
  const observer = new MutationObserver(queryClient, {
225
- variables: 1,
226
- cacheTime: 10,
227
- mutationFn: () => Promise.resolve(),
268
+ gcTime: 10,
269
+ mutationFn: (input: number) => Promise.resolve(input),
228
270
  })
229
271
  const unsubscribe = observer.subscribe(() => undefined)
230
272
 
@@ -241,52 +283,11 @@ describe('mutationCache', () => {
241
283
  })
242
284
  })
243
285
 
244
- test('should only remove when the last observer unsubscribes', async () => {
245
- const queryClient = createQueryClient()
246
- const observer1 = new MutationObserver(queryClient, {
247
- variables: 1,
248
- cacheTime: 10,
249
- mutationFn: async () => {
250
- await sleep(10)
251
- return 'update1'
252
- },
253
- })
254
-
255
- const observer2 = new MutationObserver(queryClient, {
256
- cacheTime: 10,
257
- mutationFn: async () => {
258
- await sleep(10)
259
- return 'update2'
260
- },
261
- })
262
-
263
- await observer1.mutate()
264
-
265
- // we currently have no way to add multiple observers to the same mutation
266
- const currentMutation = observer1['currentMutation']!
267
- currentMutation.addObserver(observer1)
268
- currentMutation.addObserver(observer2)
269
-
270
- expect(currentMutation['observers'].length).toEqual(2)
271
- expect(queryClient.getMutationCache().getAll()).toHaveLength(1)
272
-
273
- currentMutation.removeObserver(observer1)
274
- currentMutation.removeObserver(observer2)
275
- expect(currentMutation['observers'].length).toEqual(0)
276
- expect(queryClient.getMutationCache().getAll()).toHaveLength(1)
277
- // wait for cacheTime to gc
278
- await sleep(10)
279
- await waitFor(() => {
280
- expect(queryClient.getMutationCache().getAll()).toHaveLength(0)
281
- })
282
- })
283
-
284
- test('should be garbage collected later when unsubscribed and mutation is loading', async () => {
286
+ test('should be garbage collected later when unsubscribed and mutation is pending', async () => {
285
287
  const queryClient = createQueryClient()
286
288
  const onSuccess = jest.fn()
287
289
  const observer = new MutationObserver(queryClient, {
288
- variables: 1,
289
- cacheTime: 10,
290
+ gcTime: 10,
290
291
  mutationFn: async () => {
291
292
  await sleep(20)
292
293
  return 'data'
@@ -298,22 +299,21 @@ describe('mutationCache', () => {
298
299
  unsubscribe()
299
300
  expect(queryClient.getMutationCache().getAll()).toHaveLength(1)
300
301
  await sleep(10)
301
- // unsubscribe should not remove even though cacheTime has elapsed b/c mutation is still loading
302
+ // unsubscribe should not remove even though gcTime has elapsed b/c mutation is still pending
302
303
  expect(queryClient.getMutationCache().getAll()).toHaveLength(1)
303
304
  await sleep(10)
304
- // should be removed after an additional cacheTime wait
305
+ // should be removed after an additional gcTime wait
305
306
  await waitFor(() => {
306
307
  expect(queryClient.getMutationCache().getAll()).toHaveLength(0)
307
308
  })
308
309
  expect(onSuccess).toHaveBeenCalledTimes(1)
309
310
  })
310
311
 
311
- test('should call callbacks even with cacheTime 0 and mutation still loading', async () => {
312
+ test('should call callbacks even with gcTime 0 and mutation still pending', async () => {
312
313
  const queryClient = createQueryClient()
313
314
  const onSuccess = jest.fn()
314
315
  const observer = new MutationObserver(queryClient, {
315
- variables: 1,
316
- cacheTime: 0,
316
+ gcTime: 0,
317
317
  mutationFn: async () => {
318
318
  return 'data'
319
319
  },