Support negated classes in the :class filter option

This commit is contained in:
Thomas Walpole 2018-05-29 16:46:04 -07:00
parent cc9629645d
commit 6995982268
3 changed files with 26 additions and 5 deletions

View File

@ -202,7 +202,11 @@ module Capybara
XPath.attr(:class)[options[:class]]
else
Array(options[:class]).map do |klass|
XPath.attr(:class).contains_word(klass)
if klass.start_with?('!')
!XPath.attr(:class).contains_word(klass.slice(1))
else
XPath.attr(:class).contains_word(klass)
end
end.reduce(:&)
end
expr = "(#{expr})[#{class_xpath}]"
@ -224,12 +228,18 @@ module Capybara
css_selectors = expr.split(',').map(&:rstrip)
expr = css_selectors.map do |sel|
sel += "##{Capybara::Selector::CSS.escape(options[:id])}" if process_id
sel += Array(options[:class]).map { |k| ".#{Capybara::Selector::CSS.escape(k)}" }.join if process_class
sel += css_from_classes(Array(options[:class])) if process_class
sel
end.join(", ")
expr
end
def css_from_classes(classes)
classes = classes.group_by { |c| c.start_with? '!' }
(classes[false].to_a.map { |c| ".#{Capybara::Selector::CSS.escape(c)}" } +
classes[true].to_a.map { |c| ":not(.#{Capybara::Selector::CSS.escape(c.slice(1))})" }).join
end
def apply_expression_filters(expr)
unapplied_options = options.keys - valid_keys
expression_filters.inject(expr) do |memo, (name, ef)|

View File

@ -1,5 +1,7 @@
# frozen_string_literal: true
# rubocop:disable Style/AsciiComments
require 'capybara/selector/filter_set'
require 'capybara/selector/css'
@ -426,3 +428,5 @@ module Capybara
end
end
end
# rubocop:enable Style/AsciiComments

View File

@ -16,8 +16,8 @@ RSpec.describe Capybara do
<h1 class="a">Totally awesome</h1>
<p>Yes it is</p>
</div>
<p class="b">Some Content</p>
<p class="b"></p>
<p class="b c">Some Content</p>
<p class="b d"></p>
</div>
<div id="#special">
</div>
@ -64,7 +64,7 @@ RSpec.describe Capybara do
it "supports `filter` as an alias for `node_filter`" do
expect do
Capybara.add_selector :filter_alias_selector do
css { |_unused| "div"}
css { |_unused| "div" }
filter(:something) { |_node, _value| true }
end
end.not_to raise_error
@ -155,6 +155,13 @@ RSpec.describe Capybara do
expect(string.all(:custom_css_selector, "h1, div", class: 'a').size).to eq 2
end
it "handles negated classes" do
expect(string.all(:custom_css_selector, "div, p", class: ['b', '!c']).size).to eq 2
expect(string.all(:custom_css_selector, "div, p", class: ['!c', '!d', 'b']).size).to eq 1
expect(string.all(:custom_xpath_selector, XPath.descendant(:div, :p), class: ['b', '!c']).size).to eq 2
expect(string.all(:custom_xpath_selector, XPath.descendant(:div, :p), class: ['!c', '!d', 'b']).size).to eq 1
end
it "works with 'special' characters" do
expect(string.find(:custom_css_selector, "input", class: ".special")[:id]).to eq 'file'
expect(string.find(:custom_css_selector, "input", class: "2checkbox")[:id]).to eq '2checkbox'