Open robertknight opened 5 years ago
It's an interesting idea - one difficulty, however, is that as you point out, in 16.8, act
is sync and doesn't allow a return value; in 16.9, it's more complex than that. If enzyme's going to have the API, it would ideally need to abstract over those differences.
Adapters do have an optional wrapInvoke
method already that wraps this, so adding it to enzyme would be trivial once the API is designed.
For components that use
useEffect
oruseState
, step (2) needs to be wrapped in anact
call in order to flush state and effects and followed by an explicit call towrapper.update()
to update the wrapper.
Is this definitely true? The README seems to indicate that the act
wrapping happens automatically with mount
.
In a recent test a colleague wrote, our calls to .simulate
(on a component that uses useState
) worked as it did in a pre-Hooks world. Our call to jest.runAllTimers
however had to be wrapped with act
and followed by an .update
.
Here's a snippet from our test:
// `mount` call and a few `.simulate` calls.
// ...
// This `simulate` causes a `setTimeout`, so we'll need to `runAllTimers` right after.
button.simulate('mouseleave');
// We were getting React `act` console errors until we wrapped the `runAllTimers` in `act`.
act(() => {
jest.runAllTimers();
});
// If we were to do a `wrapper.debug()` here, it would look like the`.simulate`
// and `jest.runAllTimers` had no effect. Running `.update` gets us into the expected state.
wrapper.update();
// ...
Regardless, I agree that it's a bit confusing. I'd be happy to help improve the README once I better understand the issue.
Is this definitely true? The README seems to indicate that the act wrapping happens automatically with mount.
You're right, it does. I should clarify that in step (2) I was referring to updates which happen a) after the initial render/mount and b) are triggered by an external event that doesn't go through an Enzyme API such as wrapper.simulate
. In your example, this would include advancing timers with jest. A manual act(...)
+ wrapper.update()
would also be required if you called an on<event>
prop directly rather than using "simulate", or triggered a state update by resolving a network fetch or something like that.
Is this proposal tied to https://github.com/airbnb/enzyme/issues/2073 ?
Is your feature request related to a problem? Please describe.
A common pattern in our Enzyme tests for components which use hooks is this:
For components that use
useEffect
oruseState
, step (2) needs to be wrapped in anact
call in order to flush state and effects and followed by an explicit call towrapper.update()
to update the wrapper.Describe the solution you'd like
Add a
wrapper.act(callback)
API which runs the provided callback, flushes any state or effect updates and then updates the wrapper. The current version ofact
is synchronous in React, but support has been added for React v16.9.0 for it to be async or even nested (see PR and umbrella issue.Example usage:
Describe alternatives you've considered
Require consumers to continue importing and calling
act()
from React's test utils followed bywrapper.update()
. This doesn't require a lot of code, but the main issue is that I think it is not obvious for beginners that this is needed.Caveats/issues
The
act
API is quite new in React. It could potentially change in future, although I think the concept of "a function which runs a callback and then flushes state updates & effects afterwards" seems pretty likely to stick around.I'm happy to draft a PR, but I wanted to get feedback on the API first.