React: Capybara + Selenium don't trigger React.DOM.input's onChange

Created on 3 Nov 2014  路  7Comments  路  Source: facebook/react

Hi,

I use Capybara for acceptance testing, and the behaviour differs between pure HTML input and an input contained in a JSX component. React.DOM input doesn't trigger onChange when Capybara sets it to an empty string (but it's triggered when I set it to space, for example).

Most helpful comment

I've ended up monkey patching Capybara Selenium. Granted, it'll only work on the Selenium driver, but it doesn't require any changes to the test suite.

class Capybara::Selenium::Node
  alias :_orig_set :set

  def set value
    native.send_keys :backspace if value.empty?
    _orig_set value
  end
end

All 7 comments

This is a Capybara problem. If you just fill input with nothing, Capybara won't send any keystrokes to a browser. That result with no change events emitted.

For reference I would paste what author of Capybara ( @jnicklas ) wrote on ticket I attached on bottom of my post:

def set(value)
  native.clear
  native.send_keys(value.to_s)
end

That's simplified version of what happens when you try to fill in the input on Capybara. You can check it yourself. Get a filled input (that contains something on page load) and change its value. It will clean and then Capybara would type requested value key by key.

You can use one of available hacks for Selenium I know you are using (link below contains one) or change your tests architecture to avoid blank-strings checking (if possible).

Reference: https://github.com/jnicklas/capybara/issues/203

It has since been fixed in Capybara, and is now only true for React-based inputs. onChange is triggered for simple HTML inputs when I set a field to ''.

I'm not sure that it's the right commit, but here it is: "Trigger change events when clearing fields".
https://github.com/jnicklas/capybara/commit/c9ba16cd08fd1f878d09ef778516240c78fbbd2e

Weird, it does ignore the change method. The fastest and most hacky solution I found is to execute React event using testing library. We can use #execute_script from Selenium driver.

execute_script "React.addons.TestUtils.Simulate.change(#{node})"

It is really shaming way to achieve a goal, but I guess if you want to do this well, you should simulate backspacing whole input.

I've ended up monkey patching Capybara Selenium. Granted, it'll only work on the Selenium driver, but it doesn't require any changes to the test suite.

class Capybara::Selenium::Node
  alias :_orig_set :set

  def set value
    native.send_keys :backspace if value.empty?
    _orig_set value
  end
end

If I'm understanding the Capybara commit right, setting the value does not trigger a change event. The test has to click on the body in order for the event to fire (which would happen if an input has focus, .value is set via js and then the click is triggered).

Is the change event actually firing without that?

For a non-React input, change does fire when native.clear is called. No need to click anywhere. The commit is not really relevant, what is relevant is that I've tested Capybara Selenium to work in that way with a non-React input.

Closing since this isn't actionable for us.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

gabegreenberg picture gabegreenberg  路  264Comments

acdlite picture acdlite  路  83Comments

kib357 picture kib357  路  103Comments

gaearon picture gaearon  路  104Comments

AdamKyle picture AdamKyle  路  148Comments