How to Test Loading State in React Components
To test a
loading state in React, render the component and check if the loading indicator (like a spinner or text) appears before the data loads. Use React Testing Library's screen and waitFor to assert the loading UI shows and then disappears when loading finishes.Syntax
Testing loading state involves rendering the component, checking for the loading indicator, and waiting for the final content to appear.
render(): Render the React component.screen.getByText(): Find the loading text or spinner.waitFor(): Wait for the loading to finish and content to appear.
javascript
import { render, screen, waitFor } from '@testing-library/react'; render(<MyComponent />); expect(screen.getByText(/loading/i)).toBeInTheDocument(); await waitFor(() => expect(screen.getByText(/data loaded/i)).toBeInTheDocument());
Example
This example shows a component that fetches data and displays a loading message while waiting. The test checks that the loading message appears first, then the data is shown.
javascript
import React, { useEffect, useState } from 'react'; import { render, screen, waitFor } from '@testing-library/react'; default function DataLoader() { const [loading, setLoading] = useState(true); const [data, setData] = useState(null); useEffect(() => { setTimeout(() => { setData('Data loaded'); setLoading(false); }, 500); }, []); if (loading) return <div>Loading...</div>; return <div>{data}</div>; } // Test test('shows loading then data', async () => { render(<DataLoader />); // Check loading state expect(screen.getByText(/loading/i)).toBeInTheDocument(); // Wait for data to appear await waitFor(() => expect(screen.getByText(/data loaded/i)).toBeInTheDocument()); });
Output
Loading... (initially visible)
Data loaded (visible after 500ms)
Common Pitfalls
Common mistakes when testing loading states include:
- Not waiting for the loading to finish, causing tests to fail.
- Checking for loading text after it disappears.
- Using
findByTextwithout understanding it waits automatically.
Always use waitFor or findBy queries to handle async UI changes.
javascript
/* Wrong: Checking loading after it disappears */ render(<DataLoader />); expect(screen.queryByText(/loading/i)).toBeInTheDocument(); // Fails if loading is gone /* Right: Check loading first, then wait for data */ expect(screen.getByText(/loading/i)).toBeInTheDocument(); await waitFor(() => expect(screen.getByText(/data loaded/i)).toBeInTheDocument());
Quick Reference
- Use
render()to mount the component. - Use
screen.getByText()to check loading UI immediately. - Use
waitFor()orfindByText()to wait for async updates. - Do not check for loading after it should be gone without waiting.
Key Takeaways
Always check the loading indicator appears before data loads.
Use waitFor or findBy queries to handle asynchronous UI changes.
Avoid checking for loading text after it disappears without waiting.
Render the component fresh for each test to avoid state leaks.
Keep tests simple: check loading, then check final content.