lib/capybara/screenshot/diff/stabilization.rb in capybara-screenshot-diff-1.3.1 vs lib/capybara/screenshot/diff/stabilization.rb in capybara-screenshot-diff-1.4.0

- old
+ new

@@ -1,8 +1,8 @@ # frozen_string_literal: true -require_relative 'os' +require_relative "os" module Capybara module Screenshot module Diff module Stabilization @@ -18,31 +18,29 @@ } return false; }() JS - def take_stable_screenshot(comparison, color_distance_limit:, shift_distance_limit:, - area_size_limit:, skip_area:, stability_time_limit:, wait:) - blurred_input = prepare_page_for_screenshot(timeout: wait) + def take_stable_screenshot(comparison, stability_time_limit:, wait:) previous_file_name = comparison.old_file_name screenshot_started_at = last_image_change_at = Time.now + clean_stabilization_images(comparison.new_file_name) + 1.step do |i| take_right_size_screenshot(comparison) - - break unless stability_time_limit - if comparison.quick_equal? clean_stabilization_images(comparison.new_file_name) break end comparison.reset if previous_file_name - stabilization_comparison = - ImageCompare.new(comparison.new_file_name, previous_file_name, - color_distance_limit: color_distance_limit, shift_distance_limit: shift_distance_limit, - area_size_limit: area_size_limit, skip_area: skip_area) + stabilization_comparison = make_stabilization_comparison_from( + comparison, + comparison.new_file_name, + previous_file_name + ) if stabilization_comparison.quick_equal? if (Time.now - last_image_change_at) > stability_time_limit clean_stabilization_images(comparison.new_file_name) break end @@ -50,43 +48,58 @@ else last_image_change_at = Time.now end end - previous_file_name = "#{comparison.new_file_name.chomp('.png')}" \ - "_x#{format('%02i', i)}_#{(Time.now - screenshot_started_at).round(1)}s" \ - "_#{stabilization_comparison.dimensions&.to_s&.gsub(', ', '_') || :initial}.png~" + previous_file_name = "#{comparison.new_file_name.chomp(".png")}" \ + "_x#{format("%02i", i)}_#{(Time.now - screenshot_started_at).round(1)}s" \ + "_#{stabilization_comparison.difference_region&.to_s&.gsub(", ", "_") || :initial}.png~" FileUtils.mv comparison.new_file_name, previous_file_name - check_max_wait_time(comparison, screenshot_started_at, - wait: wait, shift_distance_limit: shift_distance_limit) + check_max_wait_time( + comparison, + screenshot_started_at, + max_wait_time: max_wait_time(comparison.shift_distance_limit, wait) + ) end - ensure - blurred_input&.click end + def notice_how_to_avoid_this + unless @_csd_retina_warned + warn "Halving retina screenshot. " \ + 'You should add "force-device-scale-factor=1" to your Chrome chromeOptions args.' + @_csd_retina_warned = true + end + end + private - def reduce_retina_image_size(file_name) + def make_stabilization_comparison_from(comparison, new_file_name, previous_file_name) + ImageCompare.new(new_file_name, previous_file_name, **comparison.driver_options) + end + + def reduce_retina_image_size(file_name, driver) return if !ON_MAC || !selenium? || !Capybara::Screenshot.window_size - saved_image = ChunkyPNG::Image.from_file(file_name) - width = Capybara::Screenshot.window_size[0] - return if saved_image.width < width * 2 + expected_image_width = Capybara::Screenshot.window_size[0] + saved_image = driver.from_file(file_name) + return if driver.width_for(saved_image) < expected_image_width * 2 - unless @_csd_retina_warned - warn 'Halving retina screenshot. ' \ - 'You should add "force-device-scale-factor=1" to your Chrome chromeOptions args.' - @_csd_retina_warned = true + notice_how_to_avoid_this + + new_height = expected_image_width * driver.height_for(saved_image) / driver.width_for(saved_image) + resized_image = driver.resize_image_to(saved_image, expected_image_width, new_height) + + Dir.mktmpdir do |dir| + resized_image_file = "#{dir}/resized.png" + driver.save_image_to(resized_image, resized_image_file) + FileUtils.mv(resized_image_file, file_name) end - height = (width * saved_image.height) / saved_image.width - resized_image = saved_image.resample_bilinear(width, height) - resized_image.save(file_name) end def stabilization_images(base_file) - Dir["#{base_file.chomp('.png')}_x*.png~"].sort + Dir["#{base_file.chomp(".png")}_x*.png~"].sort end def clean_stabilization_images(base_file) FileUtils.rm stabilization_images(base_file) end @@ -102,55 +115,74 @@ } return null; JS blurred_input = page.driver.send :unwrap_script_result, active_element end - execute_script("$('*').css('caret-color','transparent')") if Capybara::Screenshot.hide_caret + if Capybara::Screenshot.hide_caret && !@hid_caret + execute_script(<<~JS) + var style = document.createElement('style'); + document.head.appendChild(style); + var styleSheet = style.sheet; + styleSheet.insertRule("* { caret-color: transparent !important; }", 0); + JS + @hid_caret = true + end blurred_input end def take_right_size_screenshot(comparison) save_screenshot(comparison.new_file_name) # TODO(uwe): Remove when chromedriver takes right size screenshots - reduce_retina_image_size(comparison.new_file_name) + reduce_retina_image_size(comparison.new_file_name, comparison.driver) # ODOT end - def check_max_wait_time(comparison, screenshot_started_at, wait:, shift_distance_limit:) - shift_factor = shift_distance_limit ? (shift_distance_limit * 2 + 1) ^ 2 : 1 - max_wait_time = wait * shift_factor + def check_max_wait_time(comparison, screenshot_started_at, max_wait_time:) return if (Time.now - screenshot_started_at) < max_wait_time + annotate_stabilization_images(comparison) # FIXME(uwe): Change to store the failure and only report if the test succeeds functionally. + fail("Could not get stable screenshot within #{max_wait_time}s\n" \ + "#{stabilization_images(comparison.new_file_name).join("\n")}") + end + + def annotate_stabilization_images(comparison) previous_file = comparison.old_file_name stabilization_images(comparison.new_file_name).each do |file_name| if File.exist? previous_file - stabilization_comparison = - ImageCompare.new(file_name, previous_file, - color_distance_limit: comparison.color_distance_limit, - shift_distance_limit: comparison.shift_distance_limit, - area_size_limit: comparison.area_size_limit, skip_area: comparison.skip_area) - assert stabilization_comparison.different? - FileUtils.mv stabilization_comparison.annotated_new_file_name, file_name + stabilization_comparison = make_stabilization_comparison_from( + comparison, + file_name, + previous_file + ) + if stabilization_comparison.different? + FileUtils.mv stabilization_comparison.annotated_new_file_name, file_name + end FileUtils.rm stabilization_comparison.annotated_old_file_name end previous_file = file_name end - fail("Could not get stable screenshot within #{max_wait_time}s\n" \ - "#{stabilization_images(comparison.new_file_name).join("\n")}") end + def max_wait_time(shift_distance_limit, wait) + shift_factor = shift_distance_limit ? (shift_distance_limit * 2 + 1) ^ 2 : 1 + wait * shift_factor + end + def assert_images_loaded(timeout:) return unless respond_to? :evaluate_script start = Time.now loop do pending_image = evaluate_script IMAGE_WAIT_SCRIPT break unless pending_image - assert((Time.now - start) < timeout, - "Images not loaded after #{timeout}s: #{pending_image.inspect}") + assert( + (Time.now - start) < timeout, + "Images not loaded after #{timeout}s: #{pending_image.inspect}" + ) + sleep 0.1 end end end end