6

So I updated to React 18 and now I am getting TONS of act warnings as well as failing tests.

versions:

react: 18.2.0

react-dom: 18.2.0

jest: 29.3.1

jest-environment-jsdom: 29.3.1

ts-jest: 29.0.3

typescript: 4.9.4

console.error Warning: An update to ProductPrice inside a test was not wrapped in act(...).
When testing, code that causes React state updates should be wrapped into act(...):

I have fixed about 80 tests by wrapping the assertions or my main render method in await waitFor(() => {}.

Is there a better way I should be fixing these tests? Here is an example test that went from failing to passing with the following change... The following failing test was passing before I upgraded to React 18 and corresponding react-testing-library + jest versions

-------------failing test below --------------

async function findPlpHeaderText() {
  return screen.findByTestId('plp__header-text');
}

test.only('Sold out products render as expected on store', async () => {
    await renderPage({ route: '/boutique/21443255', siteName: 'anonymous-store' });
    const headerText = await findPlpHeaderText();

    await within(headerText).findByText('Childless boutique');
    await screen.findByText('Sold Out');
    await screen.findByText('Sold Out. Must Have It?');
});

----------passing test below--------------
note: I wrapped the assertion in waitFor(() => and then they passed, I tested that this wasn't a false positive as well... this blog post inspired me to wrap my assertions in waitFor after upgrading to react 18 -- https://www.felixmokross.dev/blog/react-18-upgrade#:~:text=Fixing%20the%20tests,wrap%20assertions%20in

test.only('Sold out products render as expected on store', async () => {
    await renderPage({ route: '/boutique/21443255', siteName: 'anonymouse-store' });
    const headerText = await findPlpHeaderText();

    await waitFor(async () => {
      within(headerText).getByText('Childless boutique');
      screen.getByText('Sold Out');
      screen.getByText('Sold Out. Must Have It?');
    });
});

Has anyone else experienced this after upgrading to React 18? If there is a better solution I would love to know about it!

Another weird aspect of this is when I wrap the new passing tests with an: waitFor(async () => {}) callback, the act() warnings go away -- however if I only wrap them in waitFor(() => {}) not-async callback, the `act() warnings persist, however the tests still pass...

  • 1
    I don't know why it's been downvoted. I had this too when I upgraded to React 18 and came across this page. Anyway the solution is the question – AndyW Feb 08 '23 at 08:20
  • I have the same problem. After upgrading to React 18 most of the tests are failing now. – karlosos Feb 13 '23 at 14:05

2 Answers2

1

I am also facing react testing library test failure issues after upgrading to react 18. I am able to fix most tests by wrapping the event firing by RTL fireEvent in act function. Some of them were already wrapped in waitFor, but it was still causing test failures. So, I replaced waitFor by act, and then, it started working.

Alternatively, if you are using RTL, and you are getting some element from rendered dom immediately after fireEvent, then instead of using getBy*, try using await findBy*. It may also resolve the failing test.

Saad Farooq
  • 39
  • 1
  • 8
0

I couldn't find the root cause of this problem, but I was able to resolve it with the same approach like you. However, you can use findBy* queries instead of wrapping getBy* queries with waitFor() as Kent C. Dodds suggests in https://kentcdodds.com/blog/common-mistakes-with-react-testing-library#using-waitfor-to-wait-for-elements-that-can-be-queried-with-find:

Advice: use find* any time you want to query for something that may not be available right away.

EDIT: some tests kept failing randomly in CI with the above-mentioned method. I was able to fix it by running the tests with the --runInBand Jest CLI option, i.e. jest --runInBand. Unfortunately, I couldn't find any good explanation why it works.

pixochi
  • 23
  • 6