Skip to content

React 18. set state in finally throws "act" warning, though test is passing #1051

@JoeyAtSS

Description

@JoeyAtSS
  • @testing-library/react version: 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:

image

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
image

However, there's the WET code, i had to put the set state into handlePaymentSuccess too, to achieve the same results.

Activity

intercaetera

intercaetera commented on Apr 19, 2022

@intercaetera

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.

clothoo

clothoo commented on Apr 28, 2022

@clothoo

I'm using react-hook-form and experience the same act warning. Using either waitFor or waitForElementToBeRemoved doesn't remove the warning.

The only thing that worked is to wrap act with sleep.

  await act(async () => {
    await new Promise((resolve) => {
      setTimeout(resolve, 50);
    });
  });

credit to https://bufferings.hatenablog.com/entry/2021/11/18/015809

added a commit that references this issue on May 1, 2022
hlmnd

hlmnd commented on May 3, 2022

@hlmnd
eps1lon

eps1lon commented on May 21, 2022

@eps1lon
Member

It doesn't look like this bug report has enough info for one of us to reproduce it.

Please provide a CodeSandbox (https://react.new), or a link to a repository on GitHub.

Here are some tips for providing a minimal example: https://stackoverflow.com/help/mcve

intercaetera

intercaetera commented on May 26, 2022

@intercaetera

@eps1lon Is my example in this comment not sufficient to demonstrate the issue?

bedrich-schindler

bedrich-schindler commented on Jun 8, 2022

@bedrich-schindler

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:

image

We also observed #1057. Unfortunately, I haven't observed pattern in which it happens.

guilhermegalabarof

guilhermegalabarof commented on Jun 24, 2022

@guilhermegalabarof

Hey guys, i made some tests because I am having the same problem:
This is what I got.

"@testing-library/react": "^13.3.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"@testing-library/user-event": "^14.2.1",

// it pass without act() warning
fireEvent.change(loginField, { target: { value: '' } })
expect(loginField).toHaveValue('')

// it gives the act() warning
fireEvent.change(loginField, { target: { value: '' } })
await waitFor(async () => {
  expect(loginField).toHaveValue('')
})

// don't wait the render - error
fireEvent.click(loginButton)
expect(screen.queryAllByText('Campo obrigatório')).toHaveLength(2)

// it pass all fine :)
fireEvent.click(loginButton)
await waitFor(async () => {
  expect(screen.queryAllByText('Campo obrigatório')).toHaveLength(2)
})

This way it works fine:

// it pass without act() warning
fireEvent.change(loginField, { target: { value: '' } })
expect(loginField).toHaveValue('') 

But if I change to userEvent, I get the act() warning all over again.

userEvent.clear(loginField)
expect(loginField).toHaveValue('')

bobsilverberg

bobsilverberg commented on Jun 30, 2022

@bobsilverberg

I am having a similar problem after updating to react 18.2.0 and @testing-library/react 13.3.0. Some of my calls to dispatch store actions need to be wrapped in await act(async () => {...} ). I thought that @testing-library/react took care of the act wrapping for us.

szimek

szimek commented on Jul 4, 2022

@szimek

@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-query with 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 separate act call), but I wasn't able to create a minimal example for these.

thepuzzlemaster

thepuzzlemaster commented on Jul 7, 2022

@thepuzzlemaster

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 act warning for every letter pressed from await user.type() triggering an onChange handler, 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).

23 remaining items

szymonnowak-st

szymonnowak-st commented on Dec 14, 2022

@szymonnowak-st

It was already mentioned by others, but making sure that we only have one version of @testing-library/dom library helped us significantly reduce number of these warnings.

If you use yarn, you can run yarn why @testing-library/dom to 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.

cristianrodri

cristianrodri commented on Feb 1, 2023

@cristianrodri

I just upgraded @testing-library/dom to the latest version. yarn add -D @testing-library/dom@latest

eps1lon

eps1lon commented on Feb 16, 2023

@eps1lon
Member

@eps1lon Is my example in #1051 (comment) comment not sufficient to demonstrate the issue?

@intercaetera It's not runnable. Even after fixing the lockfile (npm ci failed), npm test I got a Validation Error. Repros need to be minimal and easily reproducible.

The repro from @szimek worked i.e. I could reproduce the bug with their repro. It also had problems though since it didn't have a lockfile. NPM couldn't even install it anymore. Only yarn succeeded.
@szimek I could fix the missing-act warning with #1137 but the test is still failing which seems correct. The image is already rendered so the waitFor is not actually waiting for the data to render.

The 3rd repro from @robin-drexler finally worked (though still missing a lockfile). However, it's a clear example of a missing act. The warning got fixed by wrapping the state update in act:

-    await new Promise((resolve) => {
-      setTimeout(resolve, 300);
+    await act(async () => {
+      await new Promise((resolve) => {
+        setTimeout(resolve, 300);
+      });

In the future, please make sure repros are minimal and runnable indefinitely in the futre (e.g. they have a lockfile ensuring the same install, they have a Node.js version.

The repro from @szimek looks like a duplicate to #1125 so I'll close this issue once we land #1137

eps1lon

eps1lon commented on Feb 16, 2023

@eps1lon
Member

Fixed in #1137
Released in @testing-library@14.0.0

annidai

annidai commented on Feb 17, 2023

@annidai

I'm getting more act warnings now with @testing-library@14.0.0.
Tested with await waitFor, and still throwing act warnings 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",

zigang93

zigang93 commented on Feb 20, 2023

@zigang93

@testing-library@14.0.0 still have same act warning

smellai

smellai commented on Feb 20, 2023

@smellai

@testing-library@14.0.0 still have same act warning

+1

zigang93

zigang93 commented on Feb 20, 2023

@zigang93

@eps1lon here is what I found out..

29.4.3 have act warning..
"jest": "^29.4.3"
"jest-environment-jsdom": "^29.4.3"

but 29.3.1 is working perfectly
"jest": "^29.3.1"
"jest-environment-jsdom": "^29.3.1"
@smellai give it a try, hope can help to solve it

eps1lon

eps1lon commented on Feb 20, 2023

@eps1lon
Member

For people still having issues, please file a new one and include a minimal, cloneable reproduction. Just a list of dependencies is not sufficient.

locked as resolved and limited conversation to collaborators on Feb 20, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Participants

      @szimek@bobsilverberg@robin-drexler@nstepien@thepuzzlemaster

      Issue actions

        React 18. set state in finally throws "act" warning, though test is passing · Issue #1051 · testing-library/react-testing-library