Skip to content

Commit

Permalink
Remove unnecessary readonly check because actions shouldn't do anythi…
Browse files Browse the repository at this point in the history
…ng on readonly elements anyway

Get element name and type in one request in Selenium driver
  • Loading branch information
twalpole committed Apr 2, 2019
1 parent 96da1d2 commit e39c65e
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 13 deletions.
2 changes: 1 addition & 1 deletion lib/capybara/node/element.rb
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def value
#
# @return [Capybara::Node::Element] The element
def set(value, **options)
raise Capybara::ReadOnlyElementError, "Attempt to set readonly element with value: #{value}" if readonly?
raise Capybara::ReadOnlyElementError, "Attempt to set readonly element with value: #{value}" if ENV['CAPYBARA_THOROUGH'] && readonly?

options = session_options.default_set_options.to_h.merge(options)
synchronize { base.set(value, options) }
Expand Down
23 changes: 18 additions & 5 deletions lib/capybara/selenium/node.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,10 @@ def style(styles)
def set(value, **options)
raise ArgumentError, "Value cannot be an Array when 'multiple' attribute is not present. Not a #{value.class}" if value.is_a?(Array) && !multiple?

case tag_name
tag_name, type = attrs(:tagName, :type)
case tag_name.downcase
when 'input'
case self[:type]
case type.downcase
when 'radio'
click
when 'checkbox'
Expand Down Expand Up @@ -146,9 +147,8 @@ def selected?; boolean_attr(native.selected?); end

def disabled?
return true unless native.enabled?

# WebDriver only defines `disabled?` for form controls but fieldset makes sense too
tag_name == 'fieldset' && find_xpath('ancestor-or-self::fieldset[@disabled]').any?
find_xpath('self::fieldset/ancestor-or-self::fieldset[@disabled]').any?
end

def content_editable?
Expand Down Expand Up @@ -211,7 +211,7 @@ def set_text(value, clear: nil, **_unused)
# 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.execute_script "arguments[0].value = ''", self unless clear == :none
driver.execute_script "if (!arguments[0].readOnly){ arguments[0].value = '' }", self unless clear == :none
send_keys(value)
end
end
Expand Down Expand Up @@ -269,6 +269,7 @@ def set_datetime_local(value) # rubocop:disable Naming/AccessorMethodName

def update_value_js(value)
driver.execute_script(<<-JS, self, value)
if (arguments[0].readOnly) { return };
if (document.activeElement !== arguments[0]){
arguments[0].focus();
}
Expand Down Expand Up @@ -352,6 +353,18 @@ def build_node(native_node, initial_cache = {})
self.class.new(driver, native_node, initial_cache)
end

def attrs(*attr_names)
return attr_names.map { |name| self[name.to_s] } if ENV['CAPYBARA_THOROUGH']

driver.evaluate_script <<~'JS', self, attr_names.map(&:to_s)
(function(el, names){
return names.map(function(name){
return el[name]
});
})(arguments[0], arguments[1]);
JS
end

GET_XPATH_SCRIPT = <<~'JS'
(function(el, xml){
var xpath = '';
Expand Down
26 changes: 19 additions & 7 deletions lib/capybara/spec/session/node_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,24 @@
expect(@session.first('//input').value).to eq('')
end

it 'should raise if the text field is readonly' do
expect { @session.first('//input[@readonly]').set('changed') }.to raise_error(Capybara::ReadOnlyElementError)
end
if ENV['CAPYBARA_THOROUGH']
it 'should raise if the text field is readonly' do
expect { @session.first('//input[@readonly]').set('changed') }.to raise_error(Capybara::ReadOnlyElementError)
end

it 'should raise if the textarea is readonly' do
expect { @session.first('//textarea[@readonly]').set('changed') }.to raise_error(Capybara::ReadOnlyElementError)
end
else
it 'should not change if the text field is readonly' do
@session.first('//input[@readonly]').set('changed')
expect(@session.first('//input[@readonly]').value).to eq 'should not change'
end

it 'should raise if the textarea is readonly' do
expect { @session.first('//textarea[@readonly]').set('changed') }.to raise_error(Capybara::ReadOnlyElementError)
it 'should not change if the textarea is readonly' do
@session.first('//textarea[@readonly]').set('changed')
expect(@session.first('//textarea[@readonly]').value).to eq 'textarea should not change'
end
end

it 'should use global default options' do
Expand All @@ -125,7 +137,7 @@
expect(element.base).to have_received(:set).with('gorilla', clear: :backspace)
end

context 'with a contenteditable element', requires: [:js] do
context 'with a contenteditable element', requires: [:js], focus_: true do
it 'should allow me to change the contents' do
@session.visit('/with_js')
@session.find(:css, '#existing_content_editable').set('WYSIWYG')
Expand Down Expand Up @@ -155,7 +167,7 @@
end
end

describe '#disabled?' do
describe '#disabled?', :focus_ do
it 'should extract disabled node' do
@session.visit('/form')
expect(@session.find('//input[@id="customer_name"]')).to be_disabled
Expand Down

0 comments on commit e39c65e

Please sign in to comment.