Skip to content

Commit 99690d1

Browse files
authored
test({react,preact}-query/usePrefetchInfiniteQuery): inline single-use helpers and adopt the 'pageParam' mock convention (#11079)
1 parent 10770f0 commit 99690d1

2 files changed

Lines changed: 84 additions & 105 deletions

File tree

packages/preact-query/src/__tests__/usePrefetchInfiniteQuery.test.tsx

Lines changed: 41 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { fireEvent } from '@testing-library/preact'
33
import type { VNode } from 'preact'
44
import { Suspense } from 'preact/compat'
55
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
6-
import type { Mock } from 'vitest'
76

87
import {
98
QueryCache,
@@ -13,33 +12,6 @@ import {
1312
} from '..'
1413
import { renderWithClient } from './utils'
1514

16-
const generateInfiniteQueryOptions = (
17-
data: Array<{ data: string; currentPage: number; totalPages: number }>,
18-
) => {
19-
let currentPage = 0
20-
21-
return {
22-
queryFn: vi
23-
.fn<(...args: Array<any>) => Promise<(typeof data)[number]>>()
24-
.mockImplementation(async () => {
25-
const currentPageData = data[currentPage]
26-
if (!currentPageData) {
27-
throw new Error(`No data defined for page ${currentPage}`)
28-
}
29-
30-
await sleep(10)
31-
currentPage++
32-
33-
return currentPageData
34-
}),
35-
initialPageParam: 1,
36-
getNextPageParam: (lastPage: (typeof data)[number]) =>
37-
lastPage.currentPage === lastPage.totalPages
38-
? undefined
39-
: lastPage.currentPage + 1,
40-
}
41-
}
42-
4315
describe('usePrefetchInfiniteQuery', () => {
4416
let queryCache: QueryCache
4517
let queryClient: QueryClient
@@ -60,18 +32,21 @@ describe('usePrefetchInfiniteQuery', () => {
6032

6133
it('should prefetch an infinite query if query state does not exist', async () => {
6234
const data = [
63-
{ data: 'Do you fetch on render?', currentPage: 1, totalPages: 3 },
64-
{ data: 'Or do you render as you fetch?', currentPage: 2, totalPages: 3 },
65-
{
66-
data: 'Either way, Tanstack Query helps you!',
67-
currentPage: 3,
68-
totalPages: 3,
69-
},
35+
'Do you fetch on render?',
36+
'Or do you render as you fetch?',
37+
'Either way, Tanstack Query helps you!',
7038
]
7139

7240
const queryOpts = {
7341
queryKey: queryKey(),
74-
...generateInfiniteQueryOptions(data),
42+
queryFn: vi
43+
.fn<(context: { pageParam: number }) => Promise<string>>()
44+
.mockImplementation(({ pageParam }) =>
45+
sleep(10).then(() => data[pageParam]!),
46+
),
47+
initialPageParam: 0,
48+
getNextPageParam: (_lastPage: string, allPages: Array<string>) =>
49+
allPages.length < data.length ? allPages.length : undefined,
7550
}
7651

7752
function Page() {
@@ -80,7 +55,7 @@ describe('usePrefetchInfiniteQuery', () => {
8055
return (
8156
<div>
8257
{state.data.pages.map((page, index) => (
83-
<div key={index}>data: {page.data}</div>
58+
<div key={index}>data: {page}</div>
8459
))}
8560
<button onClick={() => state.fetchNextPage()}>Next Page</button>
8661
</div>
@@ -114,26 +89,35 @@ describe('usePrefetchInfiniteQuery', () => {
11489
})
11590

11691
it('should not display fallback if the query cache is already populated', async () => {
92+
const data = [
93+
'Prefetch rocks!',
94+
'No waterfalls, boy!',
95+
'Tanstack Query #ftw',
96+
]
97+
11798
const queryOpts = {
11899
queryKey: queryKey(),
119-
...generateInfiniteQueryOptions([
120-
{ data: 'Prefetch rocks!', currentPage: 1, totalPages: 3 },
121-
{ data: 'No waterfalls, boy!', currentPage: 2, totalPages: 3 },
122-
{ data: 'Tanstack Query #ftw', currentPage: 3, totalPages: 3 },
123-
]),
100+
queryFn: vi
101+
.fn<(context: { pageParam: number }) => Promise<string>>()
102+
.mockImplementation(({ pageParam }) =>
103+
sleep(10).then(() => data[pageParam]!),
104+
),
105+
initialPageParam: 0,
106+
getNextPageParam: (_lastPage: string, allPages: Array<string>) =>
107+
allPages.length < data.length ? allPages.length : undefined,
124108
}
125109

126110
queryClient.prefetchInfiniteQuery({ ...queryOpts, pages: 3 })
127111
await vi.advanceTimersByTimeAsync(30)
128-
;(queryOpts.queryFn as Mock).mockClear()
112+
queryOpts.queryFn.mockClear()
129113

130114
function Page() {
131115
const state = useSuspenseInfiniteQuery(queryOpts)
132116

133117
return (
134118
<div>
135119
{state.data.pages.map((page, index) => (
136-
<div key={index}>data: {page.data}</div>
120+
<div key={index}>data: {page}</div>
137121
))}
138122
<button onClick={() => state.fetchNextPage()}>Next Page</button>
139123
</div>
@@ -162,13 +146,20 @@ describe('usePrefetchInfiniteQuery', () => {
162146
})
163147

164148
it('should not create an endless loop when using inside a suspense boundary', async () => {
149+
const data = ['Infinite Page 1', 'Infinite Page 2', 'Infinite Page 3']
150+
165151
const queryOpts = {
166152
queryKey: queryKey(),
167-
...generateInfiniteQueryOptions([
168-
{ data: 'Infinite Page 1', currentPage: 1, totalPages: 3 },
169-
{ data: 'Infinite Page 2', currentPage: 1, totalPages: 3 },
170-
{ data: 'Infinite Page 3', currentPage: 1, totalPages: 3 },
171-
]),
153+
queryFn: vi
154+
.fn<(context: { pageParam: number }) => Promise<string>>()
155+
.mockImplementation(({ pageParam }) =>
156+
sleep(10).then(() => data[pageParam]!),
157+
),
158+
initialPageParam: 0,
159+
// always reports another page available, to guard against an endless
160+
// auto-advance loop rather than a bounded pagination sequence
161+
getNextPageParam: (_lastPage: string, allPages: Array<string>) =>
162+
allPages.length,
172163
}
173164

174165
function Prefetch({ children }: { children: VNode }) {
@@ -182,7 +173,7 @@ describe('usePrefetchInfiniteQuery', () => {
182173
return (
183174
<div>
184175
{state.data.pages.map((page, index) => (
185-
<div key={index}>data: {page.data}</div>
176+
<div key={index}>data: {page}</div>
186177
))}
187178
<button onClick={() => state.fetchNextPage()}>Next Page</button>
188179
</div>

packages/react-query/src/__tests__/usePrefetchInfiniteQuery.test.tsx

Lines changed: 43 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -9,37 +9,6 @@ import {
99
useSuspenseInfiniteQuery,
1010
} from '..'
1111
import { renderWithClient } from './utils'
12-
import type { Mock } from 'vitest'
13-
14-
const createFallback = () =>
15-
vi.fn().mockImplementation(() => <div>Loading...</div>)
16-
17-
const generateInfiniteQueryOptions = (
18-
data: Array<{ data: string; currentPage: number; totalPages: number }>,
19-
) => {
20-
let currentPage = 0
21-
22-
return {
23-
queryFn: vi
24-
.fn<(...args: Array<any>) => Promise<(typeof data)[number]>>()
25-
.mockImplementation(async () => {
26-
const currentPageData = data[currentPage]
27-
if (!currentPageData) {
28-
throw new Error('No data defined for page ' + currentPage)
29-
}
30-
31-
await sleep(10)
32-
currentPage++
33-
34-
return currentPageData
35-
}),
36-
initialPageParam: 1,
37-
getNextPageParam: (lastPage: (typeof data)[number]) =>
38-
lastPage.currentPage === lastPage.totalPages
39-
? undefined
40-
: lastPage.currentPage + 1,
41-
}
42-
}
4312

4413
describe('usePrefetchInfiniteQuery', () => {
4514
let queryCache: QueryCache
@@ -57,20 +26,23 @@ describe('usePrefetchInfiniteQuery', () => {
5726
})
5827

5928
it('should prefetch an infinite query if query state does not exist', async () => {
60-
const Fallback = createFallback()
29+
const Fallback = vi.fn().mockImplementation(() => <div>Loading...</div>)
6130
const data = [
62-
{ data: 'Do you fetch on render?', currentPage: 1, totalPages: 3 },
63-
{ data: 'Or do you render as you fetch?', currentPage: 2, totalPages: 3 },
64-
{
65-
data: 'Either way, Tanstack Query helps you!',
66-
currentPage: 3,
67-
totalPages: 3,
68-
},
31+
'Do you fetch on render?',
32+
'Or do you render as you fetch?',
33+
'Either way, Tanstack Query helps you!',
6934
]
7035

7136
const queryOpts = {
7237
queryKey: queryKey(),
73-
...generateInfiniteQueryOptions(data),
38+
queryFn: vi
39+
.fn<(context: { pageParam: number }) => Promise<string>>()
40+
.mockImplementation(({ pageParam }) =>
41+
sleep(10).then(() => data[pageParam]!),
42+
),
43+
initialPageParam: 0,
44+
getNextPageParam: (_lastPage: string, allPages: Array<string>) =>
45+
allPages.length < data.length ? allPages.length : undefined,
7446
}
7547

7648
function Page() {
@@ -79,7 +51,7 @@ describe('usePrefetchInfiniteQuery', () => {
7951
return (
8052
<div>
8153
{state.data.pages.map((page, index) => (
82-
<div key={index}>data: {page.data}</div>
54+
<div key={index}>data: {page}</div>
8355
))}
8456
<button onClick={() => state.fetchNextPage()}>Next Page</button>
8557
</div>
@@ -113,27 +85,36 @@ describe('usePrefetchInfiniteQuery', () => {
11385
})
11486

11587
it('should not display fallback if the query cache is already populated', async () => {
116-
const Fallback = createFallback()
88+
const Fallback = vi.fn().mockImplementation(() => <div>Loading...</div>)
89+
const data = [
90+
'Prefetch rocks!',
91+
'No waterfalls, boy!',
92+
'Tanstack Query #ftw',
93+
]
94+
11795
const queryOpts = {
11896
queryKey: queryKey(),
119-
...generateInfiniteQueryOptions([
120-
{ data: 'Prefetch rocks!', currentPage: 1, totalPages: 3 },
121-
{ data: 'No waterfalls, boy!', currentPage: 2, totalPages: 3 },
122-
{ data: 'Tanstack Query #ftw', currentPage: 3, totalPages: 3 },
123-
]),
97+
queryFn: vi
98+
.fn<(context: { pageParam: number }) => Promise<string>>()
99+
.mockImplementation(({ pageParam }) =>
100+
sleep(10).then(() => data[pageParam]!),
101+
),
102+
initialPageParam: 0,
103+
getNextPageParam: (_lastPage: string, allPages: Array<string>) =>
104+
allPages.length < data.length ? allPages.length : undefined,
124105
}
125106

126107
queryClient.prefetchInfiniteQuery({ ...queryOpts, pages: 3 })
127108
await vi.advanceTimersByTimeAsync(30)
128-
;(queryOpts.queryFn as Mock).mockClear()
109+
queryOpts.queryFn.mockClear()
129110

130111
function Page() {
131112
const state = useSuspenseInfiniteQuery(queryOpts)
132113

133114
return (
134115
<div>
135116
{state.data.pages.map((page, index) => (
136-
<div key={index}>data: {page.data}</div>
117+
<div key={index}>data: {page}</div>
137118
))}
138119
<button onClick={() => state.fetchNextPage()}>Next Page</button>
139120
</div>
@@ -162,13 +143,20 @@ describe('usePrefetchInfiniteQuery', () => {
162143
})
163144

164145
it('should not create an endless loop when using inside a suspense boundary', async () => {
146+
const data = ['Infinite Page 1', 'Infinite Page 2', 'Infinite Page 3']
147+
165148
const queryOpts = {
166149
queryKey: queryKey(),
167-
...generateInfiniteQueryOptions([
168-
{ data: 'Infinite Page 1', currentPage: 1, totalPages: 3 },
169-
{ data: 'Infinite Page 2', currentPage: 1, totalPages: 3 },
170-
{ data: 'Infinite Page 3', currentPage: 1, totalPages: 3 },
171-
]),
150+
queryFn: vi
151+
.fn<(context: { pageParam: number }) => Promise<string>>()
152+
.mockImplementation(({ pageParam }) =>
153+
sleep(10).then(() => data[pageParam]!),
154+
),
155+
initialPageParam: 0,
156+
// always reports another page available, to guard against an endless
157+
// auto-advance loop rather than a bounded pagination sequence
158+
getNextPageParam: (_lastPage: string, allPages: Array<string>) =>
159+
allPages.length,
172160
}
173161

174162
function Prefetch({ children }: { children: React.ReactNode }) {
@@ -182,7 +170,7 @@ describe('usePrefetchInfiniteQuery', () => {
182170
return (
183171
<div>
184172
{state.data.pages.map((page, index) => (
185-
<div key={index}>data: {page.data}</div>
173+
<div key={index}>data: {page}</div>
186174
))}
187175
<button onClick={() => state.fetchNextPage()}>Next Page</button>
188176
</div>

0 commit comments

Comments
 (0)