Add fill_option to Selenium for clearing with backspaces

Sending the correct number of backspace keys to clear an input before
filling it in with the desired text more accurately mimics real-world
behavior, which can be useful when used with libraries that want to
maintain a tight control over the DOM, such as React.js.

This option can be used by passing `:fill_options` to the `fill_in`
method in your feature specs:

  fill_in 'my_input', :with => 'my text',
    :fill_options => { :clear => :backspace }

Or, with the Ruby 1.9 style syntax:

  fill_in 'my input', with: 'my text'
    fill_options: { clear: :backspace }
This commit is contained in:
Joe Lencioni 2015-04-07 17:26:02 -07:00
parent c789ffb089
commit cfc507ff12
3 changed files with 33 additions and 4 deletions

View File

@ -4,6 +4,7 @@ Release date: unreleased
### Added
* 'formmethod' attribute support in RackTest driver [Emilia Andrzejewska]
* Clear field using backspaces in Selenium driver by using `:fill_options => { :clear => :backspace }` [Joe Lencioni]
#Version 2.4.4
Release date: 2014-10-13

View File

@ -23,7 +23,7 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
end
end
def set(value)
def set(value, fill_options)
tag_name = self.tag_name
type = self[:type]
if (Array === value) && !self[:multiple]
@ -42,9 +42,17 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
elsif value.to_s.empty?
native.clear
else
#script can change a readonly element which user input cannot, so dont execute if readonly
driver.browser.execute_script "arguments[0].value = ''", native
native.send_keys(value.to_s)
if fill_options[:clear] == :backspace
# Clear field by sending the correct number of backspace keys.
backspaces = [:backspace] * self.value.to_s.length
native.send_keys(*(backspaces + [value.to_s]))
else
# Clear field by JavaScript assignment of the value property.
# Script can change a readonly element which user input cannot, so
# don't execute if readonly.
driver.browser.execute_script "arguments[0].value = ''", native
native.send_keys(value.to_s)
end
end
elsif native.attribute('isContentEditable')
#ensure we are focused on the element

View File

@ -180,4 +180,24 @@ Capybara::SpecHelper.spec "#fill_in" do
end.to raise_error(Capybara::ElementNotFound)
end
end
context "with { :clear => :backspace } fill_option", :requires => [:js] do
it 'should only trigger onchange once' do
@session.visit('/with_js')
@session.fill_in('with_change_event', :with => 'some value',
:fill_options => { :clear => :backspace })
# click outside the field to trigger the change event
@session.find(:css, 'body').click
expect(@session.find(:css, '.change_event_triggered', :match => :one)).to have_text 'some value'
end
it 'should trigger change when clearing field' do
@session.visit('/with_js')
@session.fill_in('with_change_event', :with => '',
:fill_options => { :clear => :backspace })
# click outside the field to trigger the change event
@session.find(:css, 'body').click
expect(@session).to have_selector(:css, '.change_event_triggered', :match => :one)
end
end
end