/usr/lib/ruby/vendor_ruby/capybara/queries/selector_query.rb is in ruby-capybara 2.10.2-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | # frozen_string_literal: true
module Capybara
module Queries
class SelectorQuery < Queries::BaseQuery
attr_accessor :selector, :locator, :options, :expression, :find, :negative
VALID_KEYS = COUNT_KEYS + [:text, :id, :class, :visible, :exact, :match, :wait, :filter_set]
VALID_MATCH = [:first, :smart, :prefer_exact, :one]
def initialize(*args, &filter_block)
@options = if args.last.is_a?(Hash) then args.pop.dup else {} end
@filter_block = filter_block
if args[0].is_a?(Symbol)
@selector = Selector.all.fetch(args.shift) do |selector_type|
warn "Unknown selector type (:#{selector_type}), defaulting to :#{Capybara.default_selector} - This will raise an exception in a future version of Capybara"
nil
end
@locator = args.shift
else
@selector = Selector.all.values.find { |s| s.match?(args[0]) }
@locator = args.shift
end
@selector ||= Selector.all[Capybara.default_selector]
warn "Unused parameters passed to #{self.class.name} : #{args.to_s}" unless args.empty?
# for compatibility with Capybara 2.0
if Capybara.exact_options and @selector == Selector.all[:option]
@options[:exact] = true
end
@expression = @selector.call(@locator, @options)
warn_exact_usage
assert_valid_keys
end
def name; selector.name; end
def label; selector.label or selector.name; end
def description
@description = String.new("#{label} #{locator.inspect}")
@description << " with text #{options[:text].inspect}" if options[:text]
@description << " with id #{options[:id]}" if options[:id]
@description << " with classes #{Array(options[:class]).join(',')}]" if options[:class]
@description << selector.description(options)
@description << " that also matches the custom filter block" if @filter_block
@description
end
def matches_filters?(node)
if options[:text]
regexp = options[:text].is_a?(Regexp) ? options[:text] : Regexp.escape(options[:text].to_s)
return false if not node.text(visible).match(regexp)
end
case visible
when :visible then return false unless node.visible?
when :hidden then return false if node.visible?
end
res = query_filters.all? do |name, filter|
if options.has_key?(name)
filter.matches?(node, options[name])
elsif filter.default?
filter.matches?(node, filter.default)
else
true
end
end
res &&= @filter_block.call(node) unless @filter_block.nil?
res
end
def visible
case (vis = options.fetch(:visible){ @selector.default_visibility })
when true then :visible
when false then :all
else vis
end
end
def exact?
return false if !supports_exact?
options.fetch(:exact, Capybara.exact)
end
def match
options.fetch(:match, Capybara.match)
end
def xpath(exact=nil)
exact = self.exact? if exact.nil?
expr = if @expression.respond_to?(:to_xpath) and exact
@expression.to_xpath(:exact)
else
@expression.to_s
end
filtered_xpath(expr)
end
def css
filtered_css(@expression)
end
# @api private
def resolve_for(node, exact = nil)
node.synchronize do
children = if selector.format == :css
node.find_css(self.css)
else
node.find_xpath(self.xpath(exact))
end.map do |child|
if node.is_a?(Capybara::Node::Base)
Capybara::Node::Element.new(node.session, child, node, self)
else
Capybara::Node::Simple.new(child)
end
end
Capybara::Result.new(children, self)
end
end
# @api private
def supports_exact?
@expression.respond_to? :to_xpath
end
private
def valid_keys
VALID_KEYS + custom_keys
end
def query_filters
if options.has_key?(:filter_set)
Capybara::Selector::FilterSet.all[options[:filter_set]].filters
else
@selector.custom_filters
end
end
def custom_keys
@custom_keys ||= query_filters.keys + @selector.expression_filters
end
def assert_valid_keys
super
unless VALID_MATCH.include?(match)
raise ArgumentError, "invalid option #{match.inspect} for :match, should be one of #{VALID_MATCH.map(&:inspect).join(", ")}"
end
end
def filtered_xpath(expr)
if options.has_key?(:id) || options.has_key?(:class)
expr = "(#{expr})"
expr = "#{expr}[#{XPath.attr(:id) == options[:id]}]" if options.has_key?(:id) && !custom_keys.include?(:id)
if options.has_key?(:class) && !custom_keys.include?(:class)
class_xpath = Array(options[:class]).map do |klass|
"contains(concat(' ',normalize-space(@class),' '),' #{klass} ')"
end.join(" and ")
expr = "#{expr}[#{class_xpath}]"
end
end
expr
end
def filtered_css(expr)
if options.has_key?(:id) || options.has_key?(:class)
css_selectors = expr.split(',').map(&:rstrip)
expr = css_selectors.map do |sel|
sel += "##{Capybara::Selector::CSS.escape(options[:id])}" if options.has_key?(:id) && !custom_keys.include?(:id)
sel += Array(options[:class]).map { |k| ".#{Capybara::Selector::CSS.escape(k)}"}.join if options.has_key?(:class) && !custom_keys.include?(:class)
sel
end.join(", ")
end
expr
end
def warn_exact_usage
if options.has_key?(:exact) && !supports_exact?
warn "The :exact option only has an effect on queries using the XPath#is method. Using it with the query \"#{expression.to_s}\" has no effect."
end
end
end
end
end
|