How to fix waitFor timeout: timed out waiting for element to appear in React

ReactINTERMEDIATEMEDIUMUpdated Dec 10, 2025· 139 views

This error occurs when React Testing Library's waitFor utility times out while waiting for an element to appear in the DOM. The default timeout is 1000ms, and this error means the element didn't appear within that time. Common causes include async actions not being awaited, fake timers interfering, or elements not rendering as expected.

Quick fix

Fixes waitFor timeout: timed out waiting for element to appear

// ❌ Wrong - not awaited
userEvent.click(button);

// ✅ Correct - awaited
await userEvent.click(button);
  1. Check if you're awaiting user-event actions
  2. Check for Jest fake timer conflicts
  3. Increase timeout if needed
  4. Debug what's actually rendered
react — error
// ❌ Wrong - not awaited
userEvent.click(button);
// ✅ Correct - awaited
await userEvent.click(button);
waitFor timeout: timed out waiting for element to appear

What this error means

The `waitFor` utility in React Testing Library is used to wait for asynchronous changes in your component. It repeatedly runs a callback function until either the callback succeeds (doesn't throw) or the timeout is reached (default: 1000ms). When you see "waitFor timeout: timed out waiting for element to appear", it means: 1. Your test expected an element to appear in the DOM 2. The `waitFor` utility checked repeatedly for the element 3. After 1000ms (or your custom timeout), the element still wasn't found 4. The test fails with this timeout error This is a common integration testing issue where the component's state changes aren't happening as expected, or the test isn't properly waiting for asynchronous operations to complete.

Typical symptoms

  • Test fails with 'waitFor timeout: timed out waiting for element to appear'
  • The element appears visually but the test can't find it
  • Test passes when you increase the timeout but fails with default
  • Async operations seem to complete but elements don't render
  • The error includes container state showing what was actually rendered

Common causes

  1. Async user-event actions not being awaited (most common with newer versions)
  2. Jest fake timers interfering with waitFor's internal timing
  3. Element query returns null because the element doesn't exist in the DOM
  4. Component state isn't updating as expected
  5. Network requests or other async operations haven't completed
  6. The element exists but with different text/content than expected
  7. Component is conditionally rendering based on state that hasn't changed
  8. Testing in wrong container or wrong render scope

How to fix "waitFor timeout: timed out waiting for element to appear"

1Check if you're awaiting user-event actions

With newer versions of @testing-library/user-event, all actions must be awaited:

typescript
// ❌ Wrong - not awaited
userEvent.click(button);

// ✅ Correct - awaited
await userEvent.click(button);

Update all user-event calls in your test:

typescript
// Before
userEvent.type(input, "test");
userEvent.click(button);

// After
await userEvent.type(input, "test");
await userEvent.click(button);
2Check for Jest fake timer conflicts

If you're using jest.useFakeTimers(), it can interfere with waitFor. The waitFor utility uses real timers internally.

Solution 1: Use modern fake timers API:

typescript
// Use modern timers
jest.useFakeTimers({ doNotFake: ['setImmediate'] });

// Or use legacy timers
jest.useFakeTimers('legacy');

Solution 2: Restore real timers for waitFor tests:

typescript
beforeEach(() => {
  jest.useRealTimers(); // Use real timers for waitFor tests
});

// Or switch back to real timers before waitFor
jest.useRealTimers();
await waitFor(() => {
  expect(getByText('Hello')).toBeInTheDocument();
});
jest.useFakeTimers(); // Switch back if needed
3Increase timeout if needed

If your element legitimately takes longer to appear, increase the timeout:

typescript
// Increase to 3000ms (3 seconds)
await waitFor(() => {
  expect(getByText('Loading complete')).toBeInTheDocument();
}, { timeout: 3000 });

// Or globally configure waitFor options
import { configure } from '@testing-library/dom';
configure({ asyncUtilTimeout: 3000 });

Note: Increasing timeout should be a last resort. First fix the underlying issue causing the delay.

4Debug what's actually rendered

The error message includes the container's state. You can also manually debug:

typescript
// Log what's actually in the DOM
console.log(container.innerHTML);

// Or use screen.debug()
import { screen } from '@testing-library/react';
screen.debug();

// Check if element exists with different query
const element = queryByText('Some text');
if (!element) {
  console.log('Element not found. DOM contains:', container.innerHTML);
}

This helps identify if:
- The element renders with different text
- The element is in a different container
- The element never renders at all

5Verify async operations complete

Ensure all async operations complete before checking for elements:

typescript
// Mock API calls
jest.spyOn(api, 'fetchData').mockResolvedValue({ data: 'test' });

// Wait for API call to complete
await waitFor(() => {
  expect(api.fetchData).toHaveBeenCalled();
});

// Then check for element
await waitFor(() => {
  expect(getByText('Data loaded')).toBeInTheDocument();
});

// For React Query, wait for queries to settle
await waitFor(() => {
  expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
});
6Check element queries

Make sure you're using the right query and the element actually exists:

typescript
// Common mistakes:
// 1. Using getBy when element might not exist yet
// ❌ getByText throws immediately if not found
expect(getByText('Hello')).toBeInTheDocument();

// ✅ queryByText returns null, works with waitFor
await waitFor(() => {
  expect(queryByText('Hello')).toBeInTheDocument();
});

// 2. Wrong text matching
// Element has "Hello World" but you query for "Hello"
await waitFor(() => {
  expect(getByText('Hello World')).toBeInTheDocument();
});

// 3. Case sensitivity
await waitFor(() => {
  expect(getByText('hello', { exact: false })).toBeInTheDocument();
});

Advanced notes

### Understanding waitFor Behavior

waitFor runs your callback function repeatedly until it succeeds (doesn't throw) or times out. Key behaviors:

1. Default timeout: 1000ms
2. Interval between retries: 50ms
3. Callback must throw: Returning false or a falsy value won't trigger retries
4. Container state in error: The error message includes what was actually rendered

### Common Pitfalls

setImmediate conflicts: If you have global.setImmediate = jest.useRealTimers; in your Jest config, remove it as it can break waitFor.

Act warnings: If you see "Warning: An update to Component inside a test was not wrapped in act(...)", you may need to use waitFor differently:

typescript
// Instead of this causing act warnings
fireEvent.click(button);
await waitFor(() => {
  expect(getByText('Updated')).toBeInTheDocument();
});

// Use findBy which wraps waitFor
fireEvent.click(button);
const element = await findByText('Updated');

Custom waitFor implementations: Avoid creating custom waiting logic. Use the built-in utilities:

typescript
// ❌ Custom sleep
await new Promise(resolve => setTimeout(resolve, 100));

// ✅ Built-in waitFor
await waitFor(() => {
  expect(getByText('Ready')).toBeInTheDocument();
});

### Performance Considerations

If tests are consistently timing out:
1. Check for infinite loops or state updates in components
2. Ensure mocked APIs resolve promptly
3. Consider if the component is doing too much work synchronously
4. Use jest.setTimeout() for overall test timeout if needed

### Version-Specific Notes

- @testing-library/user-event v14+: All actions must be awaited
- React 18: Ensure you're using @testing-library/react v13+ for proper concurrent mode support
- Jest 27+: Fake timers behavior changed, use jest.useFakeTimers('legacy') if needed

Frequently asked questions

What does "waitFor timeout: timed out waiting for element to appear" mean?
The waitFor utility in React Testing Library is used to wait for asynchronous changes in your component. It repeatedly runs a callback function until either the callback succeeds (doesn't throw) or the timeout is reached (default: 1000ms). When you see "waitFor timeout: timed out waiting for element to appear", it means: 1.
How do I fix "waitFor timeout: timed out waiting for element to appear"?
This error occurs when React Testing Library's waitFor utility times out while waiting for an element to appear in the DOM. The default timeout is 1000ms, and this error means the element didn't appear within that time. Common causes include async actions not being awaited, fake timers interfering, or elements not rendering as expected.
What causes "waitFor timeout: timed out waiting for element to appear"?
Async user-event actions not being awaited (most common with newer versions) Jest fake timers interfering with waitFor's internal timing Element query returns null because the element doesn't exist in the DOM
Is the "waitFor timeout: timed out waiting for element to appear" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading