How to Test React Lists in React
Testing dynamically rendered lists is a crucial part of building robust React applications. This article outlines the step-by-step process of testing React lists using React Testing Library (RTL) and Jest, focusing on verifying list item counts, asserting content accuracy, and handling empty states.
The Component under Test
To demonstrate how to test lists, we will use a simple
UserList component. This component accepts an array of
users and renders them as an unordered list. If the list is empty, it
displays a fallback message.
import React from 'react';
export function UserList({ users = [] }) {
if (users.length === 0) {
return <p>No users found.</p>;
}
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}1. Testing List Rendering
When testing a list, your primary goal is to ensure that the correct number of items render and that the content of those items is correct.
The best practice in React Testing Library is to query elements by
their ARIA role. For lists, we use the listitem role.
import { render, screen } from '@testing-library/react';
import { UserList } from './UserList';
test('renders a list of users', () => {
const mockUsers = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
];
render(<UserList users={mockUsers} />);
// Retrieve all list items
const listItems = screen.getAllByRole('listitem');
// Assert the correct number of items are rendered
expect(listItems).toHaveLength(2);
// Assert the correct content is displayed
expect(listItems[0]).toHaveTextContent('Alice');
expect(listItems[1]).toHaveTextContent('Bob');
});2. Testing Empty States
It is equally important to test the behavior of the component when the data array is empty. This ensures your fallback UI works as expected.
test('renders fallback text when user list is empty', () => {
render(<UserList users={[]} />);
// Check that the fallback text is in the document
const fallbackMessage = screen.getByText('No users found.');
expect(fallbackMessage).toBeInTheDocument();
// Ensure no list items are rendered
const listItems = screen.queryAllByRole('listitem');
expect(listItems).toHaveLength(0);
});3. Testing Dynamic Lists (Adding/Removing Items)
If your list allows users to add or remove items dynamically, you
should test the user interaction. In this scenario, we use
@testing-library/user-event to simulate adding an item to
the list.
Assuming a parent component manages the list state and renders an “Add User” button:
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { App } from './App'; // Component that manages list state
test('allows users to add items to the list', async () => {
render(<App />);
// Assert initial state (e.g., 2 items)
let listItems = screen.getAllByRole('listitem');
expect(listItems).toHaveLength(2);
// Simulate entering a new user name
const input = screen.getByRole('textbox', { name: /user name/i });
await userEvent.type(input, 'Charlie');
// Simulate clicking the "Add" button
const button = screen.getByRole('button', { name: /add user/i });
await userEvent.click(button);
// Assert list has updated to 3 items
listItems = screen.getAllByRole('listitem');
expect(listItems).toHaveLength(3);
expect(listItems[2]).toHaveTextContent('Charlie');
});