lib/watir-webdriver/locators/element_locator.rb in watir-webdriver-0.5.3 vs lib/watir-webdriver/locators/element_locator.rb in watir-webdriver-0.5.4

- old
+ new

@@ -8,11 +8,11 @@ :class_name, :css, :id, :link, :link_text, - :name, + # :name, # deliberately excluded to be watirspec compliant :partial_link_text, :tag_name, :xpath ] @@ -73,18 +73,18 @@ def find_first_by_multiple selector = normalized_selector idx = selector.delete(:index) - xpath = given_xpath(selector) || build_xpath(selector) + how, what = given_xpath(selector) || build_wd_selector(selector) - if xpath + if how # could build xpath for selector if idx - @wd.find_elements(:xpath, xpath)[idx] + @wd.find_elements(how, what)[idx] else - @wd.find_element(:xpath, xpath) + @wd.find_element(how, what) end else # can't use xpath, probably a regexp in there if idx wd_find_by_regexp_selector(selector, :select)[idx] @@ -99,13 +99,13 @@ if selector.has_key? :index raise ArgumentError, "can't locate all elements by :index" end - xpath = given_xpath(selector) || build_xpath(selector) - if xpath - @wd.find_elements(:xpath, xpath) + how, what = given_xpath(selector) || build_wd_selector(selector) + if how + @wd.find_elements(how, what) else wd_find_by_regexp_selector(selector, :select) end end @@ -130,13 +130,17 @@ if rx_selector.has_key?(:label) && should_use_label_element? selector[:id] = id_from_label(rx_selector.delete(:label)) || return end - xpath = build_xpath(selector) || raise("internal error: unable to build xpath from #{selector.inspect}") + how, what = build_wd_selector(selector) - elements = @wd.find_elements(:xpath, xpath) + unless how + raise Error, "internal error: unable to build WebDriver selector from #{selector.inspect}" + end + + elements = @wd.find_elements(how, what) elements.__send__(method) { |el| matches_selector?(el, rx_selector) } end VALID_WHATS = [String, Regexp] @@ -262,17 +266,21 @@ def should_use_label_element? @selector[:tag_name] != "option" end - def build_xpath(selectors) - return if selectors.values.any? { |e| e.kind_of? Regexp } + def build_wd_selector(selectors) + unless selectors.values.any? { |e| e.kind_of? Regexp } + build_css(selectors) || build_xpath(selectors) + end + end + def build_xpath(selectors) xpath = ".//" xpath << (selectors.delete(:tag_name) || '*').to_s - idx = selectors.delete(:index) + idx = selectors.delete :index # the remaining entries should be attributes unless selectors.empty? xpath << "[" << attribute_expression(selectors) << "]" end @@ -281,23 +289,69 @@ xpath << "[#{idx + 1}]" end p :xpath => xpath, :selectors => selectors if $DEBUG - xpath + [:xpath, xpath] end + def build_css(selectors) + return unless use_css?(selectors) + + css = '' + css << (selectors.delete(:tag_name) || '') + + klass = selectors.delete(:class) + if klass + if klass.include? ' ' + css << %([class="#{css_escape klass}"]) + else + css << ".#{klass}" + end + end + + href = selectors.delete(:href) + if href + css << %([href~="#{css_escape href}"]) + end + + selectors.each do |key, value| + key = key.to_s.gsub("_", "-") + css << %([#{key}="#{css_escape value}"]) # TODO: proper escaping + end + + [:css, css] + end + + def use_css?(selectors) + return false unless Watir.prefer_css? + + if selectors.has_key?(:text) || selectors.has_key?(:label) || selectors.has_key?(:index) + return false + end + + if selectors.has_key?(:class) && selectors[:class] !~ /^[\w-]+$/ui + return false + end + + true + end + 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 + def css_escape(str) + str.gsub('"', '\\"') + end + def equal_pair(key, value) if key == :class klass = XpathSupport.escape " #{value} " "contains(concat(' ', @class, ' '), #{klass})" elsif key == :label && should_use_label_element? @@ -338,10 +392,10 @@ unless selector.empty? || can_be_combined_with_xpath?(selector) raise ArgumentError, ":xpath cannot be combined with other selectors (#{selector.inspect})" end - xpath + [:xpath, xpath] end def can_be_combined_with_xpath?(selector) # ouch - is this worth it? keys = selector.keys