Hi 👋 Thanks for the great library! Think I may have found a bug but if not I would love to know what I'm doing wrong here.
react-testing-library version: 5.4.4react version: 16.7.0node version: 10.15.0npm (or yarn) version: yarn 1.10.1test('disabled checkbox cannot be selected', () => {
const onChange = jest.fn()
const {getByTestId} = render(
<input
type="checkbox"
onChange={onChange}
data-testid="checkbox"
disabled
/>,
)
const checkbox = getByTestId('checkbox')
fireEvent.click(checkbox)
expect(onChange).not.toHaveBeenCalled() // this fails
})
I wrote a test to check that a checkbox onChange function would not be called if the checkbox is disabled.
The test failed saying that the onChange function had been called.
https://codesandbox.io/s/91684p354
The test should pass. onChange functions should not be called in the test if the checkbox is disabled.
Not sure, haven't looked into the code yet.
Confirmed! This is pretty odd! I'm not sure what it could be. Anyone wanna dig into this one? Pretty good learning opportunity here :)
You should use onClick listener for checkbox inputs
https://codesandbox.io/s/j22y6pl21y
/**
* SECTION: handle `click` event
*/
function shouldUseClickEvent(elem) {
// Use the `click` event to detect changes to checkbox and radio inputs.
// This approach works across all browsers, whereas `change` does not fire
// until `blur` in IE8.
var nodeName = elem.nodeName;
return nodeName && nodeName.toLowerCase() === 'input' && (elem.type === 'checkbox' || elem.type === 'radio');
}
Thanks @puemos, but the fact is that the tests function differently from when you do this in an app. You definitely should be able to use onChange like this and fire a click event. Something else is up 🤔
I don't know if this is a problem, but either for disabled or disabled={true}, render.debug() shows me <input disabled="" />. If I create a component in React in this way, the input is not disabled, so you can click on it.
Could it be a problem with the jsdom?
@kentcdodds My feeling is there is a problem with firEvent of dom-testing-library somehow. Did not get the problem when a click is triggered in an element is self. Can you suggest me the best way to figure out the problem?
This is interesting. I created a vanilla JavaScript version of this:
https://codesandbox.io/s/q70qj31m46
const app = document.getElementById('app')
app.innerHTML = ''
const input = document.createElement('input')
input.setAttribute('type', 'checkbox')
input.setAttribute('disabled', 'true')
let clickCalled = false
input.addEventListener('click', () => {
clickCalled = true
})
let changeCalled = false
input.addEventListener('change', () => {
changeCalled = true
})
let inputCalled = false
input.addEventListener('input', () => {
inputCalled = true
})
app.appendChild(input)
// this is basically what fireEvent.click does
const event = new MouseEvent('click', {
bubbles: true,
cancelable: true,
button: 0,
})
input.dispatchEvent(event)
The result is that the input and change handlers are called, but the click handler is not called. And the input actually gets checked despite being disabled.
I'm guessing this has something to do with a strange specification or something. If someone wants to investigate this further then I'd welcome help there...
I'm afraid I don't have time to dedicate to this problem at the moment.
It looks like this may be a case where the spec was followed a little _too_ closely. According to the Spec:
A form control that is disabled must prevent any click events that are queued on the user interaction task source from being dispatched on the element.
In the vanilla JS example, we can see that it is in fact not dispatching the click event, but dispatching the remaining events.
My hypothesis is that browsers are doing some special handling for dispatching click events as opposed to other events in order to control ad clicking (I may be totally off basis here though I'm no expert). This is based entirely off of this method:
https://github.com/chromium/chromium/blob/master/third_party/blink/renderer/core/dom/events/event_dispatcher.cc#L77
Which has this line that immediately returns if it's a form element that is disabled:
https://github.com/chromium/chromium/blob/master/third_party/blink/renderer/core/dom/events/event_dispatcher.cc#L90
So yeah...my guess is that the right way to handle this is to make sure we are more closely simulating what the browser appears to be doing, and swallowing the click event if the element is disabled.
But that would be a change for react right? Not react-testing-library
I don't think so. Since React is just proxying the event, they don't do anything around calling dispatchEvent to my knowledge.
My guess is that we need to do something here: https://github.com/kentcdodds/dom-testing-library/blob/master/src/events.js#L310
To account for the click event on ignored elements, and just swallow the event. This will mimic what the browser is doing under the hood (and I'm guessing the feature we would get if we could actually click a button rather than just dispatching the click event).
Thoughts?
I think it will make more sense when I see a pull request. Anyone willing to open that up?
I'll work on it!
On Tue, Feb 19, 2019, 2:37 PM Kent C. Dodds notifications@github.com
wrote:
I think it will make more sense when I see a pull request. Anyone willing
to open that up?—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/kentcdodds/react-testing-library/issues/275#issuecomment-465299986,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ADw5WQaWqaXZsNbMRT4HlCr3AM3Z_a7Uks5vPGCJgaJpZM4aPLjm
.
This is handled by user-event.
Most helpful comment
This is handled by user-event.