22
33## What is this library?
44
5- This library allows you to make render-per- render assertions on your React
6- components and hooks. This is usually not necessary, but can be highly
7- beneficial when testing hot code paths.
5+ This library allows you to make committed- render-to-committed- render assertions
6+ on your React components and hooks. This is usually not necessary, but can be
7+ highly beneficial when testing hot code paths.
88
99## Who is this library for?
1010
@@ -36,7 +36,7 @@ test('iterate through renders with DOM snapshots', async () => {
3636 const {takeRender , render } = createRenderStream ({
3737 snapshotDOM: true ,
3838 })
39- const utils = render (< Counter / > )
39+ const utils = await render (< Counter / > )
4040 const incrementButton = utils .getByText (' Increment' )
4141 await userEvent .click (incrementButton)
4242 await userEvent .click (incrementButton)
@@ -58,36 +58,14 @@ test('iterate through renders with DOM snapshots', async () => {
5858})
5959```
6060
61- ### ` renderToRenderStream ` as a shortcut for ` createRenderStream ` and calling ` render `
62-
63- In every place you would call
64-
65- ``` js
66- const renderStream = createRenderStream (options)
67- const utils = renderStream .render (< Component / > , options)
68- ```
69-
70- you can also call
71-
72- ``` js
73- const renderStream = renderToRenderStream (< Component / > , combinedOptions)
74- // if required
75- const utils = await renderStream .renderResultPromise
76- ```
77-
78- This might be shorter (especially in cases where you don't need to access
79- ` utils ` ), but keep in mind that the render is executed ** asynchronously** after
80- calling ` renderToRenderStream ` , and that you need to ` await renderResultPromise `
81- if you need access to ` utils ` as returned by ` render ` .
82-
8361### ` renderHookToSnapshotStream `
8462
8563Usage is very similar to RTL's ` renderHook ` , but you get a ` snapshotStream `
8664object back that you can iterate with ` takeSnapshot ` calls.
8765
8866``` jsx
8967test (' `useQuery` with `skip`' , async () => {
90- const {takeSnapshot , rerender } = renderHookToSnapshotStream (
68+ const {takeSnapshot , rerender } = await renderHookToSnapshotStream (
9169 ({skip}) => useQuery (query, {skip}),
9270 {
9371 wrapper : ({children}) => < Provider client= {client}> {children}< / Provider> ,
@@ -105,7 +83,7 @@ test('`useQuery` with `skip`', async () => {
10583 expect (result .data ).toEqual ({hello: ' world 1' })
10684 }
10785
108- rerender ({skip: true })
86+ await rerender ({skip: true })
10987 {
11088 const snapshot = await takeSnapshot ()
11189 expect (snapshot .loading ).toBe (false )
@@ -146,7 +124,7 @@ test('`useTrackRenders` with suspense', async () => {
146124 }
147125
148126 const {takeRender , render } = createRenderStream ()
149- render (< App / > )
127+ await render (< App / > )
150128 {
151129 const {renderedComponents } = await takeRender ()
152130 expect (renderedComponents).toEqual ([App, LoadingComponent])
@@ -179,7 +157,7 @@ test('custom snapshots with `replaceSnapshot`', async () => {
179157 const {takeRender, replaceSnapshot, render} = createRenderStream <{
180158 value: number
181159 }>()
182- const utils = render (<Counter />)
160+ const utils = await render (<Counter />)
183161 const incrementButton = utils .getByText (' Increment' )
184162 await userEvent .click (incrementButton )
185163 {
@@ -215,16 +193,14 @@ test('assertions in `onRender`', async () => {
215193 )
216194 }
217195
218- const {takeRender, replaceSnapshot, renderResultPromise} =
219- renderToRenderStream <{
220- value: number
221- }>({
222- onRender(info ) {
223- // you can use `expect` here
224- expect (info .count ).toBe (info .snapshot .value + 1 )
225- },
226- })
227- const utils = await renderResultPromise
196+ const {takeRender, replaceSnapshot, utils} = await renderToRenderStream <{
197+ value: number
198+ }>({
199+ onRender(info ) {
200+ // you can use `expect` here
201+ expect (info .count ).toBe (info .snapshot .value + 1 )
202+ },
203+ })
228204 const incrementButton = utils .getByText (' Increment' )
229205 await userEvent .click (incrementButton )
230206 await userEvent .click (incrementButton )
@@ -247,7 +223,7 @@ This library adds to matchers to `expect` that can be used like
247223
248224``` tsx
249225test (' basic functionality' , async () => {
250- const {takeRender} = renderToRenderStream (<RerenderingComponent />)
226+ const {takeRender} = await renderToRenderStream (<RerenderingComponent />)
251227
252228 await expect (takeRender ).toRerender ()
253229 await takeRender ()
@@ -285,17 +261,46 @@ await expect(snapshotStream).toRerender()
285261> [!TIP]
286262>
287263> If you don't want these matchers not to be automatically installed, you can
288- > import from ` @testing- library/ react- render- stream` instead.
264+ > import from ` @testing- library/ react- render- stream/ pure` instead.
265+ > Keep in mind that if you use the ` / pure` import, you have to call the
266+ > ` cleanup` export manually after each test.
267+
268+ ## Usage side-by side with ` @testing- library/ react` or other tools that use ` act` or set ` IS_REACT_ACT_ENVIRONMENT `
289269
290- ## A note on ` act` .
270+ This library should not be used with ` act` , and it will throw an error if
271+ ` IS_REACT_ACT_ENVIRONMENT ` is ` true ` .
291272
292- You might want to avoid using this library with ` act` , as ` act`
293- [can end up batching multiple renders](https://github.com/facebook/react/issues/30031#issuecomment-2183951296)
294- into one in a way that would not happen in a production application.
273+ React Testing Library sets ` IS_REACT_ACT_ENVIRONMENT ` to ` true ` globally, and
274+ wraps some helpers like ` userEvent .click ` in ` act` calls.
275+ To use this library side-by-side with React Testing Library, we ship the
276+ ` disableActEnvironment` helper to undo these changes temporarily.
295277
296- While that is convenient in a normal test suite, it defeats the purpose of this
297- library.
278+ It returns a ` Disposable` and can be used together with the
279+ [` using` keyword](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-2.html#using-declarations-and-explicit-resource-management)
280+ to automatically clean up once the scope is left:
298281
299- Keep in mind that tools like ` userEvent .click ` use ` act` internally. Many of
300- those calls would only trigger one render anyways, so it can be okay to use
301- them, but avoid this for longer-running actions inside of ` act` calls.
282+ ` ` ` ts
283+ test (' my test' , () => {
284+ using _disabledAct = disableActEnvironment ()
285+
286+ // your test code here
287+
288+ // as soon as this scope is left, the environment will be cleaned up
289+ })
290+ ```
291+
292+ If you cannot use ` using ` , you can also manually call the returned ` cleanup `
293+ function. We recommend using ` finally ` to ensure the act environment is cleaned
294+ up if your test fails, otherwise it could leak between tests:
295+
296+ ``` ts
297+ test (' my test' , () => {
298+ const {cleanup} = disableActEnvironment ()
299+
300+ try {
301+ // your test code here
302+ } finally {
303+ cleanup ()
304+ }
305+ })
306+ ```
0 commit comments