@tanstack/query-core 5.59.16 → 5.59.20
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.
- package/build/legacy/queriesObserver.cjs +8 -0
- package/build/legacy/queriesObserver.cjs.map +1 -1
- package/build/legacy/queriesObserver.js +8 -0
- package/build/legacy/queriesObserver.js.map +1 -1
- package/build/modern/queriesObserver.cjs +8 -0
- package/build/modern/queriesObserver.cjs.map +1 -1
- package/build/modern/queriesObserver.js +8 -0
- package/build/modern/queriesObserver.js.map +1 -1
- package/package.json +3 -2
- package/src/queriesObserver.ts +9 -0
- package/src/__tests__/OmitKeyof.test-d.ts +0 -175
- package/src/__tests__/focusManager.test.tsx +0 -163
- package/src/__tests__/hydration.test.tsx +0 -1069
- package/src/__tests__/infiniteQueryBehavior.test.tsx +0 -427
- package/src/__tests__/infiniteQueryObserver.test-d.tsx +0 -64
- package/src/__tests__/infiniteQueryObserver.test.tsx +0 -198
- package/src/__tests__/mutationCache.test.tsx +0 -376
- package/src/__tests__/mutationObserver.test.tsx +0 -326
- package/src/__tests__/mutations.test.tsx +0 -603
- package/src/__tests__/notifyManager.test.tsx +0 -85
- package/src/__tests__/onlineManager.test.tsx +0 -168
- package/src/__tests__/queriesObserver.test.tsx +0 -267
- package/src/__tests__/query.test.tsx +0 -1049
- package/src/__tests__/queryCache.test.tsx +0 -350
- package/src/__tests__/queryClient.test-d.tsx +0 -156
- package/src/__tests__/queryClient.test.tsx +0 -2031
- package/src/__tests__/queryObserver.test-d.tsx +0 -108
- package/src/__tests__/queryObserver.test.tsx +0 -1236
- package/src/__tests__/utils.test.tsx +0 -468
- package/src/__tests__/utils.ts +0 -59
|
@@ -1,427 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
|
|
2
|
-
import { waitFor } from '@testing-library/react'
|
|
3
|
-
import { CancelledError, InfiniteQueryObserver } from '..'
|
|
4
|
-
import { createQueryClient, queryKey, sleep } from './utils'
|
|
5
|
-
import type {
|
|
6
|
-
InfiniteData,
|
|
7
|
-
InfiniteQueryObserverResult,
|
|
8
|
-
QueryCache,
|
|
9
|
-
QueryClient,
|
|
10
|
-
} from '..'
|
|
11
|
-
|
|
12
|
-
describe('InfiniteQueryBehavior', () => {
|
|
13
|
-
let queryClient: QueryClient
|
|
14
|
-
let queryCache: QueryCache
|
|
15
|
-
|
|
16
|
-
beforeEach(() => {
|
|
17
|
-
queryClient = createQueryClient()
|
|
18
|
-
queryCache = queryClient.getQueryCache()
|
|
19
|
-
queryClient.mount()
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
afterEach(() => {
|
|
23
|
-
queryClient.clear()
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
test('InfiniteQueryBehavior should throw an error if the queryFn is not defined', async () => {
|
|
27
|
-
const key = queryKey()
|
|
28
|
-
|
|
29
|
-
const observer = new InfiniteQueryObserver(queryClient, {
|
|
30
|
-
queryKey: key,
|
|
31
|
-
retry: false,
|
|
32
|
-
initialPageParam: 1,
|
|
33
|
-
getNextPageParam: () => 2,
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
let observerResult:
|
|
37
|
-
| InfiniteQueryObserverResult<unknown, unknown>
|
|
38
|
-
| undefined
|
|
39
|
-
|
|
40
|
-
const unsubscribe = observer.subscribe((result) => {
|
|
41
|
-
observerResult = result
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
await waitFor(() => {
|
|
45
|
-
const query = queryCache.find({ queryKey: key })!
|
|
46
|
-
return expect(observerResult).toMatchObject({
|
|
47
|
-
isError: true,
|
|
48
|
-
error: new Error(`Missing queryFn: '${query.queryHash}'`),
|
|
49
|
-
})
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
unsubscribe()
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
test('InfiniteQueryBehavior should apply the maxPages option to limit the number of pages', async () => {
|
|
56
|
-
const key = queryKey()
|
|
57
|
-
let abortSignal: AbortSignal | null = null
|
|
58
|
-
|
|
59
|
-
const queryFnSpy = vi.fn().mockImplementation(({ pageParam, signal }) => {
|
|
60
|
-
abortSignal = signal
|
|
61
|
-
return pageParam
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
const observer = new InfiniteQueryObserver<number>(queryClient, {
|
|
65
|
-
queryKey: key,
|
|
66
|
-
queryFn: queryFnSpy,
|
|
67
|
-
getNextPageParam: (lastPage) => lastPage + 1,
|
|
68
|
-
getPreviousPageParam: (firstPage) => firstPage - 1,
|
|
69
|
-
maxPages: 2,
|
|
70
|
-
initialPageParam: 1,
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
let observerResult:
|
|
74
|
-
| InfiniteQueryObserverResult<unknown, unknown>
|
|
75
|
-
| undefined
|
|
76
|
-
|
|
77
|
-
const unsubscribe = observer.subscribe((result) => {
|
|
78
|
-
observerResult = result
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
// Wait for the first page to be fetched
|
|
82
|
-
await waitFor(() =>
|
|
83
|
-
expect(observerResult).toMatchObject({
|
|
84
|
-
isFetching: false,
|
|
85
|
-
data: { pages: [1], pageParams: [1] },
|
|
86
|
-
}),
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
expect(queryFnSpy).toHaveBeenNthCalledWith(1, {
|
|
90
|
-
queryKey: key,
|
|
91
|
-
pageParam: 1,
|
|
92
|
-
meta: undefined,
|
|
93
|
-
direction: 'forward',
|
|
94
|
-
signal: abortSignal,
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
queryFnSpy.mockClear()
|
|
98
|
-
|
|
99
|
-
// Fetch the second page
|
|
100
|
-
await observer.fetchNextPage()
|
|
101
|
-
|
|
102
|
-
expect(queryFnSpy).toHaveBeenNthCalledWith(1, {
|
|
103
|
-
queryKey: key,
|
|
104
|
-
pageParam: 2,
|
|
105
|
-
direction: 'forward',
|
|
106
|
-
meta: undefined,
|
|
107
|
-
signal: abortSignal,
|
|
108
|
-
})
|
|
109
|
-
|
|
110
|
-
expect(observerResult).toMatchObject({
|
|
111
|
-
isFetching: false,
|
|
112
|
-
data: { pages: [1, 2], pageParams: [1, 2] },
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
queryFnSpy.mockClear()
|
|
116
|
-
|
|
117
|
-
// Fetch the page before the first page
|
|
118
|
-
await observer.fetchPreviousPage()
|
|
119
|
-
|
|
120
|
-
expect(queryFnSpy).toHaveBeenNthCalledWith(1, {
|
|
121
|
-
queryKey: key,
|
|
122
|
-
pageParam: 0,
|
|
123
|
-
direction: 'backward',
|
|
124
|
-
meta: undefined,
|
|
125
|
-
signal: abortSignal,
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
// Only first two pages should be in the data
|
|
129
|
-
expect(observerResult).toMatchObject({
|
|
130
|
-
isFetching: false,
|
|
131
|
-
data: { pages: [0, 1], pageParams: [0, 1] },
|
|
132
|
-
})
|
|
133
|
-
|
|
134
|
-
queryFnSpy.mockClear()
|
|
135
|
-
|
|
136
|
-
// Fetch the page before
|
|
137
|
-
await observer.fetchPreviousPage()
|
|
138
|
-
|
|
139
|
-
expect(queryFnSpy).toHaveBeenNthCalledWith(1, {
|
|
140
|
-
queryKey: key,
|
|
141
|
-
pageParam: -1,
|
|
142
|
-
meta: undefined,
|
|
143
|
-
direction: 'backward',
|
|
144
|
-
signal: abortSignal,
|
|
145
|
-
})
|
|
146
|
-
|
|
147
|
-
expect(observerResult).toMatchObject({
|
|
148
|
-
isFetching: false,
|
|
149
|
-
data: { pages: [-1, 0], pageParams: [-1, 0] },
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
queryFnSpy.mockClear()
|
|
153
|
-
|
|
154
|
-
// Fetch the page after
|
|
155
|
-
await observer.fetchNextPage()
|
|
156
|
-
|
|
157
|
-
expect(queryFnSpy).toHaveBeenNthCalledWith(1, {
|
|
158
|
-
queryKey: key,
|
|
159
|
-
pageParam: 1,
|
|
160
|
-
meta: undefined,
|
|
161
|
-
direction: 'forward',
|
|
162
|
-
signal: abortSignal,
|
|
163
|
-
})
|
|
164
|
-
|
|
165
|
-
expect(observerResult).toMatchObject({
|
|
166
|
-
isFetching: false,
|
|
167
|
-
data: { pages: [0, 1] },
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
queryFnSpy.mockClear()
|
|
171
|
-
|
|
172
|
-
// Refetch the infinite query
|
|
173
|
-
await observer.refetch()
|
|
174
|
-
|
|
175
|
-
// Only 2 pages should refetch
|
|
176
|
-
expect(queryFnSpy).toHaveBeenCalledTimes(2)
|
|
177
|
-
|
|
178
|
-
expect(queryFnSpy).toHaveBeenNthCalledWith(1, {
|
|
179
|
-
queryKey: key,
|
|
180
|
-
pageParam: 0,
|
|
181
|
-
meta: undefined,
|
|
182
|
-
direction: 'forward',
|
|
183
|
-
signal: abortSignal,
|
|
184
|
-
})
|
|
185
|
-
|
|
186
|
-
expect(queryFnSpy).toHaveBeenNthCalledWith(2, {
|
|
187
|
-
queryKey: key,
|
|
188
|
-
pageParam: 1,
|
|
189
|
-
meta: undefined,
|
|
190
|
-
direction: 'forward',
|
|
191
|
-
signal: abortSignal,
|
|
192
|
-
})
|
|
193
|
-
|
|
194
|
-
unsubscribe()
|
|
195
|
-
})
|
|
196
|
-
|
|
197
|
-
test('InfiniteQueryBehavior should support query cancellation', async () => {
|
|
198
|
-
const key = queryKey()
|
|
199
|
-
let abortSignal: AbortSignal | null = null
|
|
200
|
-
|
|
201
|
-
const queryFnSpy = vi.fn().mockImplementation(({ pageParam, signal }) => {
|
|
202
|
-
abortSignal = signal
|
|
203
|
-
sleep(10)
|
|
204
|
-
return pageParam
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
const observer = new InfiniteQueryObserver<number>(queryClient, {
|
|
208
|
-
queryKey: key,
|
|
209
|
-
queryFn: queryFnSpy,
|
|
210
|
-
getNextPageParam: (lastPage) => lastPage + 1,
|
|
211
|
-
getPreviousPageParam: (firstPage) => firstPage - 1,
|
|
212
|
-
initialPageParam: 1,
|
|
213
|
-
})
|
|
214
|
-
|
|
215
|
-
let observerResult:
|
|
216
|
-
| InfiniteQueryObserverResult<unknown, unknown>
|
|
217
|
-
| undefined
|
|
218
|
-
|
|
219
|
-
const unsubscribe = observer.subscribe((result) => {
|
|
220
|
-
observerResult = result
|
|
221
|
-
})
|
|
222
|
-
|
|
223
|
-
const query = observer.getCurrentQuery()
|
|
224
|
-
query.cancel()
|
|
225
|
-
|
|
226
|
-
// Wait for the first page to be cancelled
|
|
227
|
-
await waitFor(() =>
|
|
228
|
-
expect(observerResult).toMatchObject({
|
|
229
|
-
isFetching: false,
|
|
230
|
-
isError: true,
|
|
231
|
-
error: new CancelledError(),
|
|
232
|
-
data: undefined,
|
|
233
|
-
}),
|
|
234
|
-
)
|
|
235
|
-
|
|
236
|
-
expect(queryFnSpy).toHaveBeenCalledTimes(1)
|
|
237
|
-
|
|
238
|
-
expect(queryFnSpy).toHaveBeenNthCalledWith(1, {
|
|
239
|
-
queryKey: key,
|
|
240
|
-
pageParam: 1,
|
|
241
|
-
meta: undefined,
|
|
242
|
-
direction: 'forward',
|
|
243
|
-
signal: abortSignal,
|
|
244
|
-
})
|
|
245
|
-
|
|
246
|
-
unsubscribe()
|
|
247
|
-
})
|
|
248
|
-
|
|
249
|
-
test('InfiniteQueryBehavior should not refetch pages if the query is cancelled', async () => {
|
|
250
|
-
const key = queryKey()
|
|
251
|
-
let abortSignal: AbortSignal | null = null
|
|
252
|
-
|
|
253
|
-
let queryFnSpy = vi.fn().mockImplementation(({ pageParam, signal }) => {
|
|
254
|
-
abortSignal = signal
|
|
255
|
-
return pageParam
|
|
256
|
-
})
|
|
257
|
-
|
|
258
|
-
const observer = new InfiniteQueryObserver<number>(queryClient, {
|
|
259
|
-
queryKey: key,
|
|
260
|
-
queryFn: queryFnSpy,
|
|
261
|
-
getNextPageParam: (lastPage) => lastPage + 1,
|
|
262
|
-
getPreviousPageParam: (firstPage) => firstPage - 1,
|
|
263
|
-
initialPageParam: 1,
|
|
264
|
-
})
|
|
265
|
-
|
|
266
|
-
let observerResult:
|
|
267
|
-
| InfiniteQueryObserverResult<unknown, unknown>
|
|
268
|
-
| undefined
|
|
269
|
-
|
|
270
|
-
const unsubscribe = observer.subscribe((result) => {
|
|
271
|
-
observerResult = result
|
|
272
|
-
})
|
|
273
|
-
|
|
274
|
-
// Wait for the first page to be fetched
|
|
275
|
-
await waitFor(() =>
|
|
276
|
-
expect(observerResult).toMatchObject({
|
|
277
|
-
isFetching: false,
|
|
278
|
-
data: { pages: [1], pageParams: [1] },
|
|
279
|
-
}),
|
|
280
|
-
)
|
|
281
|
-
|
|
282
|
-
queryFnSpy.mockClear()
|
|
283
|
-
|
|
284
|
-
// Fetch the second page
|
|
285
|
-
await observer.fetchNextPage()
|
|
286
|
-
|
|
287
|
-
expect(observerResult).toMatchObject({
|
|
288
|
-
isFetching: false,
|
|
289
|
-
data: { pages: [1, 2], pageParams: [1, 2] },
|
|
290
|
-
})
|
|
291
|
-
|
|
292
|
-
expect(queryFnSpy).toHaveBeenCalledTimes(1)
|
|
293
|
-
|
|
294
|
-
expect(queryFnSpy).toHaveBeenNthCalledWith(1, {
|
|
295
|
-
queryKey: key,
|
|
296
|
-
pageParam: 2,
|
|
297
|
-
meta: undefined,
|
|
298
|
-
direction: 'forward',
|
|
299
|
-
signal: abortSignal,
|
|
300
|
-
})
|
|
301
|
-
|
|
302
|
-
queryFnSpy = vi.fn().mockImplementation(({ pageParam = 1, signal }) => {
|
|
303
|
-
abortSignal = signal
|
|
304
|
-
sleep(10)
|
|
305
|
-
return pageParam
|
|
306
|
-
})
|
|
307
|
-
|
|
308
|
-
// Refetch the query
|
|
309
|
-
observer.refetch()
|
|
310
|
-
expect(observerResult).toMatchObject({
|
|
311
|
-
isFetching: true,
|
|
312
|
-
isError: false,
|
|
313
|
-
})
|
|
314
|
-
|
|
315
|
-
// Cancel the query
|
|
316
|
-
const query = observer.getCurrentQuery()
|
|
317
|
-
query.cancel()
|
|
318
|
-
|
|
319
|
-
expect(observerResult).toMatchObject({
|
|
320
|
-
isFetching: false,
|
|
321
|
-
isError: true,
|
|
322
|
-
error: new CancelledError(),
|
|
323
|
-
data: { pages: [1, 2], pageParams: [1, 2] },
|
|
324
|
-
})
|
|
325
|
-
|
|
326
|
-
// Pages should not have been fetched
|
|
327
|
-
expect(queryFnSpy).toHaveBeenCalledTimes(0)
|
|
328
|
-
|
|
329
|
-
unsubscribe()
|
|
330
|
-
})
|
|
331
|
-
|
|
332
|
-
test('InfiniteQueryBehavior should not enter an infinite loop when a page errors while retry is on #8046', async () => {
|
|
333
|
-
let errorCount = 0
|
|
334
|
-
const key = queryKey()
|
|
335
|
-
|
|
336
|
-
interface TestResponse {
|
|
337
|
-
data: Array<{ id: string }>
|
|
338
|
-
nextToken?: number
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
const fakeData = [
|
|
342
|
-
{ data: [{ id: 'item-1' }], nextToken: 1 },
|
|
343
|
-
{ data: [{ id: 'item-2' }], nextToken: 2 },
|
|
344
|
-
{ data: [{ id: 'item-3' }], nextToken: 3 },
|
|
345
|
-
{ data: [{ id: 'item-4' }] },
|
|
346
|
-
]
|
|
347
|
-
|
|
348
|
-
const fetchData = async ({ nextToken = 0 }: { nextToken?: number }) =>
|
|
349
|
-
new Promise<TestResponse>((resolve, reject) => {
|
|
350
|
-
setTimeout(() => {
|
|
351
|
-
if (nextToken == 2 && errorCount < 3) {
|
|
352
|
-
errorCount += 1
|
|
353
|
-
reject({ statusCode: 429 })
|
|
354
|
-
return
|
|
355
|
-
}
|
|
356
|
-
resolve(fakeData[nextToken] as TestResponse)
|
|
357
|
-
}, 10)
|
|
358
|
-
})
|
|
359
|
-
|
|
360
|
-
const observer = new InfiniteQueryObserver<
|
|
361
|
-
TestResponse,
|
|
362
|
-
Error,
|
|
363
|
-
InfiniteData<TestResponse>,
|
|
364
|
-
TestResponse,
|
|
365
|
-
typeof key,
|
|
366
|
-
number
|
|
367
|
-
>(queryClient, {
|
|
368
|
-
retry: 5,
|
|
369
|
-
staleTime: 0,
|
|
370
|
-
retryDelay: 10,
|
|
371
|
-
|
|
372
|
-
queryKey: key,
|
|
373
|
-
initialPageParam: 1,
|
|
374
|
-
getNextPageParam: (lastPage) => lastPage.nextToken,
|
|
375
|
-
queryFn: ({ pageParam }) => fetchData({ nextToken: pageParam }),
|
|
376
|
-
})
|
|
377
|
-
|
|
378
|
-
// Fetch Page 1
|
|
379
|
-
const page1Data = await observer.fetchNextPage()
|
|
380
|
-
expect(page1Data.data?.pageParams).toEqual([1])
|
|
381
|
-
|
|
382
|
-
// Fetch Page 2, as per the queryFn, this will reject 2 times then resolves
|
|
383
|
-
const page2Data = await observer.fetchNextPage()
|
|
384
|
-
expect(page2Data.data?.pageParams).toEqual([1, 2])
|
|
385
|
-
|
|
386
|
-
// Fetch Page 3
|
|
387
|
-
const page3Data = await observer.fetchNextPage()
|
|
388
|
-
expect(page3Data.data?.pageParams).toEqual([1, 2, 3])
|
|
389
|
-
|
|
390
|
-
// Now the real deal; re-fetching this query **should not** stamp into an
|
|
391
|
-
// infinite loop where the retryer every time restarts from page 1
|
|
392
|
-
// once it reaches the page where it errors.
|
|
393
|
-
// For this to work, we'd need to reset the error count so we actually retry
|
|
394
|
-
errorCount = 0
|
|
395
|
-
const reFetchedData = await observer.refetch()
|
|
396
|
-
|
|
397
|
-
expect(reFetchedData.data?.pageParams).toEqual([1, 2, 3])
|
|
398
|
-
})
|
|
399
|
-
|
|
400
|
-
test('should fetch even if initialPageParam is null', async () => {
|
|
401
|
-
const key = queryKey()
|
|
402
|
-
|
|
403
|
-
const observer = new InfiniteQueryObserver(queryClient, {
|
|
404
|
-
queryKey: key,
|
|
405
|
-
queryFn: async () => 'data',
|
|
406
|
-
getNextPageParam: () => null,
|
|
407
|
-
initialPageParam: null,
|
|
408
|
-
})
|
|
409
|
-
|
|
410
|
-
let observerResult:
|
|
411
|
-
| InfiniteQueryObserverResult<unknown, unknown>
|
|
412
|
-
| undefined
|
|
413
|
-
|
|
414
|
-
const unsubscribe = observer.subscribe((result) => {
|
|
415
|
-
observerResult = result
|
|
416
|
-
})
|
|
417
|
-
|
|
418
|
-
await waitFor(() =>
|
|
419
|
-
expect(observerResult).toMatchObject({
|
|
420
|
-
isFetching: false,
|
|
421
|
-
data: { pages: ['data'], pageParams: [null] },
|
|
422
|
-
}),
|
|
423
|
-
)
|
|
424
|
-
|
|
425
|
-
unsubscribe()
|
|
426
|
-
})
|
|
427
|
-
})
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expectTypeOf, it, vi } from 'vitest'
|
|
2
|
-
import { InfiniteQueryObserver } from '..'
|
|
3
|
-
import { createQueryClient, queryKey } from './utils'
|
|
4
|
-
import type { InfiniteData, QueryClient } from '..'
|
|
5
|
-
|
|
6
|
-
describe('InfiniteQueryObserver', () => {
|
|
7
|
-
let queryClient: QueryClient
|
|
8
|
-
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
queryClient = createQueryClient()
|
|
11
|
-
queryClient.mount()
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
afterEach(() => {
|
|
15
|
-
queryClient.clear()
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
it('should be inferred as a correct result type', async () => {
|
|
19
|
-
const next: number | undefined = 2
|
|
20
|
-
const queryFn = vi.fn(({ pageParam }) => String(pageParam))
|
|
21
|
-
const observer = new InfiniteQueryObserver(queryClient, {
|
|
22
|
-
queryKey: queryKey(),
|
|
23
|
-
queryFn,
|
|
24
|
-
initialPageParam: 1,
|
|
25
|
-
getNextPageParam: () => next,
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
const result = observer.getCurrentResult()
|
|
29
|
-
|
|
30
|
-
if (result.isPending) {
|
|
31
|
-
expectTypeOf(result.data).toEqualTypeOf<undefined>()
|
|
32
|
-
expectTypeOf(result.error).toEqualTypeOf<null>()
|
|
33
|
-
expectTypeOf(result.isLoading).toEqualTypeOf<boolean>()
|
|
34
|
-
expectTypeOf(result.status).toEqualTypeOf<'pending'>()
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (result.isLoading) {
|
|
38
|
-
expectTypeOf(result.data).toEqualTypeOf<undefined>()
|
|
39
|
-
expectTypeOf(result.error).toEqualTypeOf<null>()
|
|
40
|
-
expectTypeOf(result.isPending).toEqualTypeOf<true>()
|
|
41
|
-
expectTypeOf(result.status).toEqualTypeOf<'pending'>()
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (result.isLoadingError) {
|
|
45
|
-
expectTypeOf(result.data).toEqualTypeOf<undefined>()
|
|
46
|
-
expectTypeOf(result.error).toEqualTypeOf<Error>()
|
|
47
|
-
expectTypeOf(result.status).toEqualTypeOf<'error'>()
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (result.isRefetchError) {
|
|
51
|
-
expectTypeOf(result.data).toEqualTypeOf<InfiniteData<string, unknown>>()
|
|
52
|
-
expectTypeOf(result.error).toEqualTypeOf<Error>()
|
|
53
|
-
expectTypeOf(result.status).toEqualTypeOf<'error'>()
|
|
54
|
-
expectTypeOf(result.isFetchNextPageError).toEqualTypeOf<boolean>()
|
|
55
|
-
expectTypeOf(result.isFetchPreviousPageError).toEqualTypeOf<boolean>()
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (result.isSuccess) {
|
|
59
|
-
expectTypeOf(result.data).toEqualTypeOf<InfiniteData<string, unknown>>()
|
|
60
|
-
expectTypeOf(result.error).toEqualTypeOf<null>()
|
|
61
|
-
expectTypeOf(result.status).toEqualTypeOf<'success'>()
|
|
62
|
-
}
|
|
63
|
-
})
|
|
64
|
-
})
|
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
|
|
2
|
-
import { InfiniteQueryObserver } from '..'
|
|
3
|
-
import { createQueryClient, queryKey, sleep } from './utils'
|
|
4
|
-
import type { QueryClient } from '..'
|
|
5
|
-
|
|
6
|
-
describe('InfiniteQueryObserver', () => {
|
|
7
|
-
let queryClient: QueryClient
|
|
8
|
-
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
queryClient = createQueryClient()
|
|
11
|
-
queryClient.mount()
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
afterEach(() => {
|
|
15
|
-
queryClient.clear()
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
test('InfiniteQueryObserver should be able to fetch an infinite query with selector', async () => {
|
|
19
|
-
const key = queryKey()
|
|
20
|
-
const observer = new InfiniteQueryObserver(queryClient, {
|
|
21
|
-
queryKey: key,
|
|
22
|
-
queryFn: () => 1,
|
|
23
|
-
select: (data) => ({
|
|
24
|
-
pages: data.pages.map((x) => `${x}`),
|
|
25
|
-
pageParams: data.pageParams,
|
|
26
|
-
}),
|
|
27
|
-
initialPageParam: 1,
|
|
28
|
-
getNextPageParam: () => 2,
|
|
29
|
-
})
|
|
30
|
-
let observerResult
|
|
31
|
-
const unsubscribe = observer.subscribe((result) => {
|
|
32
|
-
observerResult = result
|
|
33
|
-
})
|
|
34
|
-
await sleep(1)
|
|
35
|
-
unsubscribe()
|
|
36
|
-
expect(observerResult).toMatchObject({
|
|
37
|
-
data: { pages: ['1'], pageParams: [1] },
|
|
38
|
-
})
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
test('InfiniteQueryObserver should pass the meta option to the queryFn', async () => {
|
|
42
|
-
const meta = {
|
|
43
|
-
it: 'works',
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const key = queryKey()
|
|
47
|
-
const queryFn = vi.fn(() => 1)
|
|
48
|
-
const observer = new InfiniteQueryObserver(queryClient, {
|
|
49
|
-
meta,
|
|
50
|
-
queryKey: key,
|
|
51
|
-
queryFn,
|
|
52
|
-
select: (data) => ({
|
|
53
|
-
pages: data.pages.map((x) => `${x}`),
|
|
54
|
-
pageParams: data.pageParams,
|
|
55
|
-
}),
|
|
56
|
-
initialPageParam: 1,
|
|
57
|
-
getNextPageParam: () => 2,
|
|
58
|
-
})
|
|
59
|
-
let observerResult
|
|
60
|
-
const unsubscribe = observer.subscribe((result) => {
|
|
61
|
-
observerResult = result
|
|
62
|
-
})
|
|
63
|
-
await sleep(1)
|
|
64
|
-
unsubscribe()
|
|
65
|
-
expect(observerResult).toMatchObject({
|
|
66
|
-
data: { pages: ['1'], pageParams: [1] },
|
|
67
|
-
})
|
|
68
|
-
expect(queryFn).toBeCalledWith(expect.objectContaining({ meta }))
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
test('getNextPagParam and getPreviousPageParam should receive current pageParams', async () => {
|
|
72
|
-
const key = queryKey()
|
|
73
|
-
let single: Array<string> = []
|
|
74
|
-
let all: Array<string> = []
|
|
75
|
-
const observer = new InfiniteQueryObserver(queryClient, {
|
|
76
|
-
queryKey: key,
|
|
77
|
-
queryFn: ({ pageParam }) => String(pageParam),
|
|
78
|
-
initialPageParam: 1,
|
|
79
|
-
getNextPageParam: (_, __, lastPageParam, allPageParams) => {
|
|
80
|
-
single.push('next' + lastPageParam)
|
|
81
|
-
all.push('next' + allPageParams.join(','))
|
|
82
|
-
return lastPageParam + 1
|
|
83
|
-
},
|
|
84
|
-
getPreviousPageParam: (_, __, firstPageParam, allPageParams) => {
|
|
85
|
-
single.push('prev' + firstPageParam)
|
|
86
|
-
all.push('prev' + allPageParams.join(','))
|
|
87
|
-
return firstPageParam - 1
|
|
88
|
-
},
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
await observer.fetchNextPage()
|
|
92
|
-
await observer.fetchPreviousPage()
|
|
93
|
-
|
|
94
|
-
expect(single).toEqual(['next1', 'prev1', 'prev1', 'next1', 'prev0'])
|
|
95
|
-
expect(all).toEqual(['next1', 'prev1', 'prev1', 'next0,1', 'prev0,1'])
|
|
96
|
-
|
|
97
|
-
single = []
|
|
98
|
-
all = []
|
|
99
|
-
|
|
100
|
-
await observer.refetch()
|
|
101
|
-
|
|
102
|
-
expect(single).toEqual(['next0', 'next1', 'prev0'])
|
|
103
|
-
expect(all).toEqual(['next0', 'next0,1', 'prev0,1'])
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
test('should not invoke getNextPageParam and getPreviousPageParam on empty pages', async () => {
|
|
107
|
-
const key = queryKey()
|
|
108
|
-
|
|
109
|
-
const getNextPageParam = vi.fn()
|
|
110
|
-
const getPreviousPageParam = vi.fn()
|
|
111
|
-
|
|
112
|
-
const observer = new InfiniteQueryObserver(queryClient, {
|
|
113
|
-
queryKey: key,
|
|
114
|
-
queryFn: ({ pageParam }) => String(pageParam),
|
|
115
|
-
initialPageParam: 1,
|
|
116
|
-
getNextPageParam: getNextPageParam.mockImplementation(
|
|
117
|
-
(_, __, lastPageParam) => {
|
|
118
|
-
return lastPageParam + 1
|
|
119
|
-
},
|
|
120
|
-
),
|
|
121
|
-
getPreviousPageParam: getPreviousPageParam.mockImplementation(
|
|
122
|
-
(_, __, firstPageParam) => {
|
|
123
|
-
return firstPageParam - 1
|
|
124
|
-
},
|
|
125
|
-
),
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
const unsubscribe = observer.subscribe(() => {})
|
|
129
|
-
|
|
130
|
-
getNextPageParam.mockClear()
|
|
131
|
-
getPreviousPageParam.mockClear()
|
|
132
|
-
|
|
133
|
-
queryClient.setQueryData(key, { pages: [], pageParams: [] })
|
|
134
|
-
|
|
135
|
-
expect(getNextPageParam).toHaveBeenCalledTimes(0)
|
|
136
|
-
expect(getPreviousPageParam).toHaveBeenCalledTimes(0)
|
|
137
|
-
|
|
138
|
-
unsubscribe()
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
test('should stop refetching if undefined is returned from getNextPageParam', async () => {
|
|
142
|
-
const key = queryKey()
|
|
143
|
-
let next: number | undefined = 2
|
|
144
|
-
const queryFn = vi.fn<(...args: Array<any>) => any>(({ pageParam }) =>
|
|
145
|
-
String(pageParam),
|
|
146
|
-
)
|
|
147
|
-
const observer = new InfiniteQueryObserver(queryClient, {
|
|
148
|
-
queryKey: key,
|
|
149
|
-
queryFn,
|
|
150
|
-
initialPageParam: 1,
|
|
151
|
-
getNextPageParam: () => next,
|
|
152
|
-
})
|
|
153
|
-
|
|
154
|
-
await observer.fetchNextPage()
|
|
155
|
-
await observer.fetchNextPage()
|
|
156
|
-
|
|
157
|
-
expect(observer.getCurrentResult().data?.pages).toEqual(['1', '2'])
|
|
158
|
-
expect(queryFn).toBeCalledTimes(2)
|
|
159
|
-
expect(observer.getCurrentResult().hasNextPage).toBe(true)
|
|
160
|
-
|
|
161
|
-
next = undefined
|
|
162
|
-
|
|
163
|
-
await observer.refetch()
|
|
164
|
-
|
|
165
|
-
expect(observer.getCurrentResult().data?.pages).toEqual(['1'])
|
|
166
|
-
expect(queryFn).toBeCalledTimes(3)
|
|
167
|
-
expect(observer.getCurrentResult().hasNextPage).toBe(false)
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
test('should stop refetching if null is returned from getNextPageParam', async () => {
|
|
171
|
-
const key = queryKey()
|
|
172
|
-
let next: number | null = 2
|
|
173
|
-
const queryFn = vi.fn<(...args: Array<any>) => any>(({ pageParam }) =>
|
|
174
|
-
String(pageParam),
|
|
175
|
-
)
|
|
176
|
-
const observer = new InfiniteQueryObserver(queryClient, {
|
|
177
|
-
queryKey: key,
|
|
178
|
-
queryFn,
|
|
179
|
-
initialPageParam: 1,
|
|
180
|
-
getNextPageParam: () => next,
|
|
181
|
-
})
|
|
182
|
-
|
|
183
|
-
await observer.fetchNextPage()
|
|
184
|
-
await observer.fetchNextPage()
|
|
185
|
-
|
|
186
|
-
expect(observer.getCurrentResult().data?.pages).toEqual(['1', '2'])
|
|
187
|
-
expect(queryFn).toBeCalledTimes(2)
|
|
188
|
-
expect(observer.getCurrentResult().hasNextPage).toBe(true)
|
|
189
|
-
|
|
190
|
-
next = null
|
|
191
|
-
|
|
192
|
-
await observer.refetch()
|
|
193
|
-
|
|
194
|
-
expect(observer.getCurrentResult().data?.pages).toEqual(['1'])
|
|
195
|
-
expect(queryFn).toBeCalledTimes(3)
|
|
196
|
-
expect(observer.getCurrentResult().hasNextPage).toBe(false)
|
|
197
|
-
})
|
|
198
|
-
})
|