I am using jQuery to bind a text field to the keyUp event. A fill_in "field_id", with => "test" works as expected (keyUp is triggered), but clearing the field with fill_in "field_id", with => "" does not trigger that event.
Which driver?
The selenium driver. Is it a selenium problem then? I am still not sure about the internals of Capybara ... it simply works ... and that's great :-)
setting a field's value is implemented like this in Capybara, simplified:
def set(value)
native.clear
native.send_keys(value.to_s)
end
My guess would be that if you're setting the value to "", no keys are ever actually sent, hence no key up event. Not really sure how to fix that. There's a gem called send_keys which might give you more control over this, or you could send a string with a single space or something.
It might be possible to fix it in Capybara, but I'm afraid that we'd just add more unexpected, ambiguous behaviour (_which_ key should have been pressed, backspace, space?). So I think it's probably better to leave it as is.
Ok, no problem for me as I simply workaround that by sending Javacript. Thanks for the info Jonas.
Closing this then.
Here's another workaround:
fill_in :field_id, :with => ""
send_keys [:control, "a"]
I realize Control+A might be OS-specific but at least it works even when evaluate_script doesn't (for me with FF evaluate_script was timing out).
To work around this I use fill_in to clear the input field, and then manually trigger a keyup event on the field. I am using capybara via cucumber, so the below is the helper method I use for triggering events, and the cucumber step that I use when I need to clear a field:
def trigger_event_for(selector, event)
raise "Please supply a selector" if selector.blank?
if Capybara.javascript_driver == :selenium
page.execute_script %Q{ $('#{selector}').trigger("#{event}") }
end
if Capybara.javascript_driver == :webkit
page.find(selector).trigger(event.to_sym)
end
end
Then 'delete the content of "$id"' do |id|
fill_in id, with: ""
trigger_event_for("##{id}", :keyup)
end
I was having a similar problem.
fill_in doesn't trigger 'change' event.
@nickstreet hack is working like a charm for me.
Thanks!
ruby 2.1.0
rails (= 4.1.0)
cucumber 1.3.14
selenium-webdriver (2.42.0)
capybara (2.2.1)
capybara-webkit (1.1.0)
@BMorearty When I use your suggestion, I get undefined method `send_keys' for #Object:0x007fc979f730d8 (NoMethodError)
Using this
page.find(:xpath, "//input[@placeholder = 'Prefix']").set ""
send_keys [:control, "a"]
since the Prefix field does not have an id (it's React) so I am trying to access a field with its placeholder text. It works fine to set it to a value but even though I see the set command above clear the field, the original value is still in the field once I save the form.
@DougMaisells send_keys needs to be called on an element - you probably want something like
prefix = page.find_field('Prefix')
prefix.set ""
prefix.send_keys [:control, "a"]
of you could just do something like
find_field('Prefix').send_keys([:control, "a"], :backspace)
which should have a similar effect (assuming ctrl-a selects all contents in the platform you're testing on).
@twalpole Unfortunately this field doesn't have an id, it's react and I had to access with page.find(:xpath) method
@nickstreet Thanks but doesn't work. I can see the field clear when the script runs but when as the script runs and focus travels to other fields, the former value is restored....
fill_in 'person-form-title', with: ""
trigger_event_for('person-form-title', :keyup)
#send_keys [:control, "a"]
sleep 1
@DougMaisells find_field finds by id, name or placeholder text - so find_field('Prefix') should find the element with matching placeholder text rather than needing xpath.
@twalpole so do I replace the page.find up above with find_field?
person_title = page.find(:field, 'person-form-title')
person_title.set ""
person_title.send_keys[:control, "a"]
gives error: no implicit conversion of Symbol into Integer (TypeError)
@DougMaisells try
person_title = page.find_field('person-form-title')
person_title.set ""
person_title.send_keys([:control, "a"])
If that still errors - tell me which line it's erring on
@twalpole Thanks, got by run-time error but still does not persist with the zapped value. It zaps the field as I run the scripts but the value is restored as the script travels through other fields on the form. It must be a React thing; I'll have to get with my developer. (I am QA)
@DougMaisells Ok -- it all depends on which event React is looking for to trigger it's model updates. You might want to try just doing the single line (rather than separately setting and then trying to trigger the needed events)
find_field('person-form-title').send_keys([:control, "a"], :backspace)
and see if that triggers the needed events - since that should trigger key events and the change event
@twalpole Tom, you are talking over my head now. My extent of understanding of React is it's a javascript framework which my app and others like Facebook is written in. I'll get with my dev. BTW, what you suggested above didn't work either. This time, it doesn't even render the field as zapped and it stays with its value where the other tries at least zapped the field in real-time but then it restored a moment later as it went through other fields. But with manual testing, I can highlight the value, hit the delete key, and tab (or use mouse to move focus to another field) and the zapped value persists. If you have a quick and dirty way to emulate the manual actions above, I'm all ears.
@DougMaisells - As I stated previously, my example assumed ctrl-a was selecting the contents of the field on your platform -- if howeever you're on OS X it would be cmd-a - so then your test could use
find_field('person-form-title').send_keys([:command, "a"], :backspace)
ie - send cmd-a to select everything then hit backspace to delete it all - anyway it may be best if you did talk with a developer about what events are required to complete the action with React
@twalpole Ooh, I missed that connection. Yes, I am on OSX and yes that works. I glanced over that detail above because I wasn't sure what was being talked about.
Most helpful comment
@DougMaisells send_keys needs to be called on an element - you probably want something like
of you could just do something like
find_field('Prefix').send_keys([:control, "a"], :backspace)
which should have a similar effect (assuming ctrl-a selects all contents in the platform you're testing on).