lib/watir/locators/element/locator.rb in watir-6.15.0 vs lib/watir/locators/element/locator.rb in watir-6.15.1
- old
+ new
@@ -49,37 +49,34 @@
filter == :all ? locate_elements(how, what) : locate_element(how, what)
end
def using_watir(filter = :first)
- raise ArgumentError, "can't locate all elements by :index" if @selector.key?(:index) && filter == :all
+ selector = @selector.dup
+ raise ArgumentError, "can't locate all elements by :index" if selector.key?(:index) && filter == :all
- begin
- generate_scope
- rescue LocatorException
- return nil
- end
+ @driver_scope ||= @query_scope.wd
- selector, values_to_match = selector_builder.build(@selector)
+ built = selector_builder.build(selector)
- validate_built_selector(selector, values_to_match)
+ validate_built_selector(built)
+ wd_locator = built.select { |key, _value| %i[css xpath link_text partial_link_text].include? key }
+ values_to_match = built.reject { |key, _value| %i[css xpath link_text partial_link_text].include? key }
+
if filter == :all || values_to_match.any?
- locate_matching_elements(selector, values_to_match, filter)
+ locate_matching_elements(wd_locator, values_to_match, filter)
else
- locate_element(selector.keys.first, selector.values.first, @driver_scope)
+ locate_element(wd_locator.keys.first, wd_locator.values.first, @driver_scope)
end
end
- def validate_built_selector(selector, values_to_match)
- if selector.nil?
- msg = "#{selector_builder.class} was unable to build selector from #{@selector.inspect}"
- raise LocatorException, msg
- elsif values_to_match.nil?
- msg = "#{selector_builder.class}#build is not returning expected responses for the current version of Watir"
- raise LocatorException, msg
- end
+ def validate_built_selector(built)
+ return unless built.nil? || built.empty?
+
+ msg = "#{selector_builder.class} was unable to build selector from #{@selector.inspect}"
+ raise LocatorException, msg
end
def fetch_value(element, how)
case how
when :text
@@ -96,10 +93,23 @@
how = how.to_s.tr('_', '-') if how.is_a?(::Symbol)
element.attribute(how)
end
end
+ def matching_labels(elements, values_to_match, scope)
+ label_key = values_to_match.key?(:label_element) ? :label_element : :visible_label_element
+ label_value = values_to_match.delete(:label_element) || values_to_match.delete(:visible_label_element)
+ locator_key = label_key.to_s.gsub('label', 'text').gsub('_element', '').to_sym
+
+ Watir::LabelCollection.new(scope, tag_name: 'label').map { |label|
+ next unless matches_values?(label.wd, locator_key => label_value)
+
+ input = label.for.empty? ? label.input : Watir::Input.new(scope, id: label.for)
+ input.wd if elements.include?(input.wd)
+ }.compact
+ end
+
def matching_elements(elements, values_to_match, filter: :first)
if filter == :first
idx = element_index(elements, values_to_match)
counter = 0
@@ -122,48 +132,10 @@
elements.reverse!
idx.abs - 1
end
- def generate_scope
- return @driver_scope if @driver_scope
-
- @driver_scope = @query_scope.wd
-
- if @selector.key?(:label)
- process_label :label
- elsif @selector.key?(:visible_label)
- process_label :visible_label
- end
- end
-
- def process_label(label_key)
- regexp = @selector[label_key].is_a?(Regexp)
- return unless (regexp || label_key == :visible_label) && selector_builder.should_use_label_element?
-
- label = label_from_text(label_key)
- msg = "Unable to locate element with label #{label_key}: #{@selector[label_key]}"
- raise LocatorException, msg unless label
-
- id = label.attribute('for')
- if id
- @selector[:id] = id
- else
- @driver_scope = label
- end
- end
-
- def label_from_text(label_key)
- # TODO: this won't work correctly if @wd is a sub-element, write spec
- # TODO: Figure out how to do this with find_element
- label_text = @selector.delete(label_key)
- locator_key = label_key.to_s.gsub('label', 'text').gsub('_element', '').to_sym
- locate_elements(:tag_name, 'label', @driver_scope).find do |el|
- matches_values?(el, locator_key => label_text)
- end
- end
-
def matches_values?(element, values_to_match)
matches = values_to_match.all? do |how, what|
if how == :tag_name && what.is_a?(String)
element_validator.validate(element, what)
else
@@ -199,9 +171,12 @@
def locate_matching_elements(selector, values_to_match, filter)
retries = 0
begin
elements = locate_elements(selector.keys.first, selector.values.first, @driver_scope) || []
+ if values_to_match.key?(:label_element) || values_to_match.key?(:visible_label_element)
+ elements = matching_labels(elements, values_to_match, @query_scope)
+ end
matching_elements(elements, values_to_match, filter: filter)
rescue Selenium::WebDriver::Error::StaleElementReferenceError
retries += 1
sleep 0.5
retry unless retries > 2