I want to build upon the accepted answer from @Guilhermevrs. There has been one change since, and that is that userEvent
doesn't use fireEvent
from v14 on, but this doesn't affect userEvent.click()
directly.
To mimic user interactions like clicking buttons or inputting text for testing, the Testing Library provides various APIs. These APIs are:
fireEvent
: This synchronous, low-level API works as a wrapper around the dispatchEvent
Web API. For example, you can trigger a click
event on a button using fireEvent.click(buttonElement)
which would trigger an onClick
handler function on the component.
userEvent
: An asynchronous, high-level API, userEvent
simulates real user behaviour by triggering multiple events within a single interaction. The userEvent
offers two primary methods to simulate keyboard and pointer interactions, along with utility methods expanding on these.
userEvent.keyboard()
: This method replicates events like keyDown
and keyUp
using the dispatchEvent
Web API.
userEvent.pointer()
: Similar to userEvent.keyboard()
, this method triggers a variety of pointer events using the dispatchEvent
Web API. For example, userEvent.pointer({ keys: '[MouseLeft]', target: buttonElement})
triggers the pointerDown
, mouseDown
, pointerUp
, mouseUp
and click
event.
- Utility methods: These methods combine the previous two methods to closely simulate real user behavior.
userEvent.type()
: This method emulates a click
, keydown
, keyup
and input
event. Hence, userEvent.type(inputElement, 'hello')
triggers onClick
, onKeyDown
, onKeyPress
, onKeyUp
, and onChange
handlers on the component.
userEvent.click()
: This method emulates a hover
and click
event. For instance, userEvent.click(buttonElement)
activates all the events from userEvent.pointer
with mouseEnter
, pointerEnter
, mouseOver
and pointerOver
, but no mouseLeave
and pointerLeave
since the pointer will stay on the element.
- ... you can find the others on the Utility and Convenience pages
Before version 14, userEvent
internally used fireEvent
. There was, however, a need for userEvent
to have more control over the changes happening to the DOM. As a result, the internal calls to fireEvent
have been removed in the later versions and userEvent.keyboard
and userEvent.pointer
themselves now expand on the dispatchEvent
Web API
While userEvent
is usually the preferred option because of its high-level abstraction and realism, you can fallback on fireEvent
if you need to mimic edge case interactions that userEvent
doesn't support.
userEvent
limitations
To name a few limitations of userEvent
:
- it does not yet fully support keyboard composition sessions (#1097), which is the ability to simulate a user typing in text through the keyboard in a specific manner.
- it inaccurately handles events in number input fields, where pressing ArrowUp/ArrowDown does not trigger an onChange event (#1066).
- it falls short in simulating the interaction with
datalist
elements (#1088).
These limitations are not typically encountered in daily use cases. To circumvent these issues, consider using the keyboard
or pointer
modules. Alternatively, the lower-level API fireEvent
can be used.
It should also be noted that using userEvent
trades performance for accuracy. You remove risks of incorrect assumptions in your test - such as an why onKeyDown
event not being triggered - when a seemingly simple thing like typing into a textbox is performed. But hence, userEvent
can be 10x slower than a single fireEvent
.