diff --git a/lib/capybara/selenium/extensions/find.rb b/lib/capybara/selenium/extensions/find.rb index f097ea3f..9de64ff6 100644 --- a/lib/capybara/selenium/extensions/find.rb +++ b/lib/capybara/selenium/extensions/find.rb @@ -18,44 +18,21 @@ module Capybara hints = [] if (els.size > 2) && !ENV['DISABLE_CAPYBARA_SELENIUM_OPTIMIZATIONS'] - els = filter_by_text(els, texts) unless texts.empty? + begin + els = filter_by_text(els, texts) unless texts.empty? + hints_js, functions = build_hints_js(uses_visibility, styles) - hints_js = +'' - functions = [] - if uses_visibility && !is_displayed_atom.empty? - hints_js << <<~VISIBILITY_JS - var vis_func = #{is_displayed_atom}; - VISIBILITY_JS - functions << 'vis_func' - end - - if styles.is_a? Hash - hints_js << <<~STYLE_JS - var style_func = function(el){ - var el_styles = window.getComputedStyle(el); - return #{styles.keys.map(&:to_s)}.reduce(function(res, style){ - res[style] = el_styles[style]; - return res; - }, {}); - }; - STYLE_JS - functions << 'style_func' - end - - unless functions.empty? - hints_js << <<~EACH_JS - return arguments[0].map(function(el){ - return [#{functions.join(',')}].map(function(fn){ return fn.call(null, el) }); - }); - EACH_JS - - hints = es_context.execute_script hints_js, els - hints.map! do |results| - result = {} - result[:style] = results.pop if styles.is_a? Hash - result[:visible] = results.pop if uses_visibility - result + unless functions.empty? + hints = es_context.execute_script(hints_js, els).map! do |results| + hint = {} + hint[:style] = results.pop if functions.include?(:style_func) + hint[:visible] = results.pop if functions.include?(:vis_func) + hint + end end + rescue ::Selenium::WebDriver::Error::StaleElementReferenceError + # warn 'Unexpected Stale Element Error - skipping optimization' + hints = [] end end els.map.with_index { |el, idx| build_node(el, hints[idx] || {}) } @@ -63,7 +40,7 @@ module Capybara def filter_by_text(elements, texts) es_context.execute_script <<~JS, elements, texts - var texts = arguments[1] + var texts = arguments[1]; return arguments[0].filter(function(el){ var content = el.textContent.toLowerCase(); return texts.every(function(txt){ return content.indexOf(txt.toLowerCase()) != -1 }); @@ -71,6 +48,39 @@ module Capybara JS end + def build_hints_js(uses_visibility, styles) + functions = [] + hints_js = +'' + + if uses_visibility && !is_displayed_atom.empty? + hints_js << <<~VISIBILITY_JS + var vis_func = #{is_displayed_atom}; + VISIBILITY_JS + functions << :vis_func + end + + if styles.is_a? Hash + hints_js << <<~STYLE_JS + var style_func = function(el){ + var el_styles = window.getComputedStyle(el); + return #{styles.keys.map(&:to_s)}.reduce(function(res, style){ + res[style] = el_styles[style]; + return res; + }, {}); + }; + STYLE_JS + functions << :style_func + end + + hints_js << <<~EACH_JS + return arguments[0].map(function(el){ + return [#{functions.join(',')}].map(function(fn){ return fn.call(null, el) }); + }); + EACH_JS + + [hints_js, functions] + end + def es_context respond_to?(:execute_script) ? self : driver end