testing-library/react-testing-library

`render` does not `await act()`

Opened this issue · 7 comments

  • @testing-library/react version: 16.2.0
  • Testing Framework and version: vitest
  • DOM Environment: chromium, via @vitest/browser

Relevant code or config:

import { use } from 'react';
import { render, screen } from '@testing-library/react';

function TestComponent({ promise }: { promise: Promise<unknown> }) {
  use(promise);

  return 'test';
}

test('render', async () => {
  const promise = new Promise((resolve) => {
    setTimeout(resolve, 10);
  });

  render(<TestComponent promise={promise} />);

  await expect(screen.findByText('test')).resolves.toBeInTheDocument();
});

What you did:

I use use(promise) in components.

What happened:

I get the following error when rendering via @testing-library/react's render().

A component suspended inside an `act` scope, but the `act` call was not awaited. When testing React components that depend on asynchronous data, you must await the result:

await act(() => ...)

The test also fails:

Caused by: TestingLibraryElementError: Unable to find an element with the text: test. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.

Reproduction:

See "Relevant code or config" above.

Adding an un-awaited act manually does not resolve the issue either:

import { use } from 'react';
import { act, render, screen } from '@testing-library/react';

function TestComponent({ promise }: { promise: Promise<unknown> }) {
  use(promise);

  return 'test';
}

test('render', async () => {
  const promise = new Promise((resolve) => {
    setTimeout(resolve, 10);
  });

  act(() => {
    render(<TestComponent promise={promise} />);
  });

  await expect(screen.findByText('test')).resolves.toBeInTheDocument();
});

Problem description:

I should never get any act warnings when using @testing-library/react functions.

Suggested solution:

As the warning explicitly advises, awaiting the act call fixes the warning/test:

import { use } from 'react';
import { act, render, screen } from '@testing-library/react';

function TestComponent({ promise }: { promise: Promise<unknown> }) {
  use(promise);

  return 'test';
}

test('render', async () => {
  const promise = new Promise((resolve) => {
    setTimeout(resolve, 10);
  });

  await act(() => {
    render(<TestComponent promise={promise} />);
  });

  await expect(screen.findByText('test')).resolves.toBeInTheDocument();
});

AFAICT, in React 19, act always returns a promise, so it may be best to always await it.
Fixing the issue would make render async, which may be a breaking change.
https://github.com/testing-library/react-testing-library/blob/main/src/pure.js#L149

I see that there's already a PR for it: #1214

AFAICT, in React 19, act always returns a promise, so it may be best to always await it.

It's a fake Promise. Only if you pass in an async function you actually have to await it right now.

Only if you pass in an async function you actually have to await it right now.

render is sync, and yet the act's promise must still be awaited to resolve the warning/fix tests.

@eps1lon I wonder if you still disagree with the need to await act calls, despite the reproducible example above.

I don't disagree. That's exactly what I'm already working on: #1214

It's just that the current act doesn't need to be awaited. The Promise it returns for sync callbacks is not a Promise that needs awaiting.

You do need the async version when you use use which is why we're making it mandatory to await.

The Promise it returns for sync callbacks is not a Promise that needs awaiting.

act with a sync callback must be awaited when use is used, per the example above.

Anyway, I hope this will be resolved.

React 19 was released in December 2024, and it's the default version used by Expo 53.

The react native version of this library has had to work around the issue by adding custom *Async versions of test utils that actually support React 19's new suspense behaviour.

Is there any way that this issue can be prioritized? This is the library to use for unit testing React components and somehow it doesn't support an 8 month old version of React, which is giving this library the feeling that it's unmaintained.

We're adding custom utils/patches/etc to be able to work around it, but it would be nice to have a timeline or a non-stale PR to follow to know when official support will be added.