Skip to content
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

add fireEvent from dom-testing-library #48

Merged
merged 15 commits into from
Apr 10, 2018

Conversation

jomaxx
Copy link
Collaborator

@jomaxx jomaxx commented Apr 10, 2018

What: add fireEvent

Why: #35

How: reexport from dom-testing-library

Checklist:

  • Documentation
  • Tests
  • Ready to be merged
  • Added myself to contributors table

Wait for testing-library/dom-testing-library#13 to be merged

@jomaxx
Copy link
Collaborator Author

jomaxx commented Apr 10, 2018

@sompylasar the 4 events that I've come across that aren't handled in React the same way as other events are change, select, mouseenter, mouseleave.

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

@sompylasar
Copy link
Contributor

@jomaxx Got it, thanks.

Copy link
Member

@kentcdodds kentcdodds left a 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 => {
Copy link
Member

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'))} = {},
Copy link
Member

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?

Copy link
Collaborator Author

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.

Copy link
Collaborator Author

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

@kentcdodds
Copy link
Member

kentcdodds commented Apr 10, 2018

Could you also update the package.json so the version of dom-testing-library is forced as part of this update?

@codecov
Copy link

codecov bot commented Apr 10, 2018

Codecov Report

Merging #48 into master will not change coverage.
The diff coverage is 100%.

Impacted file tree graph

@@          Coverage Diff          @@
##           master    #48   +/-   ##
=====================================
  Coverage     100%   100%           
=====================================
  Files           1      1           
  Lines           6     18   +12     
=====================================
+ Hits            6     18   +12
Impacted Files Coverage Δ
src/index.js 100% <100%> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 6d9c368...404e14b. Read the comment docs.

Copy link
Member

@kentcdodds kentcdodds left a 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
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

@kentcdodds kentcdodds left a 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!

@@ -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.

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)

src/index.js Outdated
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.

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.

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

README.md Outdated

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

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`.

README.md Outdated
)
```

#### `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)`

README.md Outdated

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

```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.

Copy link
Member

@kentcdodds kentcdodds left a 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
Copy link
Member

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.

Copy link
Collaborator Author

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.

Copy link
Collaborator Author

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

Copy link
Member

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? 😅

Copy link
Collaborator Author

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

Copy link
Collaborator Author

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)
Copy link
Member

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>)
Copy link
Member

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?

@antsmartian
Copy link
Collaborator

@jomaxx This is awesome! Great to see -- we support so much in this small library! Cheers 💯

Copy link
Member

@kentcdodds kentcdodds left a 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!

@kentcdodds kentcdodds merged commit 86d3508 into testing-library:master Apr 10, 2018
@kentcdodds
Copy link
Member

Thanks so much for your help! I've added you as a collaborator on the project. Please make sure that you review the other/MAINTAINING.md and CONTRIBUTING.md files (specifically the bit about the commit messages and the git hooks) and familiarize yourself with the code of conduct (we're using the contributor covenant). You might also want to watch the repo to be notified when someone files an issue/PR. Please continue to make PRs as you feel the need (you can make your branches directly on the repo rather than your fork if you want). Thanks! And welcome to the team :)

julienw pushed a commit to julienw/react-testing-library that referenced this pull request Dec 20, 2018
* chore: update contributors

* chore(readme): update to reflect the api
lucbpz pushed a commit to lucbpz/react-testing-library that referenced this pull request Jul 26, 2020
…d-8.0.4

Update lint-staged to the latest version 🚀
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants