automatically click label if checkbox is hidden

This commit is contained in:
Thomas Walpole 2016-04-21 14:25:14 -07:00
parent 3f515ff826
commit 37d7df5f1c
7 changed files with 135 additions and 2 deletions

View File

@ -114,7 +114,17 @@ module Capybara
#
def check(locator, options={})
locator, options = nil, locator if locator.is_a? Hash
find(:checkbox, locator, options).set(true)
begin
find(:checkbox, locator, options).set(true)
rescue Capybara::ElementNotFound => e
begin
cbox = find(:checkbox, locator, options.merge({wait: 0, visible: :all}))
label = find(:label, for: cbox, wait: 0)
label.click if !cbox.checked?
rescue
raise e
end
end
end
##
@ -133,7 +143,17 @@ module Capybara
#
def uncheck(locator, options={})
locator, options = nil, locator if locator.is_a? Hash
find(:checkbox, locator, options).set(false)
begin
find(:checkbox, locator, options).set(false)
rescue Capybara::ElementNotFound => e
begin
cbox = find(:checkbox, locator, options.merge({wait: 0, visible: :all}))
label = find(:label, for: cbox, wait: 0)
label.click if cbox.checked?
rescue
raise e
end
end
end
##

View File

@ -60,6 +60,16 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
((tag_name == 'button') and type.nil? or type == "submit")
associated_form = form
Capybara::RackTest::Form.new(driver, associated_form).submit(self) if associated_form
elsif (tag_name == 'label')
labelled_control = if native[:for]
find_xpath("//input[@id='#{native[:for]}']").first
else
find_xpath(".//input").first
end
if labelled_control && (labelled_control.checkbox? || labelled_control.radio?)
labelled_control.set(!labelled_control.checked?)
end
end
end
@ -183,6 +193,8 @@ private
self[attribute] && !self[attribute].empty?
end
protected
def checkbox?
input_field? && type == 'checkbox'
end

View File

@ -368,6 +368,11 @@ Capybara.add_selector(:label) do
node[:for] == field_or_value.to_s
end
end
describe do |options|
desc = String.new
desc << " for #{options[:for]}" if options[:for]
end
end
Capybara.add_selector(:table) do

View File

@ -111,4 +111,31 @@ Capybara::SpecHelper.spec "#check" do
end.to raise_error(Capybara::ElementNotFound)
end
end
context "when checkbox hidden", hidden: true do
it "should check via clicking the label with :for attribute if possible" do
expect(@session.find(:checkbox, 'form_cars_tesla', unchecked: true, visible: :hidden)).to be
@session.check('form_cars_tesla')
@session.click_button('awesome')
expect(extract_results(@session)['cars']).to include('tesla')
end
it "should check via clicking the wrapping label if possible" do
expect(@session.find(:checkbox, 'form_cars_mclaren', unchecked: true, visible: :hidden)).to be
@session.check('form_cars_mclaren')
@session.click_button('awesome')
expect(extract_results(@session)['cars']).to include('mclaren')
end
it "should not click the label if unneeded" do
expect(@session.find(:checkbox, 'form_cars_jaguar', checked: true, visible: :hidden)).to be
@session.check('form_cars_jaguar')
@session.click_button('awesome')
expect(extract_results(@session)['cars']).to include('jaguar')
end
it "should raise original error when no label available" do
expect { @session.check('form_cars_ariel') }.to raise_error(Capybara::ElementNotFound, 'Unable to find checkbox "form_cars_ariel"')
end
end
end

View File

@ -38,4 +38,31 @@ Capybara::SpecHelper.spec "#uncheck" do
end.to raise_error(Capybara::ElementNotFound)
end
end
context "when checkbox hidden", hidden: true do
it "should uncheck via clicking the label with :for attribute if possible" do
expect(@session.find(:checkbox, 'form_cars_jaguar', checked: true, visible: :hidden)).to be
@session.uncheck('form_cars_jaguar')
@session.click_button('awesome')
expect(extract_results(@session)['cars']).not_to include('jaguar')
end
it "should uncheck via clicking the wrapping label if possible" do
expect(@session.find(:checkbox, 'form_cars_koenigsegg', checked: true, visible: :hidden)).to be
@session.uncheck('form_cars_koenigsegg')
@session.click_button('awesome')
expect(extract_results(@session)['cars']).not_to include('koenigsegg')
end
it "should not click the label if unneeded" do
expect(@session.find(:checkbox, 'form_cars_tesla', unchecked: true, visible: :hidden)).to be
@session.uncheck('form_cars_tesla')
@session.click_button('awesome')
expect(extract_results(@session)['cars']).not_to include('tesla')
end
it "should raise original error when no label available" do
expect { @session.uncheck('form_cars_ariel') }.to raise_error(Capybara::ElementNotFound, 'Unable to find checkbox "form_cars_ariel"')
end
end
end

View File

@ -167,6 +167,24 @@ New line after and before textarea tag
<label for="form_pets_hamster">Hamster</label>
</p>
<p>
<input type="checkbox" value="jaguar" name="form[cars][]" id="form_cars_jaguar" checked="checked" style="display: none"/>
<label for="form_cars_jaguar">Jaguar</label>
<input type="checkbox" value="tesla" name="form[cars][]" id="form_cars_tesla" style="display: none"/>
<label for="form_cars_tesla">Tesla</label>
<input type="checkbox" value="ferrari" name="form[cars][]" id="form_cars_ferrari" checked="checked" style="display: none"/>
<label for="form_cars_ferrari">Ferrari</label>
<input type="checkbox" value="ariel" name="form[cars][]" id="form_cars_ariel" style="display: none"/>
<label>
McLaren
<input type="checkbox" value="mclaren" name="form[cars][]" id="form_cars_mclaren" style="display: none"/>
</label>
<label>
Koenigsegg
<input type="checkbox" value="koenigsegg" name="form[cars][]" id="form_cars_koenigsegg" checked="checked" style="display: none"/>
</label>
</p>
<p>
<input type="checkbox" name="form[valueless_checkbox]" id="valueless_checkbox" checked="checked"/>
<label for="valueless_checkbox">Valueless Checkbox</label>

View File

@ -80,6 +80,30 @@ RSpec.describe Capybara::Session do
end
end
end
describe "#click" do
context "on a label" do
it "should toggle the associated checkbox" do
@session.visit("/form")
expect(@session).to have_unchecked_field('form_pets_cat')
@session.find(:label, 'Cat').click
expect(@session).to have_checked_field('form_pets_cat')
@session.find(:label, 'Cat').click
expect(@session).to have_unchecked_field('form_pets_cat')
@session.find(:label, 'McLaren').click
expect(@session).to have_checked_field('form_cars_mclaren', visible: :hidden)
end
it "should toggle the associated radio" do
@session.visit("/form")
expect(@session).to have_unchecked_field('gender_male')
@session.find(:label, 'Male').click
expect(@session).to have_checked_field('gender_male')
@session.find(:label, 'Female').click
expect(@session).to have_unchecked_field('gender_male')
end
end
end
end
end