Skip to content

Commit e8bc524

Browse files
author
Jack Pope
committed
Add act documentation
1 parent b51108e commit e8bc524

File tree

3 files changed

+107
-3
lines changed

3 files changed

+107
-3
lines changed

src/content/reference/react/act.md

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
---
2+
title: act
3+
---
4+
5+
<Intro>
6+
7+
To prepare a component for assertions, wrap the code rendering it and performing updates inside an act() call. This makes your test run closer to how React works in the browser.
8+
9+
</Intro>
10+
11+
<InlineToc />
12+
13+
---
14+
15+
When writing UI tests, tasks like rendering, user events, or data fetching can be considered as “units” of interaction with a user interface. React provides a helper called `act()` that makes sure all updates related to these “units” have been processed and applied to the DOM before you make any assertions.
16+
17+
The name `act` comes from the [Arrange-Act-Assert](https://wiki.c2.com/?ArrangeActAssert) pattern.
18+
19+
```js
20+
act(() => {
21+
// render components
22+
});
23+
// make assertions
24+
```
25+
26+
## Usage {/*usage*/}
27+
28+
<Note>
29+
You might find using `act()` directly a bit too verbose. To avoid some of the boilerplate, you could use a library like [React Testing Library](https://testing-library.com/docs/react-testing-library/intro), whose helpers are wrapped with `act()`.
30+
</Note>
31+
32+
For example, let’s say we have this `Counter` component:
33+
34+
```js
35+
function Counter() {
36+
const [count, setCount] = useState(0);
37+
const handleClick = () => {
38+
setCount(prev => prev + 1);
39+
}
40+
41+
useEffect(() => {
42+
document.title = `You clicked ${this.state.count} times`;
43+
}, [count]);
44+
45+
return (
46+
<div>
47+
<p>You clicked {this.state.count} times</p>
48+
<button onClick={this.handleClick}>
49+
Click me
50+
</button>
51+
</div>
52+
)
53+
}
54+
```
55+
56+
Here is how we can test it:
57+
58+
```js
59+
import React from 'react';
60+
import ReactDOM from 'react-dom/client';
61+
import Counter from './Counter';
62+
63+
let container;
64+
65+
beforeEach(() => {
66+
container = document.createElement('div');
67+
document.body.appendChild(container);
68+
});
69+
70+
afterEach(() => {
71+
document.body.removeChild(container);
72+
container = null;
73+
});
74+
75+
it('can render and update a counter', () => {
76+
// Test first render and effect
77+
React.act(() => {
78+
ReactDOM.createRoot(container).render(<Counter />);
79+
});
80+
const button = container.querySelector('button');
81+
const label = container.querySelector('p');
82+
expect(label.textContent).toBe('You clicked 0 times');
83+
expect(document.title).toBe('You clicked 0 times');
84+
85+
// Test second render and effect
86+
React.act(() => {
87+
button.dispatchEvent(new MouseEvent('click', {bubbles: true}));
88+
});
89+
expect(label.textContent).toBe('You clicked 1 times');
90+
expect(document.title).toBe('You clicked 1 times');
91+
});
92+
93+
```
94+
95+
<Pitfall>
96+
97+
Don’t forget that dispatching DOM events only works when the DOM container is added to the document. You can use a library like [React Testing Library](https://testing-library.com/docs/react-testing-library/intro) to reduce the boilerplate code.
98+
99+
</Pitfall>

src/content/reference/react/apis.md

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ In addition to [Hooks](/reference/react) and [Components](/reference/react/compo
1515
* [`lazy`](/reference/react/lazy) lets you defer loading a component's code until it's rendered for the first time.
1616
* [`memo`](/reference/react/memo) lets your component skip re-renders with same props. Used with [`useMemo`](/reference/react/useMemo) and [`useCallback`.](/reference/react/useCallback)
1717
* [`startTransition`](/reference/react/startTransition) lets you mark a state update as non-urgent. Similar to [`useTransition`.](/reference/react/useTransition)
18+
* [`act`](/reference/react/act) lets you wrap renders and interactions in tests to ensure updates have processed before making assertions.
1819

1920
---
2021

src/sidebarReference.json

+7-3
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@
110110
"title": "APIs",
111111
"path": "/reference/react/apis",
112112
"routes": [
113+
{
114+
"title": "act",
115+
"path": "/reference/react/act"
116+
},
113117
{
114118
"title": "cache",
115119
"path": "/reference/react/cache"
@@ -297,8 +301,8 @@
297301
"path": "/reference/rules",
298302
"routes": [
299303
{
300-
"title": "Components and Hooks must be pure",
301-
"path": "/reference/rules/components-and-hooks-must-be-pure"
304+
"title": "Components and Hooks must be pure",
305+
"path": "/reference/rules/components-and-hooks-must-be-pure"
302306
},
303307
{
304308
"title": "React calls Components and Hooks",
@@ -379,4 +383,4 @@
379383
]
380384
}
381385
]
382-
}
386+
}

0 commit comments

Comments
 (0)