Skip to content

render does not await act() #1385

@nstepien

Description

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions