Optimize attribute checking for :element selector
This commit is contained in:
parent
318f595ca4
commit
907b9e269f
|
@ -97,7 +97,9 @@ Capybara.add_selector(:link) do
|
|||
when true
|
||||
XPath.attr(:href)
|
||||
when Regexp
|
||||
nil # needs to be handled in filter
|
||||
regexp_to_substrings(href).map do |str|
|
||||
XPath.attr(:href).contains(str)
|
||||
end.reduce(&:&)
|
||||
else
|
||||
XPath.attr(:href) == href.to_s
|
||||
end
|
||||
|
@ -135,13 +137,19 @@ Capybara.add_selector(:link) do
|
|||
|
||||
describe_expression_filters do |**options|
|
||||
desc = +''
|
||||
desc << " with href #{options[:href].inspect}" if options[:href] && !options[:href].is_a?(Regexp)
|
||||
if (href = options[:href])
|
||||
if !href.is_a?(Regexp)
|
||||
desc << " with href #{href.inspect}"
|
||||
elsif regexp_to_substrings(href).any?
|
||||
desc << " with href matching #{href.inspect}"
|
||||
end
|
||||
end
|
||||
desc << ' with no href attribute' if options.fetch(:href, true).nil?
|
||||
desc
|
||||
end
|
||||
|
||||
describe_node_filters do |href: nil, **|
|
||||
" with href matching #{href.inspect}" if href.is_a? Regexp
|
||||
" with href matching #{href.inspect}" if href.is_a?(Regexp) && regexp_to_substrings(href).empty?
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -477,7 +485,9 @@ Capybara.add_selector(:element) do
|
|||
expression_filter(:attributes, matcher: /.+/) do |xpath, name, val|
|
||||
case val
|
||||
when Regexp
|
||||
xpath
|
||||
regexp_to_substrings(val).inject(xpath) do |xp, str|
|
||||
xp[XPath.attr(name).contains(str)]
|
||||
end
|
||||
when true
|
||||
xpath[XPath.attr(name)]
|
||||
when false
|
||||
|
|
|
@ -444,6 +444,25 @@ module Capybara
|
|||
def find_by_class_attr(classes)
|
||||
Array(classes).map { |klass| XPath.attr(:class).contains_word(klass) }.reduce(:&)
|
||||
end
|
||||
|
||||
def regexp_to_substrings(regexp)
|
||||
return [] unless regexp.options.zero?
|
||||
|
||||
regexp.source.match(CONVERTIBLE_REGEXP) do |match|
|
||||
match.captures.reject(&:empty?)
|
||||
end || []
|
||||
end
|
||||
|
||||
CONVERTIBLE_REGEXP = /
|
||||
\A
|
||||
\^? # start
|
||||
([^\[\]\\^$.|?*+()]*) # leading literal characters
|
||||
[^|]*? # do not try to convert expressions with alternates
|
||||
(?<!\\) # skip metacharacters - ie has preceding slash
|
||||
([^\[\]\\^$.|?*+()]*) # trailing literal characters
|
||||
\$? # end
|
||||
\z
|
||||
/x
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -34,6 +34,6 @@ Capybara::SpecHelper.spec '#to_capybara_node' do
|
|||
end.to raise_error(/^expected to find css "#second" within #<Capybara::Node::Element/)
|
||||
expect do
|
||||
expect(para).to have_link(href: %r{/without_simple_html})
|
||||
end.to raise_error(%r{^expected to find visible link nil with href matching /\\/without_simple_html/ within #<Capybara::Node::Element})
|
||||
end.to raise_error(%r{^expected to find link nil with href matching /\\/without_simple_html/ within #<Capybara::Node::Element})
|
||||
end
|
||||
end
|
||||
|
|
|
@ -257,6 +257,16 @@ RSpec.describe Capybara do
|
|||
expect(string.find(:element, 'input', type: 'submit').value).to eq 'click me'
|
||||
end
|
||||
|
||||
it 'supports regexp matching' do
|
||||
expect(string.find(:element, 'input', type: /sub/).value).to eq 'click me'
|
||||
expect(string.find(:element, 'input', title: /sub\w.*button/).value).to eq 'click me'
|
||||
expect(string.find(:element, 'input', title: /sub.* b.*ton/).value).to eq 'click me'
|
||||
expect(string.find(:element, 'input', title: /sub.*mit.*/).value).to eq 'click me'
|
||||
expect(string.find(:element, 'input', title: /^submit button$/).value).to eq 'click me'
|
||||
expect(string.find(:element, 'input', title: /^(?:submit|other) button$/).value).to eq 'click me'
|
||||
expect(string.find(:element, 'input', title: /SuBmIt/i).value).to eq 'click me'
|
||||
end
|
||||
|
||||
it 'still works with system keys' do
|
||||
expect { string.all(:element, 'input', type: 'submit', count: 1) }.not_to raise_error
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue