React Created Form Does Not Update Support State Object

I am trying to automate the login form for an Instagram web application:

https://instagram.com/accounts/login/

With the following code (you can run it on the Chrome console):

var frm = window.frames[1].document.forms[0]; frm.elements[0].value = 'qacitester'; frm.elements[1].value = 'qatester'; frm.elements[2].click(); 

Although the inputs are full when I track the XHR request, I see that this is posted:

username = & password = & Intent =

instead of this:

username = qacitester & password = qatester & Intent =

And forces the web application to not authenticate. You do not know why the input values ​​are not transferred to the backup object (model?) React?

+8
javascript reactjs
source share
3 answers

Instagram uses the linkState method from ReactLink:

http://facebook.imtqy.com/react/docs/two-way-binding-helpers.html

The login page refers to bundles/Login.js , which contains the compressed code as follows:

 o.createElement("input", { className:"lfFieldInput", type:"text", name:"username", maxLength:30, autoCapitalize:!1, autoCorrect:!1, valueLink:this.linkState("username") })) 

If you look at the documentation for ReactLink, this means that the value of the input field only returns to the state when the change event is fired in the input fields. However, it is not as simple as simply triggering a change event on a node in the question - I think it is because React normalizes browser events. React docs specifically say that onChange in React is not quite the same as onChange in the browser for various reasons:

http://facebook.imtqy.com/react/docs/dom-differences.html

Fortunately, in your case, Instagram uses React with Addons included, which gives you access to React TestUtils, so you can do:

 var frm = window.frames[1].document.forms[0]; var fReact = window.frames[1].React; fReact.addons.TestUtils.Simulate.change(frm.elements[0], {target: {value: 'qacitester' }}); fReact.addons.TestUtils.Simulate.change(frm.elements[1], {target: {value: 'qatester' }}); frm.elements[2].click(); 

Further documentation here:

http://facebook.imtqy.com/react/docs/test-utils.html

Please note: since the login form is in an iframe, you must use a React instance from this iframe, otherwise TestUtils will not be able to find the nodes correctly.

This will only work in situations where React Addons are included on the page. The normal assembly of Non-Addons React will require a different solution. However, if you are specifically talking about ReactLink, then this is an addon, so this is not a problem.

+5
source share

Answering my own question, the required event is input . This code seems to work:

 var doc = window.frames[1].document; var frm = doc.forms[0]; frm.elements[0].value = 'qacitester'; var evt = doc.createEvent('UIEvent'); evt.initUIEvent('input', true, false); frm.elements[0].dispatchEvent(evt); frm.elements[1].value = 'qatester'; frm.elements[1].dispatchEvent(evt); frm.elements[2].click(); 
+4
source share

The login form is actually inside the iFrame, which makes things more complicated. I was able to successfully send the login by entering the following code from the Chrome console. I am using React TestUtils, but with AutoType might be fine:

 // run in Chrome console var frame = document.querySelector('iframe[src*="login"]'); var s = document.createElement('script'); var username = frame.contentDocument.querySelector('input[name="username"]'); var password = frame.contentDocument.querySelector('input[name="password"]'); s.src = "https://fb.me/react-with-addons-0.12.0.js"; frame.contentDocument.body.appendChild(s); // wait for the script request to resolve and use: change = frame.contentWindow.React.addons.TestUtils.Simulate.change; change(username, {target: {value: 'My Great Username'}}); change(password, {target: {value: 'securepassword'}}); 

Background

React uses its own virtual event system and typically uses controlled components , which essentially means that the value input is set by reaction and trickle down to the DOM element.

With this in mind, I believe that the problem you are facing is that the reaction is looking for a key event at the input and uses the input value during the event to set the value of the DOM element. Since you simply set the value property of the DOM element, you exit the loop of controlled components.

I made a quick splash, trying to send KeyboardEvent to the input, but, alas, it was unsuccessful. I will update my answer if I really succeed.

Unsatisfactory workaround:

Use casper / phantomjs to automate form filling. This means that you don’t have to worry about sending events yourself, and you can just let the “browser” do it for you. It is also better than working in the console manually.

+1
source share

All Articles