-
Notifications
You must be signed in to change notification settings - Fork 144
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
407 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
# Use [userEvent](https://github.com/testing-library/user-event) over using `fireEvent` for user interactions (prefer-user-event) | ||
|
||
From | ||
[testing-library/dom-testing-library#107](https://github.com/testing-library/dom-testing-library/issues/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` | ||
|
||
## Rule Details | ||
|
||
This rules enforces the usage of [userEvent](https://github.com/testing-library/user-event) methods over `fireEvent`. By default, the methods from `userEvent` takes precedence, but you add exceptions by configuring the rule in `.eslintrc` | ||
|
||
See below for examples of valid usages of `fireEvent` methods with the configuration. | ||
|
||
Examples of **incorrect** code for this rule: | ||
|
||
```ts | ||
// a method in fireEvent that has a userEvent equivalent | ||
import { fireEvent } from '@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'; | ||
dom.fireEvent.click(node); | ||
``` | ||
|
||
Examples of **correct** code for this rule: | ||
|
||
```ts | ||
// any userEvent method | ||
userEvent.click(); | ||
// fireEvent method that does not have an alternative in userEvent | ||
fireEvent.cut(node); | ||
import * as dom from '@testing-library/dom'; | ||
dom.fireEvent.cut(node); | ||
|
||
// a function called fireEvent that's not imported from testing-library | ||
function fireEvent() { | ||
// do stuff | ||
} | ||
fireEvent(); | ||
``` | ||
|
||
#### Options | ||
|
||
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 | ||
|
||
```json | ||
{ | ||
"rules": { | ||
"prefer-user-event": [ | ||
"error", | ||
{ | ||
"allowedMethods": ["click", "change"] | ||
} | ||
] | ||
} | ||
} | ||
``` | ||
|
||
With this configuration example, the following use cases are considered valid | ||
|
||
```ts | ||
// using a named import | ||
import { fireEvent } from '@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'; | ||
dom.fireEvent.click(node); | ||
dom.fireEvent.change(node, { target: { value: 'foo' } }); | ||
``` | ||
|
||
## When Not To Use It | ||
|
||
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) | ||
|
||
## Further Reading | ||
|
||
- [userEvent repository](https://github.com/testing-library/user-event) | ||
- [userEvent in the react-testing-library docs](https://testing-library.com/docs/ecosystem-user-event) | ||
|
||
## Appendix | ||
|
||
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` | <ul><li>`click`</li><li>`type`</li><li>`selectOptions`</li><li>`deselectOptions`</li></ul> | | ||
| `change` | <ul><li>`upload`</li><li>`type`</li><li>`clear`</li><li>`selectOptions`</li><li>`deselectOptions`</li></ul> | | ||
| `dblClick` | <ul><li>`dblClick`</li></ul> | | ||
| `input` | <ul><li>`type`</li><li>`upload`</li><li>`selectOptions`</li><li>`deselectOptions`</li><li>`paste`</li></ul> | | ||
| `keyDown` | <ul><li>`type`</li><li>`tab`</li></ul> | | ||
| `keyPress` | <ul><li>`type`</li></ul> | | ||
| `keyUp` | <ul><li>`type`</li><li>`tab`</li></ul> | | ||
| `mouseDown` | <ul><li>`click`</li><li>`dblClick`</li><li>`selectOptions`</li><li>`deselectOptions`</li></ul> | | ||
| `mouseEnter` | <ul><li>`hover`</li><li>`selectOptions`</li><li>`deselectOptions`</li></ul> | | ||
| `mouseLeave` | <ul><li>`unhover`</li></ul> | | ||
| `mouseMove` | <ul><li>`hover`</li><li>`unhover`</li><li>`selectOptions`</li><li>`deselectOptions`</li></ul> | | ||
| `mouseOut` | <ul><li>`unhover`</li></ul> | | ||
| `mouseOver` | <ul><li>`hover`</li><li>`selectOptions`</li><li>`deselectOptions`</li></ul> | | ||
| `mouseUp` | <ul><li>`click`</li><li>`dblClick`</li><li>`selectOptions`</li><li>`deselectOptions`</li></ul> | | ||
| `paste` | <ul><li>`paste`</li></ul> | | ||
| `pointerDown` | <ul><li>`click`</li><li>`dblClick`</li><li>`selectOptions`</li><li>`deselectOptions`</li></ul> | | ||
| `pointerEnter` | <ul><li>`hover`</li><li>`selectOptions`</li><li>`deselectOptions`</li></ul> | | ||
| `pointerLeave` | <ul><li>`unhover`</li></ul> | | ||
| `pointerMove` | <ul><li>`hover`</li><li>`unhover`</li><li>`selectOptions`</li><li>`deselectOptions`</li></ul> | | ||
| `pointerOut` | <ul><li>`unhover`</li></ul> | | ||
| `pointerOver` | <ul><li>`hover`</li><li>`selectOptions`</li><li>`deselectOptions`</li></ul> | | ||
| `pointerUp` | <ul><li>`click`</li><li>`dblClick`</li><li>`selectOptions`</li><li>`deselectOptions`</li></ul> | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.