user-event vs. fireEvent: Testing Real User Interactions
user-event tests how users actually interact with your UI, not just isolated DOM events. It simulates a full action sequence, like a click firing pointerdown, mousedown, and click. Use it to test component behavior from a user's perspective.
WHY IT EXISTS: Testing Library provides fireEvent to dispatch DOM events, but real user interactions are more complex. A single click or keypress triggers a whole sequence of events. Writing tests that manually replicate this sequence is tedious, error-prone, and misses crucial browser behavior like interactability checks.
THE MENTAL MODEL: Think of fireEvent as a low-level tool for triggering a single, specific event. In contrast, user-event is a high-level simulation of a user's complete action. fireEvent.click() dispatches just a click event. await user.click() simulates a user actually moving their pointer over an element and clicking, dispatching all the intermediate events (pointerdown, mousedown, pointerup, mouseup, click) a browser would.
HOW IT WORKS: In a test, you first call userEvent.setup() to get a user instance. This instance has methods like click, type, and keyboard. When you call await user.type(input, 'hi'), user-event first checks if the input is visible and enabled. It then simulates focusing the input, firing the necessary keydown, keypress, input, and keyup events for each character, and updating the element's value and selection state along the way.
WHEN TO USE IT: Use user-event for virtually all tests that involve simulating user interaction. It leads to more robust and maintainable tests because they are focused on user behavior, not the underlying event implementation. It's the recommended way to test user flows in React, Vue, Svelte, or any other DOM-based framework.
WHEN NOT TO USE IT: The library is extensive but might not cover every obscure interaction. If a specific, low-level event sequence isn't yet implemented in user-event but is critical for your component, you might need to fall back to fireEvent. This should be the rare exception, not the rule.
ONE CANONICAL EXAMPLE: To test a user typing into an input, first set up an instance with const user = userEvent.setup(). After rendering your component, simulate the action with await user.type(screen.getByRole('textbox'), 'Hello!'). This single line correctly simulates focus, keyboard events, and value changes. Finally, you can assert that the input's value is now 'Hello!', confirming the interaction worked as expected.
Read the original → testing-library.com
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.