testing-library / testing-library/react-testing-library

`render` does not `await act()`

Open
#1,385 7 comments 15 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
JavaScript
Stars
19.7k
Forks
1.2k
Avg merge
3d 16h
Merged PRs (30d)
1

Description

  • @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

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with src/pure.js around line 149 and reproduce the issue using the provided TestComponent, promise, and render example. Trace how render invokes act in React 19, then verify the chosen behavior against the warning-free test and the possible breaking change to render's API.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, react
Domain
frontend, testing-qa
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.