@@ -302,6 +302,8 @@ The custom render function should let us:
302302- Automatically wrap the component being tested with a ` <Provider store={store}> `
303303- Return the store instance in case the test needs to dispatch more actions or check state
304304
305+ For convenience, let's also set up a [ user instance] ( https://testing-library.com/docs/user-event/setup ) .
306+
305307A typical custom render function setup could look like this:
306308
307309``` tsx title="utils/test-utils.tsx"
@@ -334,6 +336,7 @@ export type AppStore = ReturnType<typeof setupStore>
334336import React , { PropsWithChildren } from ' react'
335337import { render } from ' @testing-library/react'
336338import type { RenderOptions } from ' @testing-library/react'
339+ import { userEvent } from ' @testing-library/user-event'
337340import { configureStore } from ' @reduxjs/toolkit'
338341import { Provider } from ' react-redux'
339342
@@ -362,9 +365,10 @@ export function renderWithProviders(
362365 <Provider store = { store } >{ children } </Provider >
363366 )
364367
365- // Return an object with the store and all of RTL's query functions
368+ // Return an object with the store, user, and all of RTL's query functions
366369 return {
367370 store ,
371+ user: userEvent .setup (),
368372 ... render (ui , { wrapper: Wrapper , ... renderOptions })
369373 }
370374}
@@ -416,6 +420,7 @@ export type AppDispatch = AppStore['dispatch']
416420import React , { PropsWithChildren } from ' react'
417421import { render } from ' @testing-library/react'
418422import type { RenderOptions } from ' @testing-library/react'
423+ import { userEvent } from ' @testing-library/user-event'
419424import { Provider } from ' react-redux'
420425
421426import { setupStore } from ' ../app/store'
@@ -437,7 +442,11 @@ export function renderWithProviders(
437442 function Wrapper({ children }: PropsWithChildren <{}>): JSX .Element {
438443 return <Provider store = { store } >{ children } </Provider >
439444 }
440- return { store , ... render (ui , { wrapper: Wrapper , ... renderOptions }) }
445+ return {
446+ store ,
447+ user: userEvent .setup (),
448+ ... render (ui , { wrapper: Wrapper , ... renderOptions })
449+ }
441450}
442451// file: app/hooks.tsx noEmit
443452import { useDispatch , useSelector } from ' react-redux'
@@ -471,7 +480,7 @@ import React from 'react'
471480import { beforeAll , afterEach , afterAll , test , expect } from ' vitest'
472481import { http , HttpResponse , delay } from ' msw'
473482import { setupServer } from ' msw/node'
474- import { fireEvent , screen } from ' @testing-library/react'
483+ import { screen } from ' @testing-library/react'
475484// We're using our own custom render function and not RTL's render.
476485import { renderWithProviders } from ' ../../../utils/test-utils'
477486import UserDisplay from ' ../UserDisplay'
@@ -498,14 +507,14 @@ afterEach(() => server.resetHandlers())
498507afterAll (() => server .close ())
499508
500509test (' fetches & receives a user after clicking the fetch user button' , async () => {
501- renderWithProviders (<UserDisplay />)
510+ const { user } = renderWithProviders (<UserDisplay />)
502511
503512 // should show no user initially, and not be fetching a user
504513 expect (screen .getByText (/ no user/ i )).toBeInTheDocument ()
505514 expect (screen .queryByText (/ Fetching user\.\.\. / i )).not .toBeInTheDocument ()
506515
507516 // after clicking the 'Fetch user' button, it should now show that it is fetching the user
508- fireEvent .click (screen .getByRole (' button' , { name: / Fetch user/ i }))
517+ await user .click (screen .getByRole (' button' , { name: / Fetch user/ i }))
509518 expect (screen .queryByText (/ no user/ i )).not .toBeInTheDocument ()
510519 expect (screen .getByText (/ Fetching user\.\.\. / i )).toBeInTheDocument ()
511520
0 commit comments