Skip to content

Commit c78a8ed

Browse files
authored
test(query-core): v5: infiniteQueryBehavior: 100% code coverage (#4994)
* test(query-core): infiniteQueryBehavior: manual pageParam * test(query-core): infiniteQueryBehavior: query cancellation * test(query-core): infiniteQueryBehavior: refetch cancel * test(query-core): infiniteQueryBehavior: no page param
1 parent e87d483 commit c78a8ed

File tree

1 file changed

+288
-2
lines changed

1 file changed

+288
-2
lines changed

packages/query-core/src/tests/infiniteQueryBehavior.test.tsx

Lines changed: 288 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import type {
33
QueryClient,
44
InfiniteQueryObserverResult,
55
} 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'
88

99
describe('InfiniteQueryBehavior', () => {
1010
let queryClient: QueryClient
@@ -179,4 +179,290 @@ describe('InfiniteQueryBehavior', () => {
179179

180180
unsubscribe()
181181
})
182+
183+
test('InfiniteQueryBehavior should apply pageParam', async () => {
184+
const key = queryKey()
185+
let abortSignal: AbortSignal | null = null
186+
187+
const queryFnSpy = jest.fn().mockImplementation(({ pageParam, signal }) => {
188+
abortSignal = signal
189+
return pageParam ?? 1
190+
})
191+
192+
const observer = new InfiniteQueryObserver<number>(queryClient, {
193+
queryKey: key,
194+
queryFn: queryFnSpy,
195+
})
196+
197+
let observerResult:
198+
| InfiniteQueryObserverResult<unknown, unknown>
199+
| undefined
200+
201+
const unsubscribe = observer.subscribe((result) => {
202+
observerResult = result
203+
})
204+
205+
// Wait for the first page to be fetched
206+
await waitFor(() =>
207+
expect(observerResult).toMatchObject({
208+
isFetching: false,
209+
data: { pages: [1], pageParams: [undefined] },
210+
}),
211+
)
212+
213+
queryFnSpy.mockClear()
214+
215+
// Fetch the next page using pageParam
216+
await observer.fetchNextPage({ pageParam: 2 })
217+
218+
expect(queryFnSpy).toHaveBeenNthCalledWith(1, {
219+
queryKey: key,
220+
pageParam: 2,
221+
meta: undefined,
222+
signal: abortSignal,
223+
})
224+
225+
expect(observerResult).toMatchObject({
226+
isFetching: false,
227+
data: { pages: [1, 2], pageParams: [undefined, 2] },
228+
})
229+
230+
queryFnSpy.mockClear()
231+
232+
// Fetch the previous page using pageParam
233+
await observer.fetchPreviousPage({ pageParam: 0 })
234+
235+
expect(queryFnSpy).toHaveBeenNthCalledWith(1, {
236+
queryKey: key,
237+
pageParam: 0,
238+
meta: undefined,
239+
signal: abortSignal,
240+
})
241+
242+
expect(observerResult).toMatchObject({
243+
isFetching: false,
244+
data: { pages: [0, 1, 2], pageParams: [0, undefined, 2] },
245+
})
246+
247+
queryFnSpy.mockClear()
248+
249+
// Refetch pages: old manual page params should be used
250+
await observer.refetch()
251+
252+
expect(queryFnSpy).toHaveBeenCalledTimes(3)
253+
254+
expect(queryFnSpy).toHaveBeenNthCalledWith(1, {
255+
queryKey: key,
256+
pageParam: 0,
257+
meta: undefined,
258+
signal: abortSignal,
259+
})
260+
261+
expect(queryFnSpy).toHaveBeenNthCalledWith(2, {
262+
queryKey: key,
263+
pageParam: undefined,
264+
meta: undefined,
265+
signal: abortSignal,
266+
})
267+
268+
expect(queryFnSpy).toHaveBeenNthCalledWith(3, {
269+
queryKey: key,
270+
pageParam: 2,
271+
meta: undefined,
272+
signal: abortSignal,
273+
})
274+
275+
unsubscribe()
276+
})
277+
278+
test('InfiniteQueryBehavior should support query cancellation', async () => {
279+
const key = queryKey()
280+
let abortSignal: AbortSignal | null = null
281+
282+
const queryFnSpy = jest
283+
.fn()
284+
.mockImplementation(({ pageParam = 1, signal }) => {
285+
abortSignal = signal
286+
sleep(10)
287+
return pageParam
288+
})
289+
290+
const observer = new InfiniteQueryObserver<number>(queryClient, {
291+
queryKey: key,
292+
queryFn: queryFnSpy,
293+
getNextPageParam: (lastPage) => lastPage + 1,
294+
getPreviousPageParam: (firstPage) => firstPage - 1,
295+
})
296+
297+
let observerResult:
298+
| InfiniteQueryObserverResult<unknown, unknown>
299+
| undefined
300+
301+
const unsubscribe = observer.subscribe((result) => {
302+
observerResult = result
303+
})
304+
305+
const query = observer.getCurrentQuery()
306+
query.cancel()
307+
308+
// Wait for the first page to be cancelled
309+
await waitFor(() =>
310+
expect(observerResult).toMatchObject({
311+
isFetching: false,
312+
isError: true,
313+
error: new CancelledError(),
314+
data: undefined,
315+
}),
316+
)
317+
318+
expect(queryFnSpy).toHaveBeenCalledTimes(1)
319+
320+
expect(queryFnSpy).toHaveBeenNthCalledWith(1, {
321+
queryKey: key,
322+
pageParam: undefined,
323+
meta: undefined,
324+
signal: abortSignal,
325+
})
326+
327+
unsubscribe()
328+
})
329+
330+
test('InfiniteQueryBehavior should not refetch pages if the query is cancelled', async () => {
331+
const key = queryKey()
332+
let abortSignal: AbortSignal | null = null
333+
334+
let queryFnSpy = jest
335+
.fn()
336+
.mockImplementation(({ pageParam = 1, signal }) => {
337+
abortSignal = signal
338+
return pageParam
339+
})
340+
341+
const observer = new InfiniteQueryObserver<number>(queryClient, {
342+
queryKey: key,
343+
queryFn: queryFnSpy,
344+
getNextPageParam: (lastPage) => lastPage + 1,
345+
getPreviousPageParam: (firstPage) => firstPage - 1,
346+
})
347+
348+
let observerResult:
349+
| InfiniteQueryObserverResult<unknown, unknown>
350+
| undefined
351+
352+
const unsubscribe = observer.subscribe((result) => {
353+
observerResult = result
354+
})
355+
356+
// Wait for the first page to be fetched
357+
await waitFor(() =>
358+
expect(observerResult).toMatchObject({
359+
isFetching: false,
360+
data: { pages: [1], pageParams: [undefined] },
361+
}),
362+
)
363+
364+
queryFnSpy.mockClear()
365+
366+
// Fetch the second page
367+
await observer.fetchNextPage()
368+
369+
expect(observerResult).toMatchObject({
370+
isFetching: false,
371+
data: { pages: [1, 2], pageParams: [undefined, 2] },
372+
})
373+
374+
expect(queryFnSpy).toHaveBeenCalledTimes(1)
375+
376+
expect(queryFnSpy).toHaveBeenNthCalledWith(1, {
377+
queryKey: key,
378+
pageParam: 2,
379+
meta: undefined,
380+
signal: abortSignal,
381+
})
382+
383+
queryFnSpy = jest.fn().mockImplementation(({ pageParam = 1, signal }) => {
384+
abortSignal = signal
385+
sleep(10)
386+
return pageParam
387+
})
388+
389+
// Refetch the query
390+
observer.refetch()
391+
expect(observerResult).toMatchObject({
392+
isFetching: true,
393+
isError: false,
394+
})
395+
396+
// Cancel the query
397+
const query = observer.getCurrentQuery()
398+
query.cancel()
399+
400+
expect(observerResult).toMatchObject({
401+
isFetching: false,
402+
isError: true,
403+
error: new CancelledError(),
404+
data: { pages: [1, 2], pageParams: [undefined, 2] },
405+
})
406+
407+
// Pages should not have been fetched
408+
expect(queryFnSpy).toHaveBeenCalledTimes(0)
409+
410+
unsubscribe()
411+
})
412+
413+
test('InfiniteQueryBehavior should return the current pages if no page param can be determined', async () => {
414+
const key = queryKey()
415+
let abortSignal: AbortSignal | null = null
416+
417+
const queryFnSpy = jest
418+
.fn()
419+
.mockImplementation(({ pageParam = 1, signal }) => {
420+
abortSignal = signal
421+
return pageParam
422+
})
423+
424+
const observer = new InfiniteQueryObserver<number>(queryClient, {
425+
queryKey: key,
426+
queryFn: queryFnSpy,
427+
})
428+
429+
let observerResult:
430+
| InfiniteQueryObserverResult<unknown, unknown>
431+
| undefined
432+
433+
const unsubscribe = observer.subscribe((result) => {
434+
observerResult = result
435+
})
436+
437+
// Wait for the first page to be fetched
438+
await waitFor(() =>
439+
expect(observerResult).toMatchObject({
440+
isFetching: false,
441+
data: { pages: [1], pageParams: [undefined] },
442+
}),
443+
)
444+
445+
expect(queryFnSpy).toHaveBeenNthCalledWith(1, {
446+
queryKey: key,
447+
pageParam: undefined,
448+
meta: undefined,
449+
signal: abortSignal,
450+
})
451+
452+
queryFnSpy.mockClear()
453+
454+
// Try to fetch a page without page param and getNextPageParam defined
455+
await observer.fetchNextPage()
456+
457+
// Current pages should be returned
458+
expect(observerResult).toMatchObject({
459+
isFetching: false,
460+
data: { pages: [1], pageParams: [undefined] },
461+
})
462+
463+
// queryFnSpy should not be called
464+
expect(queryFnSpy).toBeCalledTimes(0)
465+
466+
unsubscribe()
467+
})
182468
})

0 commit comments

Comments
 (0)