react-testing-library: React 18. set state in finally throws "act" warning, though test is passing
@testing-library/reactversion: 13.1.1- Testing Framework and version: jest 27.5.1
- DOM Environment: jest-dom 27.5.1
Relevant code or config:
const handleSavedCardPayment = () => {
const paymentInfo = {
amount: formDataRef.current.amount,
userId,
accountId: formDataRef.current.selectedCardAccountId,
};
dispatch(makePayment(paymentInfo))
.then(handlePaymentSuccess)
.catch(noop) // already caught by thunk
.finally(() => {
formDataRef.current = null;
setSubmitting(false);
});
};
What you did:
NOTE: This error only shows up after updating to react 18 and testing library to 13.1.1, this was not an issue in earlier version.
setSubmitting toggles the button disability. When the promise is complete, it turns the re-enables the button. so the test is doing a waitFor button to be re-enabled.
the promise looks more like this
dispatch(makePayment(paymentInfo)) returns a promise, with a catch inside.
so the whole promise chain looks like this promisedFunction().then(() => do something).catch(error => show error). then(() => componentLevel).catch(do nothing here).finally(reset state)
What happened:

the “act” error is thrown, even though i’ve added a waitFor and that is passing to prove that that statement has already been rendered.
await waitFor(() => expect(screen.getByRole('button', { name: /submit/i })).not.toBeDisabled());
Problem description:
set state in finally seems to cause testing library to think act is incomplete, even though it is.
currently solving the error by putting the set state inside of catch

However, there’s the WET code, i had to put the set state into handlePaymentSuccess too, to achieve the same results.
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Reactions: 41
- Comments: 32 (6 by maintainers)
Commits related to this issue
- chore: upgrade version - migrate react-testing-library to support react 18 ([unsolved warning](https://github.com/testing-library/react-testing-library/issues/1051)) - vitest to 0.10.0 — committed to r2don/react-query-toolkit by lifeisegg123 2 years ago
- chore: upgrade version - migrate react-testing-library to support react 18 ([unsolved warning](https://github.com/testing-library/react-testing-library/issues/1051)) - vitest to 0.10.0 — committed to r2don/react-query-toolkit by lifeisegg123 2 years ago
- chore: upgrade version (#14) - migrate react-testing-library to support react 18 ([unsolved warning](https://github.com/testing-library/react-testing-library/issues/1051)) - vitest to 0.10.0 — committed to r2don/react-query-toolkit by lifeisegg123 2 years ago
- feat(PPDSC-2242): switch to user-event for floating-ui tests - https://floating-ui.com/docs/react-dom#testing - https://testing-library.com/docs/user-event/intro/#difference-to-fireevent - https://gi... — committed to newscorp-ghfb/NewsKit by mstuartf 2 years ago
- Revert "Update React and friend to latest version" * This reverts commit 5015f2619f88cf0bb105f10102ac98ebbe0e9722. * Wait until testing-library/react-testing-library#1051 gets fixed. — committed to openSUSE/agama by imobachgs 2 years ago
I appreciate all the additional info here, both from maintainers and other users. I have never really wrapped my head around
act(). I understand when it should be used, but I don’t fully understand what it’s actually doing. And I think because of that, I’m a bit unclear on what the right thing to do here is - to remove all of theseact()warnings which started showing up after upgrading to React 18.Is it something we as consumers should be doing differently in our tests? Something that needs to change on the React side? Something that needs to change in react-testing-library? Some combination of things? Something else entirely? Not clear yet?
I’m essentially delaying my upgrade to React 18, as a result of this issue, but it’s not quite clear to me what the eventual fix will be. So if someone is able to add some clarity there, I would really appreciate that. 🙏
I have a test roughly like this:
Clicking the button triggers an function with an API call roughly like this:
The test works fine, but React still gives me an
actwarning about thesetLoading(false)in thefinallyblock. Callingunmount()doesn’t help either.What I had to do was
waitForthe loading state to be set to false by testing itNow the
actwarning is gone, but this isn’t ideal IMO as🤷♂️
To be sure I’m not missing anything, I created two small codesandboxes with the same test.
In
@testing-lib/react@^12withreact@^17, the following simple test does not produce an act warning. (presumably becausewaitForis wrapped in an act)https://codesandbox.io/s/act-warning-waitfor-react-17-btzykv
The component under test, shows some text on click after a few ms
The same setup with
@testing-library/react@^13andreact@18, now produces a warning.https://codesandbox.io/s/act-warning-wait-for-react-18-w4e521
@eps1lon is this really the intended behaviour from now on or am I missing/misunderstanding something?
It also seems like
waitForsetsglobal.IS_REACT_ACT_ENVIRONMENTto be false while it executes, which can cause theThe current testing environment is not configured to support act(...)warning when one tries to manually wrap certain calls withact(I still need to wrap my head around this one 😅)Example sandbox for this behaviour: https://codesandbox.io/s/act-warning-wait-for-react-18-forked-nc2mm8?file=/src/App.test.js
Based on my tests, it looks like
cleanupisn’t being called at the end of every test as it used to. For me, if I manually unmount the component or call thecleanupfunction, theacterrors go away.Edit:
Note that calling
cleanupin anafterEachwill not work. You will have to actually call it at the bottom of the test. Something like thisI am having a similar problem after updating to
react 18.2.0and@testing-library/react 13.3.0. Some of my calls to dispatch store actions need to be wrapped inawait act(async () => {...} ). I thought that @testing-library/react took care of theactwrapping for us.Hey guys, i made some tests because I am having the same problem: This is what I got.
This way it works fine:
But if I change to userEvent, I get the act() warning all over again.
We are able to spot-fix tests by wrapping in act, but tests then fail previously passing cases with strange outputs that do not match manual testing.
Not to mention in our large-ish codebase, its nigh impossible to manually update the 1000+ tests we have…
I’m using react-hook-form and experience the same act warning. Using either
waitFororwaitForElementToBeRemoveddoesn’t remove the warning.The only thing that worked is to wrap act with sleep.
credit to https://bufferings.hatenablog.com/entry/2021/11/18/015809
@eps1lon Is my example in this comment not sufficient to demonstrate the issue?
Having struggled with a lot of
test was not wrapped in act(...)warnings in our tests as well, I noticed we had added@testing-library/domin our project dependencies. On re-reading the @testing-library/user-event install guide it advises not to do this:On removing the dependency from our
package.jsonall the warnings were gone. This may not be a fix for all the described issues, though adding comment here incase this helps any others having similar struggles.For info, currently using:
I’m running into the same problem upgrading my App to React 18, and RTL to 13.3.0.
In my case, I’ve even got a test which triggers an
actwarning for every letter pressed fromawait user.type()triggering anonChangehandler, which just calls a setter from a useState hook.Even if I add
await waitFor(() => expect(myInput).toHaveValue(finalValue)it still throws the warnings (amongst hundreds of other act warnings in my other tests).I have observed the same behavior as @JoeyAtSS. After update to the latest React 18 and the latest RTL, we had to change following across whole application, otherwise error from above is shown:
We also observed https://github.com/testing-library/react-testing-library/issues/1057. Unfortunately, I haven’t observed pattern in which it happens.
@eps1lon I replicated our issue here: https://codesandbox.io/s/rtl-react-18-act-issue-forked-l0bcj2?file=/src/__tests__/App.test.js.
You can see this error when you run tests and check the output in the console. In our case it’s triggered by a component that uses
react-querywith dynamic import.We’re getting these warnings/errors in other places as well (e.g. we had 2
getByText(...).click()calls right after each other and after updating to React 18, I had to wrap each in a separateactcall), but I wasn’t able to create a minimal example for these.I encountered something similar while using Formik, I suspect this is related. Here is a repo which reproduces this issue:
This only happens on the new version of RTL and React 18.
https://github.com/testing-library/react-testing-library/blob/9171163fccf0a7ea43763475ca2980898b4079a5/src/pure.js#L19-L24 It looks like this is the culprit, it disables the “act environment” while running
waitFor. This doesn’t make sense to me, any particular reason for doing this @eps1lon?It was already mentioned by others, but making sure that we only have one version of
@testing-library/domlibrary helped us significantly reduce number of these warnings.If you use yarn, you can run
yarn why @testing-library/domto see how many versions of this library you have and why. If you have more than one, it’s probably best to uninstall all libraries that depend on it and reinstall them.I guess the documentation for
act()could be more explicit about this. It’s somewhat implied by “state updates have been processed at the end” but I can see how this is fairly ambigiousIf inside an
actscope no state updates, effects etc are flushed. Only at the end. Which is why it wouldn’t make sense to wrap a waiting period inactLike others have mentioned, we’re also seeing this pervasively after upgrading to react 18 and latest RTL.
Hoping for a solution that doesn’t involve wrapping all our tests in additional
actor addingcleanup()to every test or what have you.Edit: In my case, it seems it’s caused by https://github.com/remix-run/react-router/issues/7634 as we’re also upgrading to react router v6 as part of this.
The
useNavigate()hook does not return a stable reference, and using it it in the dependency array of auseEffectcauses anyuseEffectto run again if the location changes. The end result of this is that if a test navigates as part of the user interaction, the useEffect gets triggered again and if it updates state, it may be doing so after the test has passed and completed.Just putting this here in case it helps any one else dropping by.
Just to add to this, we’ve noticed our tests riddled with act errors since moving to react 18. I’ve been able to solve most by swapping getBy to findBys and using waitFors however it has been a pain updating pretty much every test. In addition, I also had to enable
globalThis.IS_REACT_ACT_ENVIRONMENT = true;so that I could use act errors to fix the state updates that I couldn’t control via a findBy.@eps1lon here is what I found out…
29.4.3have act warning…"jest": "^29.4.3""jest-environment-jsdom": "^29.4.3"but
29.3.1is working perfectly"jest": "^29.3.1""jest-environment-jsdom": "^29.3.1"@smellai give it a try, hope can help to solve itI’m getting more
actwarnings now with@testing-library@14.0.0. Tested withawait waitFor, and still throwingactwarnings with userEvent that triggers a state change.Tested version: “jest”: “29.4.3”, “@testing-library/jest-dom”: “5.16.5”, “@testing-library/react”: “14.0.0”, “@testing-library/user-event”: “14.4.3”,
Fixed in https://github.com/testing-library/react-testing-library/pull/1137 Released in
@testing-library@14.0.0