React: onChange event not getting triggered via selenium clear()

Created on 18 Oct 2016  路  10Comments  路  Source: facebook/react

Do you want to request a _feature_ or report a _bug_?
Possible bug

What is the current behavior?
according to selenium spec and based on issues reported the .clear() method triggers an DOM onChange event spec, issue
However, when using clear, my input onChange handler is not being triggered, in the browser I can see the input as empty

What is the expected behavior?
expect onChange handler to trigger

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
using React 15.2 - reproduced on both firefox & chrome - latest version as of this post

Most helpful comment

@jquense thank you for taking the time for the explanation, it's not hard to work around this issue but the first time I encountered it took me a while to figure out what's happening and why my selenium tests weren't working as expected. I think there's a thread/proposal now in the w3c spec for webdriver to trigger an input event for clear().

will now close the issue.

All 10 comments

furthermore, I've manually attached an onchange event via the reference of the input and this does indeed get triggered

class MyInput extends Component {
  constructor(props) {
    super(props);
    this.state = {
      value: '',
    };
  }

  componentDidMount() {
    this.elem.onchange = () => console.log('Changing');
  }

  changeHandler = (evt) => {
    console.log('ChangeHandler triggered');
    this.setState({
      value: evt.target.value,
    });
  }

  render() {
    const { value } = this.state;
    return (
      <input
        ref={(el) => (this.elem = el)}
        id='myInput'
        name='myInput'
        onChange={this.changeHandler}
        value={value}
      />
    );
  }
}
  • doing setValue triggers both handlers
  • doing clear only triggers dom attached change handler

Bump. Any word on this issue? We have been hitting the same problem with Selenium.

I came across this problem too. any workarounds ?

+1 to fix this issue

I don't think there is anyway we can fix this. Selenium is operating on an API much lower than anything React can even touch. If it's not working it's because the selenium drivers aren't firing the correct native events for the input. My Suggestion to everyone is to use setValue() to an empty string as that seems more stable in terms of the right behavior

@jquense is it though (i'm not trying to be snarky, maybe it's something I'm not understanding properly) ? if I add a changeHandler to the actual dom element than that change handler triggers

ref={(el) => (this.elem = el)}

so the actual dom element changeEvent is triggered, it just doesn't seem to be picked up by react onChange listener. to be more specific:

componentDidMount() {
   // this triggers
    this.elem.onchange = () => console.log('Changing');
  }
  // this doesn't
changeHandler = (evt) => {
  console.log('ChangeHandler triggered');
  this.setState({
    value: evt.target.value,
  });
}

render() {
    const { value } = this.state;
    return (
      <input
        ref={(el) => (this.elem = el)}
        id='myInput'
        name='myInput'
        onChange={this.changeHandler}
        value={value}
      />
    );
  }

React isn't listening to onChange events in most cases it's listening for onInput so that would be the event to test here is a more accurate test i think:

componentDidMount() {
   // this triggers
    document.addEventListener('input', (e) => {
      console.log(e.target) // should be this.elem
    })
  }
  // this doesn't
changeHandler = (evt) => {
  console.log('ChangeHandler triggered');
  this.setState({
    value: evt.target.value,
  });
}

render() {
    const { value } = this.state;
    return (
      <input
        ref={(el) => (this.elem = el)}
        id='myInput'
        name='myInput'
        onChange={this.changeHandler}
        value={value}
      />
    );
  }

Again, I might be understanding event documentation wrong but it specifically says:

Here, e is a synthetic event. React defines these synthetic events according to the W3C spec, so you don't need to worry about cross-browser compatibility. See the SyntheticEvent reference guide to learn more.. I understand this is about the actual events, but I assumed this applies to the listeners as wel.

I was assuming it was a 1 = 1 correspondence between dom listeners & react listeners - onChange triggers on onchange and not only on oninput

the documentation doesn't cover anything on this difference: https://facebook.github.io/react/docs/handling-events.html

The documentation doesn't really cover this because it's an implementation detail and not generally relevant to using React. The selenium case is a bit special because you are approaching react from "underneath" it which is not usual. But yes there may not be 1 to 1 between the DOM and react events. Consider the onChange event in React, it fires for each keystroke, unlike the native event which only fires when you blur off the input. They probably should have named the event onInput because that's the behavior its actually emulating but what can you do. Generally events are pretty close to what you'd imagine the underlying event is, but onChange is particularly "abnormal".

React also handles delegating events. So rather then listen to each element individually it listens at the top level once and forwards events as they happen to React, which then traverses up and down the tree mimicking native event bubbling and capturing. This should not affect a selenium test tho, if selenium is triggering the correct events they will bubble up and be seen by React.

@jquense thank you for taking the time for the explanation, it's not hard to work around this issue but the first time I encountered it took me a while to figure out what's happening and why my selenium tests weren't working as expected. I think there's a thread/proposal now in the w3c spec for webdriver to trigger an input event for clear().

will now close the issue.

Was this page helpful?
0 / 5 - 0 ratings