When a component performs asynchronous operations (like setTimeout or network calls) that trigger state updates, you have three primary ways to handle them in RNTL:
1. Using Jest Fake Timers
Wrap the timer advancement in a synchronous act() call. This is often the cleanest way to test time-dependent logic.
2. Using waitFor
Use the waitFor utility to poll until the expected state is reached. waitFor internally uses asynchronous act().
3. Using findBy* queries
Use findBy queries (e.g., findByText), which are asynchronous versions of getBy queries. These internally call waitFor and are the most idiomatic way to wait for an element to appear after an async update.
// Solution 1: Fake Timers
import { render, act } from '@testing-library/react-native';
test('render with fake timers', () => {
jest.useFakeTimers();
render(<TestAsyncComponent />);
act(() => {
jest.runAllTimers();
});
expect(screen.getByText('Count 1')).toBeOnTheScreen();
});
// Solution 2: waitFor
import { render, screen, waitFor } from '@testing-library/react-native';
test('render with real timers - waitFor', async () => {
render(<TestAsyncComponent />);
await waitFor(() => screen.getByText('Count 1'));
expect(screen.getByText('Count 1')).toBeOnTheScreen();
});
// Solution 3: findBy (Recommended)
import { render, screen } from '@testing-library/react-native';
test('render with real timers - findBy', async () => {
render(<TestAsyncComponent />);
expect(await screen.findByText('Count 1')).toBeOnTheScreen();
});