Skip to content

add fireEvent from dom-testing-library #48

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Apr 10, 2018
11 changes: 11 additions & 0 deletions .all-contributorsrc
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,17 @@
"code",
"doc"
]
},
{
"login": "jomaxx",
"name": "Josef Maxx Blake",
"avatar_url": "https://avatars2.githubusercontent.com/u/2747424?v=4",
"profile": "http://jomaxx.com",
"contributions": [
"code",
"doc",
"test"
]
}
]
}
29 changes: 27 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
[![downloads][downloads-badge]][npmtrends]
[![MIT License][license-badge]][license]

[![All Contributors](https://img.shields.io/badge/all_contributors-13-orange.svg?style=flat-square)](#contributors)
[![All Contributors](https://img.shields.io/badge/all_contributors-14-orange.svg?style=flat-square)](#contributors)
[![PRs Welcome][prs-badge]][prs]
[![Code of Conduct][coc-badge]][coc]

Expand Down Expand Up @@ -83,6 +83,7 @@ facilitate testing implementation details). Read more about this in
* [`render`](#render)
* [`Simulate`](#simulate)
* [`wait`](#wait)
* [`fireEvent(node: HTMLElement, event: Event)`](#fireeventnode-htmlelement-event-event)
* [`TextMatch`](#textmatch)
* [`query` APIs](#query-apis)
* [Examples](#examples)
Expand Down Expand Up @@ -313,6 +314,30 @@ The default `interval` is `50ms`. However it will run your callback immediately
on the next tick of the event loop (in a `setTimeout`) before starting the
intervals.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's update the docs here to document renderIntoDocument and clearDocument (in that order). Then update the fireEvent docs to explain why it's important to use those helpers.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh i just added this, but added them below render and before Simulate

### `fireEvent(node: HTMLElement, event: Event)`

Fire DOM events.

```javascript
// <button>Submit</button>
fireEvent(
getElementByText('Submit'),
new MouseEvent('click', {
bubbles: true,
cancelable: true,
}),
)
```

#### `fireEvent[eventName](node: HTMLElement, eventInit)`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you update this to be:

#### `fireEvent[eventName](node: HTMLElement, eventProperties: Object)`


Convenience methods for firing DOM events. Look [here](./src/events.js) for full list.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you update this to say:

Convenience methods for firing DOM events. Check out
[dom-testing-library/src/events.js](https://github.com/kentcdodds/dom-testing-library/blob/master/src/events.js)
for a full list as well as default `eventProperties`.


```javascript
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update this example to the same in dom-testing-library:

// <button>Submit</button>
const rightClick = {button: 2}
fireEvent.click(getElementByText('Submit'), rightClick)
// default `button` property for click events is set to `0` which is a left click.

// <button>Submit</button>
fireEvent.click(getElementByText('Submit'))
```

## `TextMatch`

Several APIs accept a `TextMatch` which can be a `string`, `regex` or a
Expand Down Expand Up @@ -635,7 +660,7 @@ Thanks goes to these people ([emoji key][emojis]):
<!-- prettier-ignore -->
| [<img src="https://avatars.githubusercontent.com/u/1500684?v=3" width="100px;"/><br /><sub><b>Kent C. Dodds</b></sub>](https://kentcdodds.com)<br />[💻](https://github.com/kentcdodds/react-testing-library/commits?author=kentcdodds "Code") [📖](https://github.com/kentcdodds/react-testing-library/commits?author=kentcdodds "Documentation") [🚇](#infra-kentcdodds "Infrastructure (Hosting, Build-Tools, etc)") [⚠️](https://github.com/kentcdodds/react-testing-library/commits?author=kentcdodds "Tests") | [<img src="https://avatars1.githubusercontent.com/u/2430381?v=4" width="100px;"/><br /><sub><b>Ryan Castner</b></sub>](http://audiolion.github.io)<br />[📖](https://github.com/kentcdodds/react-testing-library/commits?author=audiolion "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/8008023?v=4" width="100px;"/><br /><sub><b>Daniel Sandiego</b></sub>](https://www.dnlsandiego.com)<br />[💻](https://github.com/kentcdodds/react-testing-library/commits?author=dnlsandiego "Code") | [<img src="https://avatars2.githubusercontent.com/u/12592677?v=4" width="100px;"/><br /><sub><b>Paweł Mikołajczyk</b></sub>](https://github.com/Miklet)<br />[💻](https://github.com/kentcdodds/react-testing-library/commits?author=Miklet "Code") | [<img src="https://avatars3.githubusercontent.com/u/464978?v=4" width="100px;"/><br /><sub><b>Alejandro Ñáñez Ortiz</b></sub>](http://co.linkedin.com/in/alejandronanez/)<br />[📖](https://github.com/kentcdodds/react-testing-library/commits?author=alejandronanez "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/1402095?v=4" width="100px;"/><br /><sub><b>Matt Parrish</b></sub>](https://github.com/pbomb)<br />[🐛](https://github.com/kentcdodds/react-testing-library/issues?q=author%3Apbomb "Bug reports") [💻](https://github.com/kentcdodds/react-testing-library/commits?author=pbomb "Code") [📖](https://github.com/kentcdodds/react-testing-library/commits?author=pbomb "Documentation") [⚠️](https://github.com/kentcdodds/react-testing-library/commits?author=pbomb "Tests") | [<img src="https://avatars1.githubusercontent.com/u/1288694?v=4" width="100px;"/><br /><sub><b>Justin Hall</b></sub>](https://github.com/wKovacs64)<br />[📦](#platform-wKovacs64 "Packaging/porting to new platform") |
| :---: | :---: | :---: | :---: | :---: | :---: | :---: |
| [<img src="https://avatars1.githubusercontent.com/u/1241511?s=460&v=4" width="100px;"/><br /><sub><b>Anto Aravinth</b></sub>](https://github.com/antoaravinth)<br />[💻](https://github.com/kentcdodds/react-testing-library/commits?author=antoaravinth "Code") [⚠️](https://github.com/kentcdodds/react-testing-library/commits?author=antoaravinth "Tests") [📖](https://github.com/kentcdodds/react-testing-library/commits?author=antoaravinth "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/3462296?v=4" width="100px;"/><br /><sub><b>Jonah Moses</b></sub>](https://github.com/JonahMoses)<br />[📖](https://github.com/kentcdodds/react-testing-library/commits?author=JonahMoses "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/4002543?v=4" width="100px;"/><br /><sub><b>Łukasz Gandecki</b></sub>](http://team.thebrain.pro)<br />[💻](https://github.com/kentcdodds/react-testing-library/commits?author=lgandecki "Code") [⚠️](https://github.com/kentcdodds/react-testing-library/commits?author=lgandecki "Tests") [📖](https://github.com/kentcdodds/react-testing-library/commits?author=lgandecki "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/498274?v=4" width="100px;"/><br /><sub><b>Ivan Babak</b></sub>](https://sompylasar.github.io)<br />[🐛](https://github.com/kentcdodds/react-testing-library/issues?q=author%3Asompylasar "Bug reports") [🤔](#ideas-sompylasar "Ideas, Planning, & Feedback") | [<img src="https://avatars3.githubusercontent.com/u/4439618?v=4" width="100px;"/><br /><sub><b>Jesse Day</b></sub>](https://github.com/jday3)<br />[💻](https://github.com/kentcdodds/react-testing-library/commits?author=jday3 "Code") | [<img src="https://avatars0.githubusercontent.com/u/15199?v=4" width="100px;"/><br /><sub><b>Ernesto García</b></sub>](http://gnapse.github.io)<br />[💬](#question-gnapse "Answering Questions") [💻](https://github.com/kentcdodds/react-testing-library/commits?author=gnapse "Code") [📖](https://github.com/kentcdodds/react-testing-library/commits?author=gnapse "Documentation") |
| [<img src="https://avatars1.githubusercontent.com/u/1241511?s=460&v=4" width="100px;"/><br /><sub><b>Anto Aravinth</b></sub>](https://github.com/antoaravinth)<br />[💻](https://github.com/kentcdodds/react-testing-library/commits?author=antoaravinth "Code") [⚠️](https://github.com/kentcdodds/react-testing-library/commits?author=antoaravinth "Tests") [📖](https://github.com/kentcdodds/react-testing-library/commits?author=antoaravinth "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/3462296?v=4" width="100px;"/><br /><sub><b>Jonah Moses</b></sub>](https://github.com/JonahMoses)<br />[📖](https://github.com/kentcdodds/react-testing-library/commits?author=JonahMoses "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/4002543?v=4" width="100px;"/><br /><sub><b>Łukasz Gandecki</b></sub>](http://team.thebrain.pro)<br />[💻](https://github.com/kentcdodds/react-testing-library/commits?author=lgandecki "Code") [⚠️](https://github.com/kentcdodds/react-testing-library/commits?author=lgandecki "Tests") [📖](https://github.com/kentcdodds/react-testing-library/commits?author=lgandecki "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/498274?v=4" width="100px;"/><br /><sub><b>Ivan Babak</b></sub>](https://sompylasar.github.io)<br />[🐛](https://github.com/kentcdodds/react-testing-library/issues?q=author%3Asompylasar "Bug reports") [🤔](#ideas-sompylasar "Ideas, Planning, & Feedback") | [<img src="https://avatars3.githubusercontent.com/u/4439618?v=4" width="100px;"/><br /><sub><b>Jesse Day</b></sub>](https://github.com/jday3)<br />[💻](https://github.com/kentcdodds/react-testing-library/commits?author=jday3 "Code") | [<img src="https://avatars0.githubusercontent.com/u/15199?v=4" width="100px;"/><br /><sub><b>Ernesto García</b></sub>](http://gnapse.github.io)<br />[💬](#question-gnapse "Answering Questions") [💻](https://github.com/kentcdodds/react-testing-library/commits?author=gnapse "Code") [📖](https://github.com/kentcdodds/react-testing-library/commits?author=gnapse "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/2747424?v=4" width="100px;"/><br /><sub><b>Josef Maxx Blake</b></sub>](http://jomaxx.com)<br />[💻](https://github.com/kentcdodds/react-testing-library/commits?author=jomaxx "Code") [📖](https://github.com/kentcdodds/react-testing-library/commits?author=jomaxx "Documentation") [⚠️](https://github.com/kentcdodds/react-testing-library/commits?author=jomaxx "Tests") |

<!-- ALL-CONTRIBUTORS-LIST:END -->

Expand Down
156 changes: 156 additions & 0 deletions src/__tests__/events.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import React from 'react'
import {renderIntoDocument, clearDocument, fireEvent} from '../'

const eventTypes = [
{
type: 'Clipboard',
events: ['copy', 'paste'],
elementType: 'input',
},
{
type: 'Composition',
events: ['compositionEnd', 'compositionStart', 'compositionUpdate'],
elementType: 'input',
},
{
type: 'Keyboard',
events: ['keyDown', 'keyPress', 'keyUp'],
elementType: 'input',
init: {keyCode: 13},
},
{
type: 'Focus',
events: ['focus', 'blur'],
elementType: 'input',
},
{
type: 'Form',
events: ['focus', 'blur'],
elementType: 'input',
},
{
type: 'Focus',
events: ['change', 'input', 'invalid'],
elementType: 'input',
},
{
type: 'Focus',
events: ['submit'],
elementType: 'form',
},
{
type: 'Mouse',
events: [
'click',
'contextMenu',
'doubleClick',
'drag',
'dragEnd',
'dragEnter',
'dragExit',
'dragLeave',
'dragOver',
'dragStart',
'drop',
'mouseDown',
'mouseEnter',
'mouseLeave',
'mouseMove',
'mouseOut',
'mouseOver',
'mouseUp',
],
elementType: 'button',
},
{
type: 'Selection',
events: ['select'],
elementType: 'input',
},
{
type: 'Touch',
events: ['touchCancel', 'touchEnd', 'touchMove', 'touchStart'],
elementType: 'button',
},
{
type: 'UI',
events: ['scroll'],
elementType: 'div',
},
{
type: 'Wheel',
events: ['wheel'],
elementType: 'div',
},
{
type: 'Media',
events: [
'abort',
'canPlay',
'canPlayThrough',
'durationChange',
'emptied',
'encrypted',
'ended',
'error',
'loadedData',
'loadedMetadata',
'loadStart',
'pause',
'play',
'playing',
'progress',
'rateChange',
'seeked',
'seeking',
'stalled',
'suspend',
'timeUpdate',
'volumeChange',
'waiting',
],
elementType: 'video',
},
{
type: 'Image',
events: ['load', 'error'],
elementType: 'img',
},
{
type: 'Animation',
events: ['animationStart', 'animationEnd', 'animationIteration'],
elementType: 'div',
},
{
type: 'Transition',
events: ['transitionEnd'],
elementType: 'div',
},
]

afterEach(clearDocument)

eventTypes.forEach(({type, events, elementType, init}) => {
describe(`${type} Events`, () => {
events.forEach(eventName => {
const propName = `on${eventName.charAt(0).toUpperCase()}${eventName.slice(
1,
)}`

it(`triggers ${propName}`, () => {
const ref = React.createRef()
const spy = jest.fn()

renderIntoDocument(
React.createElement(elementType, {
[propName]: spy,
ref,
}),
)

fireEvent[eventName](ref.current, init)
expect(spy).toHaveBeenCalledTimes(1)
})
})
})
})
16 changes: 16 additions & 0 deletions src/__tests__/renderIntoDocument.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Due to issues with operating systems, filename case sensitivity, and git, I prefer all my files to use kebab-casing rather than camelCasing. Could you rename this file please? I really should have an eslint rule for it.

import {renderIntoDocument, clearDocument} from '../'

afterEach(clearDocument)

it('renders button into document', () => {
const ref = React.createRef()
renderIntoDocument(<div id="test" ref={ref} />)
expect(document.body.querySelector('#test')).toBe(ref.current)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could remove the id and the assertion could be: expect(document.body.firstChild).toBe(ref.current)

})

it('clears document body', () => {
renderIntoDocument(<div id="test" />)
clearDocument()
expect(document.body.innerHTML).toBe('')
})
22 changes: 20 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import ReactDOM from 'react-dom'
import {Simulate} from 'react-dom/test-utils'
import {queries, wait} from 'dom-testing-library'
import {queries, wait, fireEvent} from 'dom-testing-library'

function render(ui, {container = document.createElement('div')} = {}) {
ReactDOM.render(ui, container)
Expand All @@ -18,4 +18,22 @@ function render(ui, {container = document.createElement('div')} = {}) {
}
}

export {render, Simulate, wait}
function renderIntoDocument(ui) {
return render(ui, {
container: document.body.appendChild(document.createElement('div')),
})
}

function clearDocument() {
document.body.innerHTML = ''
}

// fallback to synthetic events for DOM events that React doesn't handle
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be "React events that the DOM doesn't support" ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment needs an update I think. Unless I'm misunderstanding. It should say:

// fallback to synthetic events for React events that the DOM doesn't support

const syntheticEvents = ['change', 'select', 'mouseEnter', 'mouseLeave']
syntheticEvents.forEach(eventName => {
document.addEventListener(eventName.toLowerCase(), e => {
Simulate[eventName](e.target, e)
})
})

export {render, Simulate, wait, fireEvent, renderIntoDocument, clearDocument}