lib/watir/locators/element/locator.rb in watir-6.9.1 vs lib/watir/locators/element/locator.rb in watir-6.10.0

- old
+ new

@@ -34,128 +34,86 @@ @selector_builder = selector_builder @element_validator = element_validator end def locate - e = by_id and return e # short-circuit if :id is given - - element = if @selector.size == 1 - find_first_by_one - else - find_first_by_multiple - end - - # Validation not necessary if Watir builds the xpath - return element unless @selector.key?(:xpath) || @selector.key?(:css) - element_validator.validate(element, @selector) if element + using_selenium(:first) || using_watir(:first) rescue Selenium::WebDriver::Error::NoSuchElementError, Selenium::WebDriver::Error::StaleElementReferenceError nil end def locate_all - if @selector.size == 1 - find_all_by_one - else - find_all_by_multiple - end + return [@selector[:element]] if @selector.key?(:element) + using_selenium(:all) || using_watir(:all) end private - def by_id + def using_selenium(filter = :first) selector = @selector.dup - id = selector.delete(:id) - return if !id.is_a?(String) || selector[:adjacent] + tag_name = selector[:tag_name].is_a?(::Symbol) ? selector[:tag_name].to_s : selector[:tag_name] + selector.delete(:tag_name) if selector.size > 1 - tag_name = selector.delete(:tag_name) - return unless selector.empty? # multiple attributes - - element = locate_element(:id, id) - return if tag_name && !element_validator.validate(element, {tag_name: tag_name}) - - element - end - - def find_first_by_one - how, what = @selector.to_a.first - selector_builder.check_type(how, what) - - if wd_supported?(how, what) - wd_find_first_by(how, what) - else - find_first_by_multiple + WD_FINDERS.each do |sel| + next unless (value = selector.delete(sel)) + return unless selector.empty? && wd_supported?(sel, value) + if filter == :all + found = locate_elements(sel, value) + return filter_elements_by_locator(found, tag_name: tag_name, filter: filter).compact + else + found = locate_element(sel, value) + return sel != :tag_name && tag_name && !validate([found], tag_name) ? nil : found + end end + nil end - def find_first_by_multiple + def using_watir(filter = :first) selector = selector_builder.normalized_selector + visible = selector.delete(:visible) + visible_text = selector.delete(:visible_text) + tag_name = selector[:tag_name].is_a?(::Symbol) ? selector[:tag_name].to_s : selector[:tag_name] + validation_required = (selector.key?(:css) || selector.key?(:xpath)) && tag_name + if selector.key?(:index) && filter == :all + raise ArgumentError, "can't locate all elements by :index" + end idx = selector.delete(:index) unless selector[:adjacent] - visible = selector.delete(:visible) how, what = selector_builder.build(selector) - if how - # could build xpath/css for selector - if idx && idx != 0 || !visible.nil? - elements = locate_elements(how, what) - filter_elements elements, visible, idx, :single - else - locate_element(how, what) - end - else - # can't use xpath, probably a regexp in there - if idx && idx != 0 || !visible.nil? - elements = wd_find_by_regexp_selector(selector, :select) - filter_elements elements, visible, idx, :single - else - wd_find_by_regexp_selector(selector, :find) - end - end - end + needs_filtering = idx && idx != 0 || !visible.nil? || !visible_text.nil? || validation_required || filter == :all - def find_all_by_one - how, what = @selector.to_a.first - return [what] if how == :element - selector_builder.check_type how, what - - if wd_supported?(how, what) - wd_find_all_by(how, what) + if needs_filtering + matching = matching_elements(how, what, selector) + return filter_elements_by_locator(matching, visible, visible_text, idx, tag_name: tag_name, filter: filter) + elsif how + locate_element(how, what) else - find_all_by_multiple + wd_find_by_regexp_selector(selector, :first) end end - def find_all_by_multiple - selector = selector_builder.normalized_selector - visible = selector.delete(:visible) - - if selector.key? :index - raise ArgumentError, "can't locate all elements by :index" - end - - how, what = selector_builder.build(selector) - found = if how - locate_elements(how, what) - else - wd_find_by_regexp_selector(selector, :select) - end - return [] if found.nil? - filter_elements found, visible, nil, :multiple + def validate(elements, tag_name) + elements.compact.all? { |element| element_validator.validate(element, {tag_name: tag_name}) } end - def wd_find_all_by(how, what) - if what.is_a? String - locate_elements(how, what) - else - all_elements.select { |element| fetch_value(element, how) =~ what } - end + def matching_elements(how, what, selector = nil) + found = how ? locate_elements(how, what) : wd_find_by_regexp_selector(selector, :all) + found || [] end def fetch_value(element, how) case how when :text + vis = element.text + all = Watir::Element.new(@query_scope, element: element).send(:execute_js, :getTextContent, element).strip + unless all == vis.strip + Watir.logger.deprecate(':text locator with RegExp values to find elements based on only visible text', ":visible_text") + end + vis + when :visible_text element.text when :tag_name element.tag_name.downcase when :href (href = element.attribute(:href)) && href.strip @@ -166,19 +124,11 @@ def all_elements locate_elements(:xpath, ".//*") end - def wd_find_first_by(how, what) - if what.is_a? String - locate_element(how, what) - else - all_elements.find { |element| fetch_value(element, how) =~ what } - end - end - - def wd_find_by_regexp_selector(selector, method = :find) + def wd_find_by_regexp_selector(selector, filter) query_scope = ensure_scope_context rx_selector = delete_regexps_from(selector) if rx_selector.key?(:label) && selector_builder.should_use_label_element? label = label_from_text(rx_selector.delete(:label)) || return @@ -203,19 +153,22 @@ what = "(#{what})[#{predicates.join(' and ')}]" unless predicates.empty? end end elements = locate_elements(how, what, query_scope) - filter_elements_by_regex(elements, rx_selector, method) + filter_elements_by_regex(elements, rx_selector, filter) end - def filter_elements elements, visible, idx, number + def filter_elements_by_locator(elements, visible = nil, visible_text = nil, idx = nil, tag_name: nil, filter: :first) elements.select! { |el| visible == el.displayed? } unless visible.nil? - number == :single ? elements[idx || 0] : elements + elements.select! { |el| visible_text === el.text } unless visible_text.nil? + elements.select! { |el| element_validator.validate(el, {tag_name: tag_name}) } unless tag_name.nil? + filter == :first ? elements[idx || 0] : elements end - def filter_elements_by_regex(elements, selector, method) + def filter_elements_by_regex(elements, selector, filter) + method = filter == :first ? :find : :select elements.__send__(method) { |el| matches_selector?(el, selector) } end def delete_regexps_from(selector) rx_selector = {} @@ -260,21 +213,24 @@ def ensure_scope_context @query_scope.wd end - def locate_element(how, what) - @query_scope.wd.find_element(how, what) + def locate_element(how, what, scope = @query_scope.wd) + scope.find_element(how, what) end def locate_elements(how, what, scope = @query_scope.wd) scope.find_elements(how, what) end def wd_supported?(how, what) - return false unless WD_FINDERS.include?(how) - return false unless what.kind_of?(String) || what.kind_of?(Regexp) - return false if [:class, :class_name].include?(how) && what.kind_of?(String) && what.include?(' ') + return false unless what.kind_of?(String) + return false if [:class, :class_name].include?(how) && what.include?(' ') + %i[partial_link_text link_text link].each do |loc| + next unless how == loc + Watir.logger.deprecate(":#{loc} locator", ':visible_text') + end true end end end end