Suggest using userEvent
over fireEvent
for simulating user interactions (testing-library/prefer-user-event
)
From testing-library/dom-testing-library#107:
[...] it is becoming apparent the need to express user actions on a web page using a higher-level abstraction than
fireEvent
userEvent
adds related event calls from browsers to make tests more realistic than its counterpart fireEvent
, which is a low-level api.
See the appendix at the end to check how are the events from fireEvent
mapped to userEvent
.
This rule enforces the usage of userEvent methods over fireEvent
. By default, the methods from userEvent
take precedence, but you add exceptions by configuring the rule in .eslintrc
.
Examples of incorrect code for this rule:
// a method in fireEvent that has a userEvent equivalent
import { fireEvent } from '@testing-library/dom';
// or const { fireEvent } = require('@testing-library/dom');
fireEvent.click(node);
// using fireEvent with an alias
import { fireEvent as fireEventAliased } from '@testing-library/dom';
fireEventAliased.click(node);
// using fireEvent after importing the entire library
import * as dom from '@testing-library/dom';
// or const dom = require(@testing-library/dom');
dom.fireEvent.click(node);
// using fireEvent as a function
import * as dom from '@testing-library/dom';
dom.fireEvent(node, dom.createEvent('click', node));
import { fireEvent, createEvent } from '@testing-library/dom';
const clickEvent = createEvent.click(node);
fireEvent(node, clickEvent);
Examples of correct code for this rule:
import userEvent from '@testing-library/user-event';
// or const userEvent = require('@testing-library/user-event');
// any userEvent method
userEvent.click();
// fireEvent method that does not have an alternative in userEvent
import { fireEvent } from '@testing-library/dom';
// or const { fireEvent } = require('@testing-library/dom');
fireEvent.cut(node);
import * as dom from '@testing-library/dom';
// or const dom = require('@testing-library/dom');
dom.fireEvent.cut(node);
import { fireEvent, createEvent } from '@testing-library/dom';
fireEvent(node, createEvent('cut', node));
This rule allows to exclude specific functions with an equivalent in userEvent
through configuration. This is useful if you need to allow an event from fireEvent
to be used in the solution. For specific scenarios, you might want to consider disabling the rule inline.
The configuration consists of an array of strings with the names of fireEvents methods to be excluded.
An example looks like this
module.exports = {
rules: {
rules: {
'prefer-user-event': ['error', { allowedMethods: ['click', 'change'] }],
},
},
};
With this configuration example, the following use cases are considered valid
// using a named import
import { fireEvent } from '@testing-library/dom';
// or const { fireEvent } = require('@testing-library/dom');
fireEvent.click(node);
fireEvent.change(node, { target: { value: 'foo' } });
// using fireEvent with an alias
import { fireEvent as fireEventAliased } from '@testing-library/dom';
fireEventAliased.click(node);
fireEventAliased.change(node, { target: { value: 'foo' } });
// using fireEvent after importing the entire library
import * as dom from '@testing-library/dom';
// or const dom = require('@testing-library/dom');
dom.fireEvent.click(node);
dom.fireEvent.change(node, { target: { value: 'foo' } });
When you don't want to use userEvent
, such as if a legacy codebase is still using fireEvent
or you need to have more low-level control over firing events (rather than the recommended approach of testing from a user's perspective)
The following table lists all the possible equivalents from the low-level API fireEvent
to the higher abstraction API userEvent
. All the events not listed here do not have an equivalent (yet)
fireEvent method | Possible options in userEvent |
---|---|
click |
|
change |
|
dblClick |
|
input |
|
keyDown |
|
keyPress |
|
keyUp |
|
mouseDown |
|
mouseEnter |
|
mouseLeave |
|
mouseMove |
|
mouseOut |
|
mouseOver |
|
mouseUp |
|
paste |
|
pointerDown |
|
pointerEnter |
|
pointerLeave |
|
pointerMove |
|
pointerOut |
|
pointerOver |
|
pointerUp |
|