React: Triggering events on real DOM nodes doesn't trigger synthetic events

Created on 24 Feb 2015  路  20Comments  路  Source: facebook/react

From Twitter: https://twitter.com/Vjeux/status/569985084524081153

When using PhantomJS for testing browser interaction, often times what seems to happen is that values get changed directly on the DOM elements and then the 'change' event is triggered on the element. Because of this, interacting with ReactJS elements through PhantomJS and through jQuery doesn't work for some interactive elements like <input> and <select>.

Of course, the easiest solution is to take the real elements that are mounted and attach event listeners to them like $(this.MyRef.getDOMNode()).on(EVENT, CALLBACK), but it isn't the most pleasant experience.

Is there any interest in mirroring events on the real nodes to the synthetic events, or is this situation normal? I'd like to be able to interact with my application through PhantomJS, but this seems to be quite the blocker when interacting with input and select elements.

JSBin example here: http://jsbin.com/xawogo/3/edit

Most helpful comment

Trying to get an interactive product tour and was hoping to drive the UI through events (just like the user would).

Just as @bloodyowl said, the problem looks to be with jQuery not React. This issue can probably be closed.

Use the code below instead.

var event = document.createEvent("HTMLEvents");
event.initEvent("click", true, true);
var target = $('.about-page-link')[0];
target.dispatchEvent(event);

All 20 comments

I think the underlying reason this happens is that there isn't a 1 to 1 relationship with the native events and the events react fires. For instance while react responds to an onChange handler the event it is actually listening to in most cases is the 'input' event, or a click event in other cases. This happens a bunch with input components because under the hood React is smoothing over a browser inconsistencies to give a common event interface across browser's. I test my react components just fine with phantom js by making use of the test utils react includes, especially 'simulate()' which triggers the react event you expect. I, of course may just have a different situation where that works, it may be different than your use case.

the issue here is that jQuery doesn't trigger a real DOM event, but tries to find callbacks in its own internal event map (as you can see http://jsbin.com/pesanowoqe/1/edit?js,console,output)

Is there a good solution for using PhantomJS to trigger things like submitting a form, clicking a button etc..? I'm having the same issue where React listeners never get triggered.

@jquense yea I've played with the test utils. But I'm interested in end to end testing with phantomJS, and it doesn't play well with React.

I guess I'm not quite sure why not... I write all my tests using the test utils and Phantomjs and have had no problems

I've used the test utils with Jest. Are you able to integrate it directly with phantomJS to trigger events? Could you share an example with me?

@jquense @jongbeau I'd love to get a look at that example if it exists.

@jongbeau I'm able to use phantom JS to trigger React events with React.addons.TestUtils.Simulate. But it doesn't work if I want to test against production because a minimized React is used there without the TestUtils. I tried to inject a React Test Utils into the page. But it still doesn't trigger the React events.

thank you!

Jorge Vytautas Daukantas


From: Song Xie [email protected]
Sent: Friday, October 23, 2015 9:56 AM
To: facebook/react
Subject: Re: [react] Triggering events on real DOM nodes doesn't trigger synthetic events (#3249)

@jongbeauhttps://github.com/jongbeau I'm able to use phantom JS to trigger React events with React.addons.TestUtils.Simulate. But it doesn't work if I want to test against production because a minimized React is used there without the TestUtils. I tried to inject a React Test Utils into the page. But it still doesn't trigger the React events.

Reply to this email directly or view it on GitHubhttps://github.com/facebook/react/issues/3249#issuecomment-150531726.

Trying to get an interactive product tour and was hoping to drive the UI through events (just like the user would).

Just as @bloodyowl said, the problem looks to be with jQuery not React. This issue can probably be closed.

Use the code below instead.

var event = document.createEvent("HTMLEvents");
event.initEvent("click", true, true);
var target = $('.about-page-link')[0];
target.dispatchEvent(event);

@yagudaev You, sir, just saved us a lot of time. Thank you!

im having this same issue with IE9, jquery and react.

there is some jquery being used to do to:

/* not our code we have control over */
$formInputEl.val( 'bob' );

but our react components onChange events never hear any onChange event.

we've tried shimming $.val like so:

var originalVal = $.fn.val;
$.fn.val = function () {
            var result = originalVal.apply(this, arguments);
            if (_.first(arguments) !== undefined && this instanceof $ && this.length) {
                var event;
                if (ua.isIE){
                     event = document.createEvent("HTMLEvents");
                     event.initEvent("input", true, true);
                } else {
                    event = new Event('input', {bubbles:true});
                }

                if (this instanceof $ && this.length){
                    this[0].dispatchEvent(event);
                }
            }
            return result;
        };

but react still does not hear anything. it works on ie10 and ie11. weve also tried polyfilling ie custom events.

how does react listen for onChange?, if we use the non production react and TestUtils.simulate it works even in ie9. is there a way to replicate that with production react?

seems like its a combination of ObjectDefineProperty and an event for 'propertychange': https://github.com/facebook/react/blob/3b96650e39ddda5ba49245713ef16dbc52d25e9e/src/renderers/dom/client/eventPlugins/ChangeEventPlugin.js

For now, I've pub/subbed my way around this (rather than use DOM events). In IE9, there is definitely an issue with listening to programmatic propertychange events.

hi @yagudaev
How about _KeyBoardEvent_, I tried keypress, but it does not work...

not sure jQuery is a problem. was able to simulate triggering click handlers with jquery click(). keyboard events however do not work, jquery or not:

cument).arrive(".rc--searchBar--input", {onceOnly: true}, function() { var keyboardEvent = document.createEvent("KeyboardEvent"); var initMethod = typeof keyboardEvent.initKeyboardEvent !== 'undefined' ? "initKeyboardEvent" : "initKeyEvent"; keyboardEvent[initMethod]( "keypress", // event type : keydown, keyup, keypress true, // bubbles true, // cancelable window, // viewArg: should be window false, // ctrlKeyArg false, // altKeyArg false, // shiftKeyArg false, // metaKeyArg 13, // keyCodeArg : unsigned long the virtual key code, else 0 0 // charCodeArgs : unsigned long the Unicode character associated with the depressed key, else 0 ); $(".rc--searchBar--input").val(term).focus(); document.querySelector('.rc--searchBar--input').dispatchEvent(keyboardEvent);

If you are working on an end-to-end test suite, there is no need to manually simulate events. Testing tools provide appropriate methods to simulate user input, which dispatch all the necessary events. In PhantomJS the idiomatic way to perform input is through sendEvent, but it's quite low-level. Instead use PhantomJS together with Selenium or CasperJS. Nightmare is another option. All of these tools include methods for simulating keyboard and mouse input. In this way, React's synthetic events will be triggered as appropriate.

For unit and integration tests that are run in a browser ReactTestUtils.Simulate should generally be sufficient. If you find yourself writing unit tests against a production bundle, chances are high that you should be writing end-to-end tests using the tools listed above instead.

If you still need to trigger React's synthetic change events directly for some reason and the bundle is built for production, you can take a look at my react-trigger-change package.

You can鈥檛 use jQuery for this; it doesn鈥檛 actually trigger DOM events.
See https://github.com/facebook/react/issues/3249#issuecomment-77814784.

The approach by @yagudaev (https://github.com/facebook/react/issues/3249#issuecomment-177750141) and @vitalyq (https://github.com/facebook/react/issues/3249#issuecomment-292919084) should be helpful.

This issue cannot be closed and it's need to fix this bug. I used a very ugly hack to simulate a synthetic event

@devbazilio File a new issue please and describe your problem in detail. Thanks. Posting in stale issues isn鈥檛 helpful.

Was this page helpful?
0 / 5 - 0 ratings