In my simple React/ReactDOM/Enzyme unit test I get a warning from ReactDOM about wrapping any mutations to state in act()
. Why do I need to do this if my test passes anyway? I have 50 or so React components that all use hooks, custom hooks, etc. and I never wrap in act()
and they all pass.
Can I just disable this warning? I don't want to add extra code for what appears to be no reason.
The warning:
Warning: An update to MyComponent inside a test was not wrapped in act(...).
When testing, code that causes React state updates should be wrapped into act(...):
act(() => {
/* fire events that update state */
});
/* assert on the output */
This ensures that you're testing the behavior the user would see in the browser. Learn more at [redacted]
My test:
const App = () => {
const [isLoaded, setIsLoaded] = useState(false);
const myOnClick = () => {
setIsLoaded(true);
};
return (
<div onClick={myOnClick}>
{isLoaded ? 'Yes' : 'No'}
</div>
)
}
describe('My test', () => {
let wrapper
beforeAll(() => {
wrapper = mount(<App />)
})
it('renders "no"', () => {
expect(wrapper.text()).toBe('No')
})
describe('When onClick is called', () => {
beforeAll(() => {
wrapper.find('div').prop('onClick')()
})
it('renders "yes"', () => {
expect(wrapper.text()).toBe('Yes')
})
})
})
CodeSandbox repro: https://codesandbox.io/s/react-169-act-warning-repro-olm8o?expanddevtools=1&fontsize=14&hidenavigation=1&previewwindow=tests
act()
in first place runs all related useEffect
that would be async way otherwise. You don't see any difference since you don't have useEffect
in your component's code
According to Enzyme's docs in most recent version mount()
should be already wrapped with act()
internally:
If you're using React 16.8+ and
.mount()
, Enzyme will wrap apis including.simulate()
,.setProps()
,.setContext()
,.invoke()
withReactTestUtils.act()
so you don't need to manually wrap it.We cannot wrap the result of
.prop()
(or.props()
) with.act()
in Enzyme internally since it will break the equality of the returned value. However, you could use.invoke()
to simplify the code:
const wrapper = mount(<SomeComponent />);
wrapper.invoke('handler')();
expect(/* ... */);```
The line causing the act()
warning is
wrapper.find('div').prop('onClick')()
As @skyboyer's answer advised prop
is not wrapped with act
internally. When you call the onClick and update state, react is warning that something changed unexpectedly. If you use .simulate
instead you do not need to wrap it with act
.
wrapper.find('div').simulate('click')
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With