lib/watir-webdriver/locators/element_locator.rb in watir-webdriver-0.0.7 vs lib/watir-webdriver/locators/element_locator.rb in watir-webdriver-0.0.8
- old
+ new
@@ -28,14 +28,18 @@
if e = by_id
return e
end
if @selector.size == 1
- find_first_by_one
+ element = find_first_by_one
else
- find_first_by_multiple
+ element = find_first_by_multiple
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.
+ validate_element(element) if element
rescue WebDriver::Error::NoSuchElementError => wde
nil
end
def locate_all
@@ -44,29 +48,31 @@
else
find_all_by_multiple
end
end
+ private
+
def find_first_by_one
- how, what = @selector.shift
+ how, what = @selector.to_a.first
check_type how, what
if WD_FINDERS.include?(how)
wd_find_first_by(how, what)
else
- raise NotImplementedError, "find first by attribute/other"
+ find_first_by_multiple
end
end
def find_all_by_one
- how, what = @selector.shift
+ how, what = @selector.to_a.first
check_type how, what
if WD_FINDERS.include?(how)
wd_find_all_by(how, what)
else
- raise NotImplementedError, "find all by attribute/other"
+ find_all_by_multiple
end
end
def find_first_by_multiple
selector = normalized_selector
@@ -93,11 +99,11 @@
def find_all_by_multiple
selector = normalized_selector
if selector.has_key? :index
- raise Error, "can't locate all elements by :index"
+ raise ArgumentError, "can't locate all elements by :index"
end
xpath = selector[:xpath] || build_xpath(selector)
if xpath
@wd.find_elements(:xpath, xpath)
@@ -108,65 +114,75 @@
def wd_find_first_by(how, what)
if what.kind_of? String
@wd.find_element(how, what)
else
- all_elements.find { |e| fetch_value(how, e) =~ what }
+ all_elements.find { |element| fetch_value(element, how) =~ what }
end
end
def wd_find_all_by(how, what)
if what.kind_of? String
@wd.find_elements(how, what)
else
- all_elements.select { |e| fetch_value(how, e) =~ what }
+ all_elements.select { |element| fetch_value(element, how) =~ what }
end
end
def wd_find_by_regexp_selector(selector, method = :find)
rx_selector = delete_regexps_from(selector)
if rx_selector.has_key?(:label) && should_use_label_element?
- label_exp = rx_selector.delete(:label)
- label = @wd.find_elements(:tag_name, 'label').find { |e| matches_selector?({:text => label_exp}, e) } || return
-
- selector[:id] = label.attribute(:for)
+ 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}")
+ xpath = build_xpath(selector) || raise("internal error: unable to build xpath from #{selector.inspect}")
elements = @wd.find_elements(:xpath, xpath)
- elements.send(method) { |e| matches_selector?(rx_selector, e) }
+ elements.__send__(method) { |el| matches_selector?(el, rx_selector) }
end
+ VALID_WHATS = [String, Regexp]
+
def check_type(how, what)
case how
when :index
- raise TypeError, "expected Fixnum, got #{what.class}" unless what.kind_of?(Fixnum)
+ unless what.kind_of?(Fixnum)
+ raise TypeError, "expected Fixnum, got #{what.inspect}:#{what.class}"
+ end
else
- unless [String, Regexp].any? { |t| what.kind_of? t }
- raise TypeError, "expected String or Regexp, got #{what.inspect}:#{what.class}"
+ 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
- def fetch_value(how, element)
+ def id_from_label(label_exp)
+ # TODO: this won't work correctly if @wd is a sub-element
+ label = @wd.find_elements(:tag_name, 'label').find do |el|
+ matches_selector?(el, :text => label_exp)
+ end
+
+ label.attribute(:for) if label
+ end
+
+ def fetch_value(element, how)
case how
when :text
element.text
when :tag_name
element.tag_name
+ when :href
+ (href = element.attribute(:href)) && href.strip
else
element.attribute(how)
end
end
- def matches_selector?(selector, element)
- # p :start => selector
+ def matches_selector?(element, selector)
selector.all? do |how, what|
- # p :comparing => [how, what], :to => fetch_value(how, element)
- what === fetch_value(how, element)
+ what === fetch_value(element, how)
end
end
def normalized_selector
selector = {}
@@ -181,17 +197,16 @@
selector
end
def normalize_selector(how, what)
case how
- when :url
- [:href, what]
when :caption
[:text, what]
when :class_name
[:class, what]
- when :tag_name, :text, :xpath, :index, :class # include class since the attribute method is 'class_name'
+ when :tag_name, :text, :xpath, :index, :class
+ # include class since the valid attribute is 'class_name'
[how, what]
else
assert_valid_as_attribute how
[how, what]
end
@@ -208,11 +223,11 @@
rx_selector
end
def assert_valid_as_attribute(attribute)
- unless valid_attribute? attribute
+ unless valid_attribute? attribute or attribute.to_s =~ /^data_.+$/
raise MissingWayOfFindingObjectException, "invalid attribute: #{attribute.inspect}"
end
end
def by_id
@@ -270,11 +285,11 @@
end
def attribute_expression(selectors)
selectors.map do |key, val|
if val.kind_of?(Array)
- "( " + val.map { |v| equal_pair(key, v) }.join(" or ") + " )"
+ "(" + val.map { |v| equal_pair(key, v) }.join(" or ") + ")"
else
equal_pair(key, val)
end
end.join(" and ")
end
@@ -296,9 +311,20 @@
# TODO: change this behaviour?
'normalize-space(@href)'
else
"@#{key.to_s.gsub("_", "-")}"
end
+ end
+
+ def validate_element(element)
+ tn = @selector[:tag_name]
+ return if tn && !tag_name_matches?(element, tn)
+
+ if element.tag_name == 'input'
+ return if @selector[:type] && @selector[:type] != element.attribute(:type)
+ end
+
+ element
end
end # ElementLocator
end # Watir