How to Test Click Event in React Using React Testing Library
To test a
click event in React, use React Testing Library's fireEvent.click or userEvent.click on the target element and then check the expected outcome. This simulates a user clicking and lets you verify component behavior in tests.Syntax
Use fireEvent.click(element) or userEvent.click(element) to simulate a click on a React element in your test. Then use assertions to check if the click caused the expected changes.
element: The DOM node you want to click.fireEvent: A utility from React Testing Library to simulate events.userEvent: A more user-like event simulation library recommended for better realism.
javascript
import { render, screen, fireEvent } from '@testing-library/react'; // Simulate click fireEvent.click(element); // Or with userEvent (preferred) import userEvent from '@testing-library/user-event'; const user = userEvent.setup(); await user.click(element);
Example
This example shows a button that increments a counter when clicked. The test renders the component, clicks the button, and checks if the counter updates.
javascript
import React, { useState } from 'react'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; function Counter() { const [count, setCount] = useState(0); return ( <div> <p>Count: {count}</p> <button onClick={() => setCount(count + 1)}>Increment</button> </div> ); } // Test test('increments counter on click', async () => { render(<Counter />); const button = screen.getByRole('button', { name: /increment/i }); const user = userEvent.setup(); expect(screen.getByText(/count: 0/i)).toBeInTheDocument(); await user.click(button); expect(screen.getByText(/count: 1/i)).toBeInTheDocument(); });
Output
Test passes if the counter text updates from 'Count: 0' to 'Count: 1' after clicking the button.
Common Pitfalls
Common mistakes when testing click events include:
- Not waiting for async updates when using
userEvent, causing false negatives. - Using
fireEventinstead ofuserEvent, which may not simulate real user behavior fully. - Querying elements incorrectly, e.g., using
getByTextfor buttons instead ofgetByRolewhich is more accessible and reliable.
javascript
/* Wrong way: Using fireEvent without async handling */ fireEvent.click(button); expect(screen.getByText(/count: 1/i)).toBeInTheDocument(); // May fail if update is async /* Right way: Using userEvent with async */ const user = userEvent.setup(); await user.click(button); expect(screen.getByText(/count: 1/i)).toBeInTheDocument();
Quick Reference
| Function | Purpose | Notes |
|---|---|---|
| fireEvent.click(element) | Simulates a click event | Basic event simulation, less realistic |
| userEvent.click(element) | Simulates user clicking | Preferred for realistic user interaction, supports async |
| screen.getByRole('button', { name }) | Finds button by role and label | Best practice for accessibility |
| expect(...).toBeInTheDocument() | Checks element presence | Common assertion after click |
Key Takeaways
Use React Testing Library's userEvent.click to simulate realistic click events.
Always query elements by role and accessible name for reliable tests.
Await userEvent.click when testing async updates to avoid flaky tests.
Check the UI changes after the click to confirm expected behavior.
Avoid fireEvent for complex user interactions; prefer userEvent for better simulation.