From 9f516cfd7ae049aa0c0e2706c4eb66031708c8e0 Mon Sep 17 00:00:00 2001 From: Jonas Nicklas Date: Fri, 8 Mar 2013 14:18:56 +0100 Subject: [PATCH] Add support for :disabled as a filter, instead of being harcoded, closes #982 --- lib/capybara/query.rb | 8 +++-- lib/capybara/selector.rb | 33 +++++++++++++++++-- .../spec/session/click_link_or_button_spec.rb | 30 +++++++++++++++++ lib/capybara/spec/session/find_field_spec.rb | 18 ++++++++++ lib/capybara/spec/views/with_html.erb | 1 + xpath | 2 +- 6 files changed, 86 insertions(+), 6 deletions(-) diff --git a/lib/capybara/query.rb b/lib/capybara/query.rb index 87bf21d0..f91fd699 100644 --- a/lib/capybara/query.rb +++ b/lib/capybara/query.rb @@ -45,8 +45,12 @@ module Capybara when :visible then return false unless node.visible? when :hidden then return false if node.visible? end - selector.custom_filters.each do |name, block| - return false if options.has_key?(name) and not block.call(node, options[name]) + selector.custom_filters.each do |name, filter| + if options.has_key?(name) + return false unless filter.matches?(node, options[name]) + elsif filter.default? + return false unless filter.matches?(node, filter.default) + end end true end diff --git a/lib/capybara/selector.rb b/lib/capybara/selector.rb index eca56a04..a1b25722 100644 --- a/lib/capybara/selector.rb +++ b/lib/capybara/selector.rb @@ -1,7 +1,26 @@ module Capybara class Selector - attr_reader :name, :custom_filters, :format + class Filter + def initialize(name, block, options={}) + @name = name + @block = block + @options = options + end + def default? + @options.has_key?(:default) + end + + def default + @options[:default] + end + + def matches?(node, value) + @block.call(node, value) + end + end + + attr_reader :name, :custom_filters, :format class << self def all @@ -61,8 +80,8 @@ module Capybara @match and @match.call(locator) end - def filter(name, &block) - @custom_filters[name] = block + def filter(name, options={}, &block) + @custom_filters[name] = Filter.new(name, block, options) end end end @@ -83,6 +102,7 @@ Capybara.add_selector(:field) do xpath { |locator| XPath::HTML.field(locator) } filter(:checked) { |node, value| not(value ^ node.checked?) } filter(:unchecked) { |node, value| (value ^ node.checked?) } + filter(:disabled, :default => false) { |node, value| not(value ^ node.disabled?) } filter(:with) { |node, with| node.value == with } filter(:type) do |node, type| if ['textarea', 'select'].include?(type) @@ -100,6 +120,7 @@ end Capybara.add_selector(:link_or_button) do label "link or button" xpath { |locator| XPath::HTML.link_or_button(locator) } + filter(:disabled, :default => false) { |node, value| node.tag_name == "a" or not(value ^ node.disabled?) } end Capybara.add_selector(:link) do @@ -111,11 +132,13 @@ end Capybara.add_selector(:button) do xpath { |locator| XPath::HTML.button(locator) } + filter(:disabled, :default => false) { |node, value| not(value ^ node.disabled?) } end Capybara.add_selector(:fillable_field) do label "field" xpath { |locator| XPath::HTML.fillable_field(locator) } + filter(:disabled, :default => false) { |node, value| not(value ^ node.disabled?) } end Capybara.add_selector(:radio_button) do @@ -123,12 +146,14 @@ Capybara.add_selector(:radio_button) do xpath { |locator| XPath::HTML.radio_button(locator) } filter(:checked) { |node, value| not(value ^ node.checked?) } filter(:unchecked) { |node, value| (value ^ node.checked?) } + filter(:disabled, :default => false) { |node, value| not(value ^ node.disabled?) } end Capybara.add_selector(:checkbox) do xpath { |locator| XPath::HTML.checkbox(locator) } filter(:checked) { |node, value| not(value ^ node.checked?) } filter(:unchecked) { |node, value| (value ^ node.checked?) } + filter(:disabled, :default => false) { |node, value| not(value ^ node.disabled?) } end Capybara.add_selector(:select) do @@ -143,6 +168,7 @@ Capybara.add_selector(:select) do actual = node.all(:xpath, './/option').select { |option| option.selected? }.map { |option| option.text } [selected].flatten.sort == actual.sort end + filter(:disabled, :default => false) { |node, value| not(value ^ node.disabled?) } end Capybara.add_selector(:option) do @@ -152,6 +178,7 @@ end Capybara.add_selector(:file_field) do label "file field" xpath { |locator| XPath::HTML.file_field(locator) } + filter(:disabled, :default => false) { |node, value| not(value ^ node.disabled?) } end Capybara.add_selector(:table) do diff --git a/lib/capybara/spec/session/click_link_or_button_spec.rb b/lib/capybara/spec/session/click_link_or_button_spec.rb index 2906ba91..b6c4be6b 100644 --- a/lib/capybara/spec/session/click_link_or_button_spec.rb +++ b/lib/capybara/spec/session/click_link_or_button_spec.rb @@ -79,4 +79,34 @@ Capybara::SpecHelper.spec '#click_link_or_button' do end.to raise_error(Capybara::ElementNotFound, msg) end end + + context "with :disabled option" do + it "ignores disabled buttons when false" do + @session.visit('/form') + expect do + @session.click_link_or_button('Disabled button', :disabled => false) + end.to raise_error(Capybara::ElementNotFound) + end + + it "ignores disabled buttons by default" do + @session.visit('/form') + expect do + @session.click_link_or_button('Disabled button') + end.to raise_error(Capybara::ElementNotFound) + end + + it "happily clicks on links which incorrectly have the disabled attribute" do + @session.visit('/with_html') + @session.click_link_or_button('Disabled link') + @session.should have_content("Bar") + end + + it "does nothing when button is disabled" do + @session.visit('/form') + expect do + @session.click_link_or_button('Disabled button', :disabled => false) + end.to raise_error(Capybara::ElementNotFound) + end + + end end diff --git a/lib/capybara/spec/session/find_field_spec.rb b/lib/capybara/spec/session/find_field_spec.rb index 4a725418..93fbe42e 100644 --- a/lib/capybara/spec/session/find_field_spec.rb +++ b/lib/capybara/spec/session/find_field_spec.rb @@ -37,4 +37,22 @@ Capybara::SpecHelper.spec '#find_field' do end.to raise_error(Capybara::ElementNotFound) end end + + context "with :disabled option" do + it "should find disabled fields when true" do + @session.find_field("Disabled Checkbox", :disabled => true)[:name].should == "form[disabled_checkbox]" + end + + it "should not find disabled fields when false" do + expect do + @session.find_field("Disabled Checkbox", :disabled => false) + end.to raise_error(Capybara::ElementNotFound) + end + + it "should not find disabled fields by default" do + expect do + @session.find_field("Disabled Checkbox") + end.to raise_error(Capybara::ElementNotFound) + end + end end diff --git a/lib/capybara/spec/views/with_html.erb b/lib/capybara/spec/views/with_html.erb index ff023551..89a57f94 100644 --- a/lib/capybara/spec/views/with_html.erb +++ b/lib/capybara/spec/views/with_html.erb @@ -49,6 +49,7 @@ banana very fine image fine image + Disabled link Naked Query String <% if params[:query_string] %> diff --git a/xpath b/xpath index 4c7c3351..6429e5a8 160000 --- a/xpath +++ b/xpath @@ -1 +1 @@ -Subproject commit 4c7c3351f970f14635e670239e11f81fffb07717 +Subproject commit 6429e5a84a7893d514be1cb04d3ff250b74ab1f8