11import { queryKey , sleep } from '@tanstack/query-test-utils'
22import { act , fireEvent , render } from '@testing-library/preact'
3- import type { FunctionalComponent } from 'preact'
43import { Suspense , startTransition , useTransition } from 'preact/compat'
54import { useEffect , useRef , useState } from 'preact/hooks'
65import {
@@ -24,33 +23,18 @@ import type { UseSuspenseQueryOptions } from '..'
2423import { ErrorBoundary } from './ErrorBoundary'
2524import { renderWithClient } from './utils'
2625
27- type NumberQueryOptions = UseSuspenseQueryOptions < number >
28-
29- const QUERY_DURATION = 1000
30-
31- const createQuery : ( id : number ) => NumberQueryOptions = ( id ) => ( {
32- queryKey : [ id ] ,
33- queryFn : ( ) => sleep ( QUERY_DURATION ) . then ( ( ) => id ) ,
34- } )
35- const resolveQueries = async ( ) => {
36- await vi . advanceTimersByTimeAsync ( QUERY_DURATION )
37- }
38-
39- const queryClient = new QueryClient ( )
40-
4126describe ( 'useSuspenseQueries' , ( ) => {
27+ let queryClient : QueryClient
4228 const onSuspend = vi . fn ( )
4329 const onQueriesResolution = vi . fn ( )
4430
45- beforeAll ( ( ) => {
31+ beforeEach ( ( ) => {
4632 vi . useFakeTimers ( )
47- } )
48-
49- afterAll ( ( ) => {
50- vi . useRealTimers ( )
33+ queryClient = new QueryClient ( )
5134 } )
5235
5336 afterEach ( ( ) => {
37+ vi . useRealTimers ( )
5438 queryClient . clear ( )
5539 onSuspend . mockClear ( )
5640 onQueriesResolution . mockClear ( )
@@ -64,89 +48,199 @@ describe('useSuspenseQueries', () => {
6448 return < div > loading</ div >
6549 }
6650
67- const withSuspenseWrapper = < T extends object > (
68- Component : FunctionalComponent < T > ,
69- ) => {
70- function SuspendedComponent ( props : T ) {
71- return (
72- < Suspense fallback = { < SuspenseFallback /> } >
73- < Component { ...props } />
74- </ Suspense >
51+ it ( 'should suspend on mount' , ( ) => {
52+ function Page ( ) {
53+ const queriesResults = useSuspenseQueries (
54+ {
55+ queries : [ 1 , 2 ] . map ( ( id ) => ( {
56+ queryKey : [ id ] ,
57+ queryFn : ( ) => sleep ( 1000 ) . then ( ( ) => id ) ,
58+ } ) ) ,
59+ combine : ( results ) => results . map ( ( r ) => r . data ) ,
60+ } ,
61+ queryClient ,
7562 )
76- }
77-
78- return SuspendedComponent
79- }
80-
81- function QueriesContainer ( {
82- queries,
83- } : {
84- queries : Array < NumberQueryOptions >
85- } ) {
86- const queriesResults = useSuspenseQueries (
87- { queries, combine : ( results ) => results . map ( ( r ) => r . data ) } ,
88- queryClient ,
89- )
90-
91- useEffect ( ( ) => {
92- onQueriesResolution ( queriesResults )
93- } , [ queriesResults ] )
9463
95- return null
96- }
64+ useEffect ( ( ) => {
65+ onQueriesResolution ( queriesResults )
66+ } , [ queriesResults ] )
9767
98- const TestComponent = withSuspenseWrapper ( QueriesContainer )
68+ return null
69+ }
9970
100- it ( 'should suspend on mount' , ( ) => {
101- render ( < TestComponent queries = { [ 1 , 2 ] . map ( createQuery ) } /> )
71+ render (
72+ < Suspense fallback = { < SuspenseFallback /> } >
73+ < Page />
74+ </ Suspense > ,
75+ )
10276
10377 expect ( onSuspend ) . toHaveBeenCalledOnce ( )
10478 } )
10579
10680 it ( 'should resolve queries' , async ( ) => {
107- render ( < TestComponent queries = { [ 1 , 2 ] . map ( createQuery ) } /> )
81+ function Page ( ) {
82+ const queriesResults = useSuspenseQueries (
83+ {
84+ queries : [ 1 , 2 ] . map ( ( id ) => ( {
85+ queryKey : [ id ] ,
86+ queryFn : ( ) => sleep ( 1000 ) . then ( ( ) => id ) ,
87+ } ) ) ,
88+ combine : ( results ) => results . map ( ( r ) => r . data ) ,
89+ } ,
90+ queryClient ,
91+ )
10892
109- await act ( resolveQueries )
93+ useEffect ( ( ) => {
94+ onQueriesResolution ( queriesResults )
95+ } , [ queriesResults ] )
96+
97+ return null
98+ }
99+
100+ render (
101+ < Suspense fallback = { < SuspenseFallback /> } >
102+ < Page />
103+ </ Suspense > ,
104+ )
105+
106+ await act ( async ( ) => {
107+ await vi . advanceTimersByTimeAsync ( 1000 )
108+ } )
110109
111110 expect ( onQueriesResolution ) . toHaveBeenCalledTimes ( 1 )
112111 expect ( onQueriesResolution ) . toHaveBeenLastCalledWith ( [ 1 , 2 ] )
113112 } )
114113
115114 it ( 'should not suspend on mount if query has been already fetched' , ( ) => {
116- const query = createQuery ( 1 )
115+ const key = queryKey ( )
116+ const queryFn = ( ) => sleep ( 1000 ) . then ( ( ) => 1 )
117117
118- queryClient . setQueryData ( query . queryKey , query . queryFn )
118+ queryClient . setQueryData ( key , queryFn )
119119
120- render ( < TestComponent queries = { [ query ] } /> )
120+ function Page ( ) {
121+ const queriesResults = useSuspenseQueries (
122+ {
123+ queries : [ { queryKey : key , queryFn } ] ,
124+ combine : ( results ) => results . map ( ( r ) => r . data ) ,
125+ } ,
126+ queryClient ,
127+ )
128+
129+ useEffect ( ( ) => {
130+ onQueriesResolution ( queriesResults )
131+ } , [ queriesResults ] )
132+
133+ return null
134+ }
135+
136+ render (
137+ < Suspense fallback = { < SuspenseFallback /> } >
138+ < Page />
139+ </ Suspense > ,
140+ )
121141
122142 expect ( onSuspend ) . not . toHaveBeenCalled ( )
123143 } )
124144
125145 it ( 'should not break suspense when queries change without resolving' , async ( ) => {
126- const initQueries = [ 1 , 2 ] . map ( createQuery )
127- const nextQueries = [ 3 , 4 , 5 , 6 ] . map ( createQuery )
146+ const initQueries = [ 1 , 2 ] . map ( ( id ) => ( {
147+ queryKey : [ id ] ,
148+ queryFn : ( ) => sleep ( 1000 ) . then ( ( ) => id ) ,
149+ } ) )
150+ const nextQueries = [ 3 , 4 , 5 , 6 ] . map ( ( id ) => ( {
151+ queryKey : [ id ] ,
152+ queryFn : ( ) => sleep ( 1000 ) . then ( ( ) => id ) ,
153+ } ) )
154+
155+ function Page ( {
156+ queries,
157+ } : {
158+ queries : Array < UseSuspenseQueryOptions < number > >
159+ } ) {
160+ const queriesResults = useSuspenseQueries (
161+ {
162+ queries,
163+ combine : ( results ) => results . map ( ( r ) => r . data ) ,
164+ } ,
165+ queryClient ,
166+ )
167+
168+ useEffect ( ( ) => {
169+ onQueriesResolution ( queriesResults )
170+ } , [ queriesResults ] )
128171
129- const { rerender } = render ( < TestComponent queries = { initQueries } /> )
172+ return null
173+ }
130174
131- rerender ( < TestComponent queries = { nextQueries } /> )
175+ const { rerender } = render (
176+ < Suspense fallback = { < SuspenseFallback /> } >
177+ < Page queries = { initQueries } />
178+ </ Suspense > ,
179+ )
132180
133- await act ( resolveQueries )
181+ rerender (
182+ < Suspense fallback = { < SuspenseFallback /> } >
183+ < Page queries = { nextQueries } />
184+ </ Suspense > ,
185+ )
186+
187+ await act ( async ( ) => {
188+ await vi . advanceTimersByTimeAsync ( 1000 )
189+ } )
134190
135191 expect ( onSuspend ) . toHaveBeenCalled ( )
136192 // the test for onQueriesResolution is React-specific and not applicable to Preact
137193 } )
138194
139195 it ( 'should suspend only once per queries change' , async ( ) => {
140- const initQueries = [ 1 , 2 ] . map ( createQuery )
141- const nextQueries = [ 3 , 4 , 5 , 6 ] . map ( createQuery )
196+ const initQueries = [ 1 , 2 ] . map ( ( id ) => ( {
197+ queryKey : [ id ] ,
198+ queryFn : ( ) => sleep ( 1000 ) . then ( ( ) => id ) ,
199+ } ) )
200+ const nextQueries = [ 3 , 4 , 5 , 6 ] . map ( ( id ) => ( {
201+ queryKey : [ id ] ,
202+ queryFn : ( ) => sleep ( 1000 ) . then ( ( ) => id ) ,
203+ } ) )
204+
205+ function Page ( {
206+ queries,
207+ } : {
208+ queries : Array < UseSuspenseQueryOptions < number > >
209+ } ) {
210+ const queriesResults = useSuspenseQueries (
211+ {
212+ queries,
213+ combine : ( results ) => results . map ( ( r ) => r . data ) ,
214+ } ,
215+ queryClient ,
216+ )
217+
218+ useEffect ( ( ) => {
219+ onQueriesResolution ( queriesResults )
220+ } , [ queriesResults ] )
221+
222+ return null
223+ }
142224
143- const { rerender } = render ( < TestComponent queries = { initQueries } /> )
225+ const { rerender } = render (
226+ < Suspense fallback = { < SuspenseFallback /> } >
227+ < Page queries = { initQueries } />
228+ </ Suspense > ,
229+ )
144230
145- await act ( resolveQueries )
231+ await act ( async ( ) => {
232+ await vi . advanceTimersByTimeAsync ( 1000 )
233+ } )
146234
147- rerender ( < TestComponent queries = { nextQueries } /> )
235+ rerender (
236+ < Suspense fallback = { < SuspenseFallback /> } >
237+ < Page queries = { nextQueries } />
238+ </ Suspense > ,
239+ )
148240
149- await act ( resolveQueries )
241+ await act ( async ( ) => {
242+ await vi . advanceTimersByTimeAsync ( 1000 )
243+ } )
150244
151245 expect ( onSuspend ) . toHaveBeenCalledTimes ( 2 )
152246 expect ( onQueriesResolution ) . toHaveBeenCalledTimes ( 2 )
@@ -263,12 +357,16 @@ describe('useSuspenseQueries', () => {
263357} )
264358
265359describe ( 'useSuspenseQueries 2' , ( ) => {
360+ let queryClient : QueryClient
361+
266362 beforeEach ( ( ) => {
267363 vi . useFakeTimers ( )
364+ queryClient = new QueryClient ( )
268365 } )
269366
270367 afterEach ( ( ) => {
271368 vi . useRealTimers ( )
369+ queryClient . clear ( )
272370 } )
273371
274372 it ( 'should suspend all queries in parallel' , async ( ) => {
0 commit comments