Skip to content

Commit

Permalink
Implement multiple expression types for field selector type
Browse files Browse the repository at this point in the history
  • Loading branch information
twalpole committed Apr 23, 2019
1 parent dcd7fab commit 1ac0099
Showing 1 changed file with 75 additions and 8 deletions.
83 changes: 75 additions & 8 deletions lib/capybara/selector.rb
Expand Up @@ -48,7 +48,7 @@
locator_filter { |node, id| id.is_a?(Regexp) ? id.match?(node[:id]) : true }
end

Capybara.add_selector(:field, locator_type: [String, Symbol]) do
Capybara.add_selector(:field, locator_type: [String, Symbol], supports_exact: true) do
visible { |options| :hidden if options[:type].to_s == 'hidden' }

xpath do |locator, **options|
Expand All @@ -58,18 +58,85 @@
locate_field(xpath, locator, options)
end

css do |_locator, **options|
invalid_types = %w[submit image]
invalid_types << 'hidden' unless options[:type].to_s == 'hidden'
invalid_attributes = invalid_types.map { |type| ":not([type=#{type}])" }.join
"input#{invalid_attributes}, textarea, select"
end

locator_filter(skip_if: nil, format: :css) do |node, locator, exact:, **_|
optional_checks = +''
optional_checks << "(field.getAttribute('aria-label') == locator)||" if enable_aria_label
optional_checks << "(field.getAttribute('#{test_id}') == locator)||" if test_id

match_js = <<~JS
(function(field, locator){
return (
(field.id == locator) ||
(field.name == locator) ||
(field.placeholder == locator)||
#{optional_checks}
Array.from(field.labels || []).some(function(label){
return label.innerText#{exact ? '== locator' : '.includes(locator)'};
})
);
})(this, arguments[0])
JS
node.evaluate_script(match_js, locator)
end

expression_filter(:type) do |expr, type|
type = type.to_s
if %w[textarea select].include?(type)
expr.self(type.to_sym)
case default_format
when :css
if %w[textarea select].include?(type)
::Capybara::Selector::CSS.split(expr).select do |css_fragment|
css_fragment.start_with? type
end.join(',')
else
::Capybara::Selector::CSSBuilder.new(expr).add_attribute_conditions(type: type)
end
when :xpath
if %w[textarea select].include?(type)
expr.self(type.to_sym)
else
expr[XPath.attr(:type) == type]
end
else
expr[XPath.attr(:type) == type]
raise ArgumentError, "Unknown format type: #{default_format}"
end
end

filter_set(:_field) # checked/unchecked/disabled/multiple/name/placeholder

node_filter(:readonly, :boolean) { |node, value| !(value ^ node.readonly?) }
expression_filter(:name) do |expr, val|
if default_format == :css
::Capybara::Selector::CSSBuilder.new(expr).add_attribute_conditions(name: val)
else
expr[XPath.attr(:name) == val]
end
end
expression_filter(:placeholder) do |expr, val|
if default_format == :css
::Capybara::Selector::CSSBuilder.new(expr).add_attribute_conditions(placeholder: val)
else
expr[XPath.attr(:placeholder) == val]
end
end
expression_filter(:readonly, :boolean, format: :css) do |expr, val|
::Capybara::Selector::CSS.split(expr).map do |css_fragment|
if val
"#{css_fragment}:read-only"
else
"#{css_fragment}:read-write"
end
end.join(',')
end

node_filter(:readonly, :boolean, format: :xpath) do |node, value|
!(value ^ node.readonly?)
end

node_filter(:with) do |node, with|
val = node.value
Expand Down Expand Up @@ -188,7 +255,7 @@
label 'link or button'
xpath do |locator, **options|
%i[link button].map do |selector|
expression_for(selector, locator, **options)
expression_for(selector, locator, format: :xpath, **options)
end.reduce(:union)
end

Expand Down Expand Up @@ -299,7 +366,7 @@

expression_filter(:with_options) do |expr, options|
options.inject(expr) do |xpath, option|
xpath[expression_for(:option, option)]
xpath[expression_for(:option, option, format: :xpath)]
end
end

Expand Down Expand Up @@ -352,7 +419,7 @@

expression_filter(:with_options) do |expr, options|
options.inject(expr) do |xpath, option|
xpath[XPath.attr(:list) == XPath.anywhere(:datalist)[expression_for(:datalist_option, option)].attr(:id)]
xpath[XPath.attr(:list) == XPath.anywhere(:datalist)[expression_for(:datalist_option, option, format: :xpath)].attr(:id)]
end
end

Expand Down

0 comments on commit 1ac0099

Please sign in to comment.