Class: WatirNokogiri::ElementLocator
- Inherits:
-
Object
- Object
- WatirNokogiri::ElementLocator
- Includes:
- Exception
- Defined in:
- lib/watir-nokogiri/locators/element_locator.rb
Direct Known Subclasses
ButtonLocator, ChildCellLocator, ChildRowLocator, TextAreaLocator, TextFieldLocator
Constant Summary collapse
- VALID_WHATS =
[String, Regexp]
Instance Method Summary collapse
- #assert_valid_as_attribute(attribute) ⇒ Object
- #attribute_expression(selectors) ⇒ Object
- #build_nokogiri_selector(selectors) ⇒ Object
- #build_xpath(selectors) ⇒ Object
- #can_be_combined_with_css?(selector) ⇒ Boolean
- #can_be_combined_with_xpath?(selector) ⇒ Boolean
- #check_type(how, what) ⇒ Object
- #delete_regexps_from(selector) ⇒ Object
- #equal_pair(key, value) ⇒ Object
- #fetch_value(element, how) ⇒ Object
- #find_by_regexp_selector(selector, method = :find) ⇒ Object
- #given_css(selector) ⇒ Object
- #given_xpath(selector) ⇒ Object
-
#initialize(nokogiri, selector, valid_attributes) ⇒ ElementLocator
constructor
A new instance of ElementLocator.
- #label_from_text(label_exp) ⇒ Object
- #lhs_for(key) ⇒ Object
- #locate ⇒ Object
- #locate_all ⇒ Object
- #matches_selector?(element, selector) ⇒ Boolean
- #normalize_selector(how, what) ⇒ Object
- #normalized_selector ⇒ Object
- #should_use_label_element? ⇒ Boolean
- #tag_name_matches?(element_tag_name, tag_name) ⇒ Boolean
- #valid_attribute?(attribute) ⇒ Boolean
- #validate_element(element) ⇒ Object
Constructor Details
#initialize(nokogiri, selector, valid_attributes) ⇒ ElementLocator
Returns a new instance of ElementLocator.
6 7 8 9 10 |
# File 'lib/watir-nokogiri/locators/element_locator.rb', line 6 def initialize(nokogiri, selector, valid_attributes) @nokogiri = nokogiri @selector = selector.dup @valid_attributes = valid_attributes end |
Instance Method Details
#assert_valid_as_attribute(attribute) ⇒ Object
83 84 85 86 87 |
# File 'lib/watir-nokogiri/locators/element_locator.rb', line 83 def assert_valid_as_attribute(attribute) unless valid_attribute? attribute or attribute.to_s =~ /^data_.+$/ raise MissingWayOfFindingObjectException, "invalid attribute: #{attribute.inspect}" end end |
#attribute_expression(selectors) ⇒ Object
241 242 243 244 245 246 247 248 249 |
# File 'lib/watir-nokogiri/locators/element_locator.rb', line 241 def attribute_expression(selectors) selectors.map do |key, val| if val.kind_of?(Array) "(" + val.map { |v| equal_pair(key, v) }.join(" or ") + ")" else equal_pair(key, val) end end.join(" and ") end |
#build_nokogiri_selector(selectors) ⇒ Object
215 216 217 218 219 |
# File 'lib/watir-nokogiri/locators/element_locator.rb', line 215 def build_nokogiri_selector(selectors) unless selectors.values.any? { |e| e.kind_of? Regexp } build_xpath(selectors) end end |
#build_xpath(selectors) ⇒ Object
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |
# File 'lib/watir-nokogiri/locators/element_locator.rb', line 221 def build_xpath(selectors) xpath = ".//" xpath << (selectors.delete(:tag_name) || '*').to_s idx = selectors.delete :index # the remaining entries should be attributes unless selectors.empty? xpath << "[" << attribute_expression(selectors) << "]" end if idx xpath << "[#{idx + 1}]" end p :xpath => xpath, :selectors => selectors if $DEBUG [:xpath, xpath] end |
#can_be_combined_with_css?(selector) ⇒ Boolean
203 204 205 206 207 208 209 210 211 212 213 |
# File 'lib/watir-nokogiri/locators/element_locator.rb', line 203 def can_be_combined_with_css?(selector) # ouch - is this worth it? keys = selector.keys return true if keys == [:tag_name] if selector[:tag_name] == "input" return keys == [:tag_name, :type] || keys == [:type, :tag_name] end false end |
#can_be_combined_with_xpath?(selector) ⇒ Boolean
181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/watir-nokogiri/locators/element_locator.rb', line 181 def can_be_combined_with_xpath?(selector) # ouch - is this worth it? keys = selector.keys return true if keys == [:tag_name] if selector[:tag_name] == "input" return keys == [:tag_name, :type] || keys == [:type, :tag_name] end false end |
#check_type(how, what) ⇒ Object
158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/watir-nokogiri/locators/element_locator.rb', line 158 def check_type(how, what) case how when :index unless what.kind_of?(Fixnum) raise TypeError, "expected Fixnum, got #{what.inspect}:#{what.class}" end else unless VALID_WHATS.any? { |t| what.kind_of? t } raise TypeError, "expected one of #{VALID_WHATS.inspect}, got #{what.inspect}:#{what.class}" end end end |
#delete_regexps_from(selector) ⇒ Object
71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/watir-nokogiri/locators/element_locator.rb', line 71 def delete_regexps_from(selector) rx_selector = {} selector.dup.each do |how, what| next unless what.kind_of?(Regexp) rx_selector[how] = what selector.delete how end rx_selector end |
#equal_pair(key, value) ⇒ Object
251 252 253 254 255 256 257 258 259 260 261 262 |
# File 'lib/watir-nokogiri/locators/element_locator.rb', line 251 def equal_pair(key, value) if key == :class klass = XpathSupport.escape " #{value} " "contains(concat(' ', @class, ' '), #{klass})" elsif key == :label && should_use_label_element? # we assume :label means a corresponding label element, not the attribute text = "normalize-space()=#{XpathSupport.escape value}" "(@id=//label[#{text}]/@for or parent::label[#{text}])" else "#{lhs_for(key)}=#{XpathSupport.escape value}" end end |
#fetch_value(element, how) ⇒ Object
110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/watir-nokogiri/locators/element_locator.rb', line 110 def fetch_value(element, how) case how when :text element.text when :tag_name element.node_name.downcase when :href (href = element.get_attribute('href')) && href.strip else element.get_attribute(how.to_s.gsub("_", "-")) end end |
#find_by_regexp_selector(selector, method = :find) ⇒ Object
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/watir-nokogiri/locators/element_locator.rb', line 48 def find_by_regexp_selector(selector, method = :find) parent = @nokogiri rx_selector = delete_regexps_from(selector) if rx_selector.has_key?(:label) && should_use_label_element? label = label_from_text(rx_selector.delete(:label)) || (return []) if (id = label.get_attribute('for')) selector[:id] = id else parent = label end end how, what = build_nokogiri_selector(selector) unless how raise Error, "internal error: unable to build WebDriver selector from #{selector.inspect}" end elements = parent.xpath(what) elements.__send__(method) { |el| matches_selector?(el, rx_selector) } end |
#given_css(selector) ⇒ Object
193 194 195 196 197 198 199 200 201 |
# File 'lib/watir-nokogiri/locators/element_locator.rb', line 193 def given_css(selector) return unless css = selector.delete(:css) unless selector.empty? || can_be_combined_with_css?(selector) raise ArgumentError, ":css cannot be combined with other selectors (#{selector.inspect})" end [:css, xpath] end |
#given_xpath(selector) ⇒ Object
171 172 173 174 175 176 177 178 179 |
# File 'lib/watir-nokogiri/locators/element_locator.rb', line 171 def given_xpath(selector) return unless xpath = selector.delete(:xpath) unless selector.empty? || can_be_combined_with_xpath?(selector) raise ArgumentError, ":xpath cannot be combined with other selectors (#{selector.inspect})" end [:xpath, xpath] end |
#label_from_text(label_exp) ⇒ Object
97 98 99 100 101 102 |
# File 'lib/watir-nokogiri/locators/element_locator.rb', line 97 def label_from_text(label_exp) # TODO: this won't work correctly if @nokogiri is a sub-element @nokogiri.search('label').find do |el| matches_selector?(el, :text => label_exp) end end |
#lhs_for(key) ⇒ Object
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 |
# File 'lib/watir-nokogiri/locators/element_locator.rb', line 264 def lhs_for(key) case key when :text, 'text' 'normalize-space()' when :href # TODO: change this behaviour? 'normalize-space(@href)' when :type # type attributes can be upper case - downcase them # https://github.com/watir/watir-webdriver/issues/72 XpathSupport.downcase('@type') else "@#{key.to_s.gsub("_", "-")}" end end |
#locate ⇒ Object
12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
# File 'lib/watir-nokogiri/locators/element_locator.rb', line 12 def locate() idx = @selector.delete(:index) if idx element = locate_all[idx] else element = locate_all.first end # This actually only applies when finding by xpath - browser.text_field(:xpath, "//input[@type='radio']") # We don't need to validate the element if we built the xpath ourselves. # It is also used to alter behavior of methods locating more than one type of element # (e.g. text_field locates both input and textarea) validate_element(element) if element end |
#locate_all ⇒ Object
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/watir-nokogiri/locators/element_locator.rb', line 27 def locate_all() selector = normalized_selector if selector.has_key? :index raise ArgumentError, "can't locate all elements by :index" end how, what = given_css(selector) || given_xpath(selector) || build_nokogiri_selector(selector) case how when :css @nokogiri.css(what) when :xpath @nokogiri.xpath(what) else find_by_regexp_selector(selector, :select) end end |
#matches_selector?(element, selector) ⇒ Boolean
104 105 106 107 108 |
# File 'lib/watir-nokogiri/locators/element_locator.rb', line 104 def matches_selector?(element, selector) selector.all? do |how, what| what === fetch_value(element, how) end end |
#normalize_selector(how, what) ⇒ Object
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/watir-nokogiri/locators/element_locator.rb', line 136 def normalize_selector(how, what) case how when :tag_name, :text, :xpath, :index, :class, :label, :css # include :class since the valid attribute is 'class_name' # include :for since the valid attribute is 'html_for' [how, what] when :class_name [:class, what] when :caption [:text, what] when :for assert_valid_as_attribute :html_for [how, what] else assert_valid_as_attribute how [how, what] end end |
#normalized_selector ⇒ Object
123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/watir-nokogiri/locators/element_locator.rb', line 123 def normalized_selector selector = {} @selector.each do |how, what| check_type(how, what) how, what = normalize_selector(how, what) selector[how] = what end selector end |
#should_use_label_element? ⇒ Boolean
93 94 95 |
# File 'lib/watir-nokogiri/locators/element_locator.rb', line 93 def should_use_label_element? @selector[:tag_name] != "option" end |
#tag_name_matches?(element_tag_name, tag_name) ⇒ Boolean
293 294 295 |
# File 'lib/watir-nokogiri/locators/element_locator.rb', line 293 def tag_name_matches?(element_tag_name, tag_name) tag_name === element_tag_name end |
#valid_attribute?(attribute) ⇒ Boolean
89 90 91 |
# File 'lib/watir-nokogiri/locators/element_locator.rb', line 89 def valid_attribute?(attribute) @valid_attributes && @valid_attributes.include?(attribute) end |
#validate_element(element) ⇒ Object
280 281 282 283 284 285 286 287 288 289 290 291 |
# File 'lib/watir-nokogiri/locators/element_locator.rb', line 280 def validate_element(element) tn = @selector[:tag_name] element_tag_name = element.node_name.downcase return if tn && !tag_name_matches?(element_tag_name, tn) if element_tag_name == 'input' return if @selector[:type] && @selector[:type] != element.get_attribute(:type).downcase end element end |