@@ -98,9 +98,12 @@ if (import.meta.vitest) {
9898 const { render, screen, act } = await import ( '@testing-library/react' ) ;
9999 const { userEvent } = await import ( '@testing-library/user-event' ) ;
100100 const MediaWikiAPIs = await import ( '../services/MediaWikiAPIs' ) ;
101+ const { QueryClient, QueryClientProvider } = await import ( '@tanstack/react-query' ) ;
102+ type QueryClientType = InstanceType < typeof QueryClient > ;
101103
102104 describe ( 'SearchForm' , ( ) => {
103105 const mockFormAction = vi . fn ( ) ;
106+ let queryClient : QueryClientType ;
104107 const defaultSearchState = {
105108 wikiUrl : new URL ( 'https://en.wikipedia.org' ) ,
106109 pageId : null ,
@@ -139,6 +142,9 @@ if (import.meta.vitest) {
139142
140143 beforeEach ( ( ) => {
141144 mockFormAction . mockClear ( ) ;
145+ queryClient = new QueryClient ( {
146+ defaultOptions : { queries : { retry : false } } ,
147+ } ) ;
142148 vi . spyOn ( MediaWikiAPIs , 'fetchPageId' ) . mockImplementation (
143149 mockFetchPageId
144150 ) ;
@@ -148,8 +154,16 @@ if (import.meta.vitest) {
148154 vi . restoreAllMocks ( ) ;
149155 } ) ;
150156
157+ const renderWithQuery = ( component : React . ReactElement ) => {
158+ return render (
159+ < QueryClientProvider client = { queryClient } >
160+ { component }
161+ </ QueryClientProvider >
162+ ) ;
163+ } ;
164+
151165 it ( 'renders form inputs and button' , async ( ) => {
152- await act ( async ( ) => render ( < SearchForm { ...defaultProps } /> ) ) ;
166+ await act ( async ( ) => renderWithQuery ( < SearchForm { ...defaultProps } /> ) ) ;
153167 expect ( screen . getByLabelText ( / W i k i A r t i c l e T i t l e : / i) ) . toBeInTheDocument ( ) ;
154168 expect ( screen . getByLabelText ( / T e x t t o F i n d : / i) ) . toBeInTheDocument ( ) ;
155169 expect (
@@ -159,7 +173,7 @@ if (import.meta.vitest) {
159173
160174 it ( 'submits form with correct FormData' , async ( ) => {
161175 const user = userEvent . setup ( ) ;
162- await act ( async ( ) => render ( < SearchForm { ...defaultProps } /> ) ) ;
176+ await act ( async ( ) => renderWithQuery ( < SearchForm { ...defaultProps } /> ) ) ;
163177 const titleInput = screen . getByLabelText ( / W i k i A r t i c l e T i t l e : / i) ;
164178 const textArea = screen . getByLabelText ( / T e x t t o F i n d : / i) ;
165179 const button = screen . getByRole ( 'button' , {
@@ -185,22 +199,22 @@ if (import.meta.vitest) {
185199 } ) ;
186200
187201 it ( 'renders the startRevId input field' , async ( ) => {
188- await act ( async ( ) => render ( < SearchForm { ...defaultProps } /> ) ) ;
202+ await act ( async ( ) => renderWithQuery ( < SearchForm { ...defaultProps } /> ) ) ;
189203 expect (
190204 screen . getByLabelText ( / S e a r c h f r o m R e v I D \( o p t i o n a l \) : / i)
191205 ) . toBeInTheDocument ( ) ;
192206 } ) ;
193207
194208 it ( 'renders the endRevId input field' , async ( ) => {
195- await act ( async ( ) => render ( < SearchForm { ...defaultProps } /> ) ) ;
209+ await act ( async ( ) => renderWithQuery ( < SearchForm { ...defaultProps } /> ) ) ;
196210 expect (
197211 screen . getByLabelText ( / E n d R e v I D \( o p t i o n a l \) : / i)
198212 ) . toBeInTheDocument ( ) ;
199213 } ) ;
200214
201215 it ( 'does not populate the endRevId input with the revisionId from searchState' , async ( ) => {
202216 await act ( async ( ) =>
203- render (
217+ renderWithQuery (
204218 < SearchForm
205219 formAction = { mockFormAction }
206220 isPending = { false }
@@ -220,7 +234,7 @@ if (import.meta.vitest) {
220234
221235 it ( 'submits form with correct FormData including endRevId' , async ( ) => {
222236 const user = userEvent . setup ( ) ;
223- await act ( async ( ) => render ( < SearchForm { ...defaultProps } /> ) ) ;
237+ await act ( async ( ) => renderWithQuery ( < SearchForm { ...defaultProps } /> ) ) ;
224238 const titleInput = screen . getByLabelText ( / W i k i A r t i c l e T i t l e : / i) ;
225239 const textArea = screen . getByLabelText ( / T e x t t o F i n d : / i) ;
226240 const endRevIdInput = screen . getByLabelText ( / E n d R e v I D \( o p t i o n a l \) : / i) ;
@@ -252,7 +266,7 @@ if (import.meta.vitest) {
252266 it ( 'does not submit when inputs are empty' , async ( ) => {
253267 const user = userEvent . setup ( ) ;
254268 await act ( async ( ) =>
255- render (
269+ renderWithQuery (
256270 < SearchForm
257271 { ...defaultProps }
258272 searchState = { {
@@ -272,7 +286,7 @@ if (import.meta.vitest) {
272286
273287 it ( 'disables the button when isPending is true' , async ( ) => {
274288 await act ( async ( ) =>
275- render (
289+ renderWithQuery (
276290 < SearchForm
277291 formAction = { mockFormAction }
278292 isPending = { true }
@@ -285,14 +299,14 @@ if (import.meta.vitest) {
285299 } ) ;
286300
287301 it ( 'renders the WikiSelector component' , async ( ) => {
288- await act ( async ( ) => render ( < SearchForm { ...defaultProps } /> ) ) ;
302+ await act ( async ( ) => renderWithQuery ( < SearchForm { ...defaultProps } /> ) ) ;
289303 expect ( screen . getByLabelText ( / W i k i S i t e : / i) ) . toBeInTheDocument ( ) ;
290304 } ) ;
291305
292306 it ( 'the selected option remains selected after form submission' , async ( ) => {
293307 const { fireEvent } = await import ( '@testing-library/react' ) ;
294308 const user = userEvent . setup ( ) ;
295- await act ( async ( ) => render ( < SearchForm { ...defaultProps } /> ) ) ;
309+ await act ( async ( ) => renderWithQuery ( < SearchForm { ...defaultProps } /> ) ) ;
296310 const wikiSelector =
297311 await screen . findByLabelText < HTMLSelectElement > ( / W i k i S i t e : / i) ;
298312
@@ -315,7 +329,7 @@ if (import.meta.vitest) {
315329
316330 it ( 'renders initial values from searchState' , async ( ) => {
317331 await act ( async ( ) =>
318- render (
332+ renderWithQuery (
319333 < SearchForm
320334 formAction = { mockFormAction }
321335 isPending = { false }
@@ -349,7 +363,7 @@ if (import.meta.vitest) {
349363 } ) ;
350364
351365 it ( 'renders the order radio buttons' , async ( ) => {
352- await act ( async ( ) => render ( < SearchForm { ...defaultProps } /> ) ) ;
366+ await act ( async ( ) => renderWithQuery ( < SearchForm { ...defaultProps } /> ) ) ;
353367 expect (
354368 screen . getByLabelText ( / A s c e n d i n g \( O l d e r F i r s t \) / i)
355369 ) . toBeInTheDocument ( ) ;
@@ -364,7 +378,7 @@ if (import.meta.vitest) {
364378 order : 'asc' as const ,
365379 } ;
366380 await act ( async ( ) =>
367- render ( < SearchForm { ...defaultProps } searchState = { searchStateAsc } /> )
381+ renderWithQuery ( < SearchForm { ...defaultProps } searchState = { searchStateAsc } /> )
368382 ) ;
369383 expect (
370384 screen . getByLabelText ( / D e s c e n d i n g \( N e w e r F i r s t \) / i)
@@ -377,7 +391,7 @@ if (import.meta.vitest) {
377391 order : 'asc' as const ,
378392 } ;
379393 const { rerender } = await act ( async ( ) =>
380- render (
394+ renderWithQuery (
381395 < SearchForm { ...emptySearchProps } searchState = { searchStateAsc } />
382396 )
383397 ) ;
@@ -396,7 +410,11 @@ if (import.meta.vitest) {
396410 order : 'desc' as const ,
397411 } ;
398412 await act ( async ( ) =>
399- rerender ( < SearchForm { ...defaultProps } searchState = { searchStateDesc } /> )
413+ rerender (
414+ < QueryClientProvider client = { queryClient } >
415+ < SearchForm { ...defaultProps } searchState = { searchStateDesc } />
416+ </ QueryClientProvider >
417+ )
400418 ) ;
401419 const radioAsc2 = screen . getByLabelText (
402420 / A s c e n d i n g \( O l d e r F i r s t \) / i
@@ -410,7 +428,7 @@ if (import.meta.vitest) {
410428
411429 it ( 'submits form with correct FormData including order' , async ( ) => {
412430 const user = userEvent . setup ( ) ;
413- await act ( async ( ) => render ( < SearchForm { ...defaultProps } /> ) ) ;
431+ await act ( async ( ) => renderWithQuery ( < SearchForm { ...defaultProps } /> ) ) ;
414432 const titleInput = screen . getByLabelText ( / W i k i A r t i c l e T i t l e : / i) ;
415433 const textArea = screen . getByLabelText ( / T e x t t o F i n d : / i) ;
416434 const descendingRadio = screen . getByLabelText (
0 commit comments