/usr/lib/ruby/vendor_ruby/capybara/selector/selector.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 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 | # frozen_string_literal: true
require 'capybara/selector/filter_set'
require 'capybara/selector/css'
require 'xpath'
#Patch XPath to allow a nil condition in where
module XPath
class Renderer
def where(on, condition)
condition = condition.to_s
if !condition.empty?
"#{on}[#{condition}]"
else
"#{on}"
end
end
end
end
module Capybara
class Selector
attr_reader :name, :format, :expression_filters
class << self
def all
@selectors ||= {}
end
def add(name, &block)
all[name.to_sym] = Capybara::Selector.new(name.to_sym, &block)
end
def update(name, &block)
all[name.to_sym].instance_eval(&block)
end
def remove(name)
all.delete(name.to_sym)
end
end
def initialize(name, &block)
@name = name
@filter_set = FilterSet.add(name){}
@match = nil
@label = nil
@failure_message = nil
@description = nil
@format = nil
@expression = nil
@expression_filters = []
@default_visibility = nil
instance_eval(&block)
end
def custom_filters
@filter_set.filters
end
##
#
# Define a selector by an xpath expression
#
# @overload xpath(*expression_filters, &block)
# @param [Array<Symbol>] expression_filters ([]) Names of filters that can be implemented via this expression
# @yield [locator, options] The block to use to generate the XPath expression
# @yieldparam [String] locator The locator string passed to the query
# @yieldparam [Hash] options The options hash passed to the query
# @yieldreturn [#to_xpath, #to_s] An object that can produce an xpath expression
#
# @overload xpath()
# @return [#call] The block that will be called to generate the XPath expression
#
def xpath(*expression_filters, &block)
@format, @expression_filters, @expression = :xpath, expression_filters.flatten, block if block
format == :xpath ? @expression : nil
end
##
#
# Define a selector by a CSS selector
#
# @overload css(*expression_filters, &block)
# @param [Array<Symbol>] expression_filters ([]) Names of filters that can be implemented via this CSS selector
# @yield [locator, options] The block to use to generate the CSS selector
# @yieldparam [String] locator The locator string passed to the query
# @yieldparam [Hash] options The options hash passed to the query
# @yieldreturn [#to_s] An object that can produce a CSS selector
#
# @overload css()
# @return [#call] The block that will be called to generate the CSS selector
#
def css(*expression_filters, &block)
@format, @expression_filters, @expression = :css, expression_filters.flatten, block if block
format == :css ? @expression : nil
end
##
#
# Automatic selector detection
#
# @yield [locator] This block takes the passed in locator string and returns whether or not it matches the selector
# @yieldparam [String], locator The locator string used to determin if it matches the selector
# @yieldreturn [Boolean] Whether this selector matches the locator string
# @return [#call] The block that will be used to detect selector match
#
def match(&block)
@match = block if block
@match
end
##
#
# Set/get a descriptive label for the selector
#
# @overload label(label)
# @param [String] label A descriptive label for this selector - used in error messages
# @overload label()
# @return [String] The currently set label
#
def label(label=nil)
@label = label if label
@label
end
##
#
# Description of the selector
#
# @param [Hash] options The options of the query used to generate the description
# @return [String] Description of the selector when used with the options passed
#
def description(options={})
@filter_set.description(options)
end
def call(locator, options={})
if format
# @expression.call(locator, options.select {|k,v| @expression_filters.include?(k)})
@expression.call(locator, options)
else
warn "Selector has no format"
end
end
##
#
# Should this selector be used for the passed in locator
#
# This is used by the automatic selector selection mechanism when no selector type is passed to a selector query
#
# @param [String] locator The locator passed to the query
# @return [Boolean] Whether or not to use this selector
#
def match?(locator)
@match and @match.call(locator)
end
##
#
# Define a non-expression filter for use with this selector
#
# @overload filter(name, *types, options={}, &block)
# @param [Symbol] name The filter name
# @param [Array<Symbol>] types The types of the filter - currently valid types are [:boolean]
# @param [Hash] options ({}) Options of the filter
# @option options [Array<>] :valid_values Valid values for this filter
# @option options :default The default value of the filter (if any)
# @option options :skip_if Value of the filter that will cause it to be skipped
#
def filter(name, *types_and_options, &block)
options = types_and_options.last.is_a?(Hash) ? types_and_options.pop.dup : {}
types_and_options.each { |k| options[k] = true}
custom_filters[name] = Filter.new(name, block, options)
end
def filter_set(name, filters_to_use = nil)
f_set = FilterSet.all[name]
f_set.filters.each do | name, filter |
custom_filters[name] = filter if filters_to_use.nil? || filters_to_use.include?(name)
end
f_set.descriptions.each { |desc| @filter_set.describe &desc }
end
def describe &block
@filter_set.describe &block
end
##
#
# Set the default visibility mode that shouble be used if no visibile option is passed when using the selector.
# If not specified will default to the behavior indicated by Capybara.ignore_hidden_elements
#
# @param [Symbol] default_visibility Only find elements with the specified visibility:
# * :all - finds visible and invisible elements.
# * :hidden - only finds invisible elements.
# * :visible - only finds visible elements.
def visible(default_visibility)
@default_visibility = default_visibility
end
def default_visibility
if @default_visibility.nil?
Capybara.ignore_hidden_elements
else
@default_visibility
end
end
private
def locate_field(xpath, locator, options={})
locate_xpath = xpath #need to save original xpath for the label wrap
if locator
locator = locator.to_s
attr_matchers = XPath.attr(:id).equals(locator) |
XPath.attr(:name).equals(locator) |
XPath.attr(:placeholder).equals(locator) |
XPath.attr(:id).equals(XPath.anywhere(:label)[XPath.string.n.is(locator)].attr(:for))
attr_matchers |= XPath.attr(:'aria-label').is(locator) if Capybara.enable_aria_label
locate_xpath = locate_xpath[attr_matchers]
locate_xpath += XPath.descendant(:label)[XPath.string.n.is(locator)].descendant(xpath)
end
locate_xpath = [:name, :placeholder].inject(locate_xpath) { |memo, ef| memo[find_by_attr(ef, options[ef])] }
locate_xpath
end
def find_by_attr(attribute, value)
finder_name = "find_by_#{attribute.to_s}_attr"
if respond_to?(finder_name, true)
send(finder_name, value)
else
value ? XPath.attr(attribute).equals(value) : nil
end
end
def find_by_class_attr(classes)
if classes
Array(classes).map do |klass|
"contains(concat(' ',normalize-space(@class),' '),' #{klass} ')"
end.join(" and ").to_sym
else
nil
end
end
end
end
|