0
0
ReactHow-ToBeginner · 3 min read

How to Test Async Code in React: Simple Guide with Examples

To test async code in React, use async/await in your test functions combined with React Testing Library's waitFor or findBy queries. This lets you wait for UI updates caused by async operations before making assertions.
📐

Syntax

Use async keyword on your test function to enable await. Use waitFor to wait for changes or findBy queries that return promises resolving when elements appear.

Example parts:

  • async () => { ... }: marks test as asynchronous.
  • await waitFor(() => expect(...)): waits until the expectation passes.
  • await findByText('text'): waits for element with text to appear.
javascript
import { render, screen, waitFor } from '@testing-library/react';

// Async test function
test('async test example', async () => {
  render(<MyComponent />);

  // waitFor waits for callback to not throw
  await waitFor(() => expect(screen.getByText('Loaded')).toBeInTheDocument());

  // or use findBy queries that return promises
  const element = await screen.findByText('Loaded');
  expect(element).toBeVisible();
});
💻

Example

This example shows testing a React component that fetches data asynchronously and displays it. The test waits for the data to appear before checking the UI.

javascript
import React, { useEffect, useState } from 'react';
import { render, screen } from '@testing-library/react';

// Component that fetches data asynchronously
function AsyncComponent() {
  const [data, setData] = useState(null);

  useEffect(() => {
    setTimeout(() => {
      setData('Hello Async');
    }, 500);
  }, []);

  if (!data) return <div>Loading...</div>;
  return <div>{data}</div>;
}

// Test for AsyncComponent
test('shows async data after loading', async () => {
  render(<AsyncComponent />);

  // Initially shows loading
  expect(screen.getByText('Loading...')).toBeInTheDocument();

  // Wait for async data to appear
  const resolvedData = await screen.findByText('Hello Async');
  expect(resolvedData).toBeInTheDocument();
});
Output
PASS shows async data after loading
⚠️

Common Pitfalls

Common mistakes when testing async React code include:

  • Not using async/await causing tests to finish before async updates.
  • Using getBy queries instead of findBy or waitFor, which fail if element is not immediately present.
  • Not cleaning up mocks or timers, leading to flaky tests.
javascript
import { render, screen } from '@testing-library/react';

// Wrong: missing async/await, test may pass before update
// test('wrong async test', () => {
//   render(<AsyncComponent />);
//   expect(screen.getByText('Hello Async')).toBeInTheDocument(); // fails
// });

// Right: use async/await and findBy
// test('correct async test', async () => {
//   render(<AsyncComponent />);
//   const element = await screen.findByText('Hello Async');
//   expect(element).toBeInTheDocument();
// });
📊

Quick Reference

Tips for testing async React code:

  • Mark test functions async to use await.
  • Use findBy queries to wait for elements.
  • Use waitFor to wait for arbitrary conditions.
  • Mock async functions or timers to control test timing.
  • Clean up mocks and timers after tests.

Key Takeaways

Always use async/await in your test functions when testing async React code.
Use React Testing Library's findBy queries or waitFor to wait for UI updates.
Avoid getBy queries for async elements as they expect immediate presence.
Mock async operations and timers to make tests reliable and fast.
Clean up mocks and timers to prevent test interference.