diff --git a/lib/capybara/selector.rb b/lib/capybara/selector.rb index c21f15d8..78c9054b 100644 --- a/lib/capybara/selector.rb +++ b/lib/capybara/selector.rb @@ -467,6 +467,10 @@ Capybara.add_selector(:element) do case val when Regexp xpath + when true + xpath[XPath.attr(name)] + when false + xpath[!XPath.attr(name)] when XPath::Expression xpath[XPath.attr(name)[val]] else @@ -478,6 +482,12 @@ Capybara.add_selector(:element) do val.is_a?(Regexp) ? node[name] =~ val : true end - describe_expression_filters + describe_expression_filters do |**options| + booleans, values = options.partition {|k,v| [true, false].include? v }.map &:to_h + desc = describe_all_expression_filters(values) + desc += booleans.map do |k, v| + v ? " with #{k} attribute" : "without #{k} attribute" + end.join + end end # rubocop:enable Metrics/BlockLength diff --git a/spec/selector_spec.rb b/spec/selector_spec.rb index 57564e2d..a6948a31 100644 --- a/spec/selector_spec.rb +++ b/spec/selector_spec.rb @@ -265,11 +265,21 @@ RSpec.describe Capybara do expect(string.find(:element, type: 'submit').value).to eq 'click me' end + it 'validates attribute presence when true' do + expect(string.find(:element, name: true)[:id]).to eq 'my_text_input' + end + + it 'validates attribute absence when false' do + expect(string.find(:element, 'option', disabled: false, selected: false).value).to eq 'a' + end + it 'includes wildcarded keys in description' do - expect { string.find(:element, 'input', not_there: 'bad', count: 1) } + expect { string.find(:element, 'input', not_there: 'bad', presence: true, absence: false, count: 1) } .to(raise_error do |e| expect(e).to be_a(Capybara::ElementNotFound) expect(e.message).to include 'not_there => bad' + expect(e.message).to include 'with presence attribute' + expect(e.message).to include 'without absence attribute' expect(e.message).not_to include 'count 1' end) end