-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Conversation
@sompylasar the 4 events that I've come across that aren't handled in React the same way as other events are
I haven't been able to get this working in jsdom so triggering the real events and falling back to synthetic events seem like the cleanest option |
@jomaxx Got it, thanks. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this! It's great!
src/index.js
Outdated
@@ -18,4 +21,11 @@ function render(ui, {container = document.createElement('div')} = {}) { | |||
} | |||
} | |||
|
|||
export {render, Simulate, wait} | |||
// fallback to synthetic events for DOM events that React doesn't handle | |||
;['change', 'select', 'mouseEnter', 'mouseLeave'].forEach(eventName => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer to give names to arrays rather than doing this.
const syntheticEvents = ['change', 'select', 'mouseEnter', 'mouseLeave']
syntheticEvents.forEach(eventName => {
document.addEventListener(eventName.toLowerCase(), e => {
Simulate[eventName](e.target, e)
})
})
Notice that I used document
rather than window
. I'm not certain whether that makes much of a difference in practice, but I checked the React source and I'm pretty sure that's where they attach event handlers.
src/index.js
Outdated
function render(ui, {container = document.createElement('div')} = {}) { | ||
function render( | ||
ui, | ||
{container = document.body.appendChild(document.createElement('div'))} = {}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We definitely don't want to do this right now. We could expose a renderIntoDocument
method that does this (and removes the node on unmount
or something). The problem with this is that you could have a bunch of elements dangling out on the body throughout your tests and if you don't clean it up it could break things in unexpected ways. Also it's a source of memory leaks.
As discussed in #35 we'll have to recommend to people (in the docs) that if they want to use this method, they must either 1) append the container
to the body themselves or 2) use the renderIntoDocument
(which I think we should create as a small abstraction over this function which appends the container to the body). In either case people should be warned that they should create a beforeEach(() => document.body.innerHTML = '')
in their test. Perhaps we could even create a util so they could do: beforeEach(clearDOM)
.
Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Works for me. I'd suggest an unmountAll
helper:
afterEach(unmountAll)
Clearing the DOM will clean up the DOM but won't trigger componentWillUnmount
on components which might have their own cleanup to do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe components cleaning up subscribers should not be our concern though
Could you also update the |
Codecov Report
@@ Coverage Diff @@
## master #48 +/- ##
=====================================
Coverage 100% 100%
=====================================
Files 1 1
Lines 6 18 +12
=====================================
+ Hits 6 18 +12
Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add the utilities we discussed renderIntoDocument
and clearDocument
with docs (for tests you can probably just use both of them in your fireEvent
tests). I think we should just recommend people do beforeEach(clearDocument)
in any test that they use renderIntoDocument
. We should also add to the fireEvent
docs that your components must be in the document for fireEvent
to work, so we recommend people use renderIntoDocument
and clearDocument
if they want to use fireEvent
. We should indicate also the benefit of using fireEvent
over Simulate
. Specifically that it's less react-specific and therefore aligns with the guiding principle more.
Thanks!
src/index.js
Outdated
@@ -18,4 +18,12 @@ function render(ui, {container = document.createElement('div')} = {}) { | |||
} | |||
} | |||
|
|||
export {render, Simulate, wait} | |||
// fallback to synthetic events for DOM events that React doesn't handle |
There was a problem hiding this comment.
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" ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Getting closer! This is going to be great. Thanks!
src/__tests__/renderIntoDocument.js
Outdated
@@ -0,0 +1,16 @@ | |||
import React from 'react' |
There was a problem hiding this comment.
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.
src/__tests__/renderIntoDocument.js
Outdated
it('renders button into document', () => { | ||
const ref = React.createRef() | ||
renderIntoDocument(<div id="test" ref={ref} />) | ||
expect(document.body.querySelector('#test')).toBe(ref.current) |
There was a problem hiding this comment.
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)
src/index.js
Outdated
document.body.innerHTML = '' | ||
} | ||
|
||
// fallback to synthetic events for DOM events that React doesn't handle |
There was a problem hiding this comment.
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
@@ -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. | |||
|
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
README.md
Outdated
|
||
#### `fireEvent[eventName](node: HTMLElement, eventInit)` | ||
|
||
Convenience methods for firing DOM events. Look [here](./src/events.js) for full list. |
There was a problem hiding this comment.
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`.
README.md
Outdated
) | ||
``` | ||
|
||
#### `fireEvent[eventName](node: HTMLElement, eventInit)` |
There was a problem hiding this comment.
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)`
README.md
Outdated
|
||
Convenience methods for firing DOM events. Look [here](./src/events.js) for full list. | ||
|
||
```javascript |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is great 👍 Just a few questions.
README.md
Outdated
fireEvent.click(getElementByText('Submit'), rightClick) | ||
// default `button` property for click events is set to `0` which is a left click. | ||
|
||
// don't forget to unmount component so componentWillUnmount can clean up subscriptions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this totally required for react to do its job? I'm not certain it's necessary 🤔
If it is then perhaps our clearDocument
should actually be called cleanup
and do that job for people. If it's required for everyone to do it, and it's not confusing or complicated for us to do it in the library, then we should do it in the library.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok we can do it in the library, but i think this is even more reason to have cleanup
be in an afterEach
hook so if a componentWillUnmount
throws an error it will be associated with the correct test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done but kept beforeEach
in examples
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok we can do it in the library, but i think this is even more reason to have cleanup be in an afterEach hook so if a componentWillUnmount throws an error it will be associated with the correct test.
This makes a lot of sense. Sorry, but could you change it back? 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
haha np, will change it back
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
README.md
Outdated
import { renderIntoDocument, clearDocument, render, fireEvent } | ||
|
||
// don't forget to clean up the document.body | ||
afterEach(clearDocument) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
README.md
Outdated
|
||
test('clicks submit button', () => { | ||
const spy = jest.fn(); | ||
const { unmount, getByText } render(<button onClick={spy}>Submit</button>) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The =
is missing in this assignment.
Also, shouldn't this example be using renderIntoDocument
instead of render
?
@jomaxx This is awesome! Great to see -- we support so much in this small library! Cheers 💯 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I love this. Thank you so much for making this happen!
Thanks so much for your help! I've added you as a collaborator on the project. Please make sure that you review the |
* chore: update contributors * chore(readme): update to reflect the api
…d-8.0.4 Update lint-staged to the latest version 🚀
What: add fireEvent
Why: #35
How: reexport from dom-testing-library
Checklist:
Wait for testing-library/dom-testing-library#13 to be merged