2
2
3
3
## What is this library?
4
4
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.
8
8
9
9
## Who is this library for?
10
10
@@ -36,7 +36,7 @@ test('iterate through renders with DOM snapshots', async () => {
36
36
const {takeRender , render } = createRenderStream ({
37
37
snapshotDOM: true ,
38
38
})
39
- const utils = render (< Counter / > )
39
+ const utils = await render (< Counter / > )
40
40
const incrementButton = utils .getByText (' Increment' )
41
41
await userEvent .click (incrementButton)
42
42
await userEvent .click (incrementButton)
@@ -58,36 +58,14 @@ test('iterate through renders with DOM snapshots', async () => {
58
58
})
59
59
```
60
60
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
-
83
61
### ` renderHookToSnapshotStream `
84
62
85
63
Usage is very similar to RTL's ` renderHook ` , but you get a ` snapshotStream `
86
64
object back that you can iterate with ` takeSnapshot ` calls.
87
65
88
66
``` jsx
89
67
test (' `useQuery` with `skip`' , async () => {
90
- const {takeSnapshot , rerender } = renderHookToSnapshotStream (
68
+ const {takeSnapshot , rerender } = await renderHookToSnapshotStream (
91
69
({skip}) => useQuery (query, {skip}),
92
70
{
93
71
wrapper : ({children}) => < Provider client= {client}> {children}< / Provider> ,
@@ -105,7 +83,7 @@ test('`useQuery` with `skip`', async () => {
105
83
expect (result .data ).toEqual ({hello: ' world 1' })
106
84
}
107
85
108
- rerender ({skip: true })
86
+ await rerender ({skip: true })
109
87
{
110
88
const snapshot = await takeSnapshot ()
111
89
expect (snapshot .loading ).toBe (false )
@@ -146,7 +124,7 @@ test('`useTrackRenders` with suspense', async () => {
146
124
}
147
125
148
126
const {takeRender , render } = createRenderStream ()
149
- render (< App / > )
127
+ await render (< App / > )
150
128
{
151
129
const {renderedComponents } = await takeRender ()
152
130
expect (renderedComponents).toEqual ([App, LoadingComponent])
@@ -179,7 +157,7 @@ test('custom snapshots with `replaceSnapshot`', async () => {
179
157
const {takeRender, replaceSnapshot, render} = createRenderStream <{
180
158
value: number
181
159
}>()
182
- const utils = render (<Counter />)
160
+ const utils = await render (<Counter />)
183
161
const incrementButton = utils .getByText (' Increment' )
184
162
await userEvent .click (incrementButton )
185
163
{
@@ -215,16 +193,14 @@ test('assertions in `onRender`', async () => {
215
193
)
216
194
}
217
195
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
+ })
228
204
const incrementButton = utils .getByText (' Increment' )
229
205
await userEvent .click (incrementButton )
230
206
await userEvent .click (incrementButton )
@@ -247,7 +223,7 @@ This library adds to matchers to `expect` that can be used like
247
223
248
224
``` tsx
249
225
test (' basic functionality' , async () => {
250
- const {takeRender} = renderToRenderStream (<RerenderingComponent />)
226
+ const {takeRender} = await renderToRenderStream (<RerenderingComponent />)
251
227
252
228
await expect (takeRender ).toRerender ()
253
229
await takeRender ()
@@ -285,17 +261,46 @@ await expect(snapshotStream).toRerender()
285
261
> [!TIP]
286
262
>
287
263
> 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 `
289
269
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 ` .
291
272
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.
295
277
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:
298
281
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