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

Triggering events on real DOM nodes doesn't trigger synthetic events #3249

Closed
justinwoo opened this issue Feb 24, 2015 · 20 comments
Closed

Triggering events on real DOM nodes doesn't trigger synthetic events #3249

justinwoo opened this issue Feb 24, 2015 · 20 comments

Comments

@justinwoo
Copy link
Contributor

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

@jquense
Copy link
Contributor

jquense commented Mar 9, 2015

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.

@bloodyowl
Copy link
Contributor

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)

@jongbeau
Copy link

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
Copy link
Contributor

jquense commented Mar 27, 2015

@jongbeau http://facebook.github.io/react/docs/test-utils.html#simulate

@jongbeau
Copy link

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

@jquense
Copy link
Contributor

jquense commented Mar 28, 2015

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

@jongbeau
Copy link

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?

@TSMMark
Copy link

TSMMark commented Sep 22, 2015

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

@aifreedom
Copy link

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

@daukantas
Copy link

thank you!

Jorge Vytautas Daukantas


From: Song Xie notifications@github.com
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//issues/3249#issuecomment-150531726.

@yagudaev
Copy link

yagudaev commented Feb 1, 2016

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);

@zdenekhatak
Copy link

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

@NickStefan
Copy link

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.

@NickStefan
Copy link

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.

@lovedota
Copy link

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

@chalda
Copy link

chalda commented Feb 28, 2017

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:

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

@vitalyq
Copy link

vitalyq commented Apr 10, 2017

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.

@gaearon
Copy link
Collaborator

gaearon commented Oct 2, 2017

You can’t use jQuery for this; it doesn’t actually trigger DOM events.
See #3249 (comment).

The approach by @yagudaev (#3249 (comment)) and @vitalyq (#3249 (comment)) should be helpful.

@linux019
Copy link

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

@gaearon
Copy link
Collaborator

gaearon commented Aug 29, 2018

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

@facebook facebook locked as off-topic and limited conversation to collaborators Aug 29, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests