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/awaitcausing tests to finish before async updates. - Using
getByqueries instead offindByorwaitFor, 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
asyncto useawait. - Use
findByqueries to wait for elements. - Use
waitForto 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.