Why React event handler is not called on dispatchEvent?

Misha Moroshko picture Misha Moroshko · Aug 21, 2016 · Viewed 19.9k times · Source

Consider the following input element in a React component:

<input onChange={() => console.log('onChange')} ... />

While testing the React component, I'm emulating user changing the input value:

input.value = newValue;
TestUtils.Simulate.change(input);

This causes 'onChange' to be logged, as expected.

However, when the 'change' event is dispatched directly (I'm using jsdom):

input.value = newValue;
input.dispatchEvent(new Event('change'));

the onChange handler is not called.

Why?

My motivation to use dispatchEvent rather than TestUtils.Simulate is because TestUtils.Simulate doesn't support event bubbling and my component's behavior relies on that. I wonder whether there is a way to test events without TestUtils.Simulate?

Answer

rofrol picture rofrol · Jul 27, 2017

One way to do it without ReactTestUtils.Simulate:

var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'https://unpkg.com/react-trigger-change/dist/react-trigger-change.js';
document.head.appendChild(script);
input.value = value;
reactTriggerChange(input);

Look at the source of react-trigger-change to just cherry-pick what's needed. Example snippet:

if (nodeName === 'select' ||
    (nodeName === 'input' && type === 'file')) {
    // IE9-IE11, non-IE
    // Dispatch change.
    event = document.createEvent('HTMLEvents');
    event.initEvent('change', true, false);
    node.dispatchEvent(event);
  }