lib/capybara/screenshot/diff/capybara_setup.rb in capybara-screenshot-diff-0.5.3 vs lib/capybara/screenshot/diff/capybara_setup.rb in capybara-screenshot-diff-0.6.0

- old
+ new

@@ -95,12 +95,12 @@ end end teardown do if Capybara::Screenshot::Diff.enabled && @test_screenshots - test_screenshot_errors = - @test_screenshots.map { |args| assert_image_not_changed(*args) }.compact + test_screenshot_errors = @test_screenshots + .map { |caller, name, compare| assert_image_not_changed(caller, name, compare) }.compact fail(test_screenshot_errors.join("\n\n")) if test_screenshot_errors.any? end end def screenshot_section(name) @@ -112,39 +112,39 @@ @screenshot_counter = 0 return unless Capybara::Screenshot.active? && name.present? FileUtils.rm_rf screenshot_dir end - def screenshot(name) + def screenshot(name, color_distance_limit: Capybara::Screenshot::Diff.color_distance_limit, + area_size_limit: nil) return unless Capybara::Screenshot.active? return if window_size_is_wrong? if @screenshot_counter name = "#{format('%02i', @screenshot_counter)}_#{name}" @screenshot_counter += 1 end name = full_name(name) file_name = "#{self.class.screenshot_area_abs}/#{name}.png" - org_name = "#{self.class.screenshot_area_abs}/#{name}_0.png~" - new_name = "#{self.class.screenshot_area_abs}/#{name}_1.png~" FileUtils.mkdir_p File.dirname(file_name) - committed_file_name = check_vcs(name, file_name, org_name) - previous_file_exists = committed_file_name && File.exist?(committed_file_name) - previous_size = File.size(committed_file_name) if previous_file_exists - take_stable_screenshot(file_name, previous_size) - return unless previous_file_exists - (@test_screenshots ||= []) << [caller[0], name, file_name, committed_file_name, new_name, org_name] + committed_file_name = check_vcs(name, file_name) + comparison = Capybara::Screenshot::Diff::ImageCompare.new(committed_file_name, file_name, + dimensions: Capybara::Screenshot.window_size, color_distance_limit: color_distance_limit, + area_size_limit: area_size_limit) + take_stable_screenshot(comparison) + return unless comparison.old_file_exists? + (@test_screenshots ||= []) << [caller[0], name, comparison] end private def window_size_is_wrong? selenium? && Capybara::Screenshot.window_size && (!page.driver.chrome? || ON_WINDOWS) && # TODO(uwe): Allow for Chrome when it works page.driver.browser.manage.window.size != Selenium::WebDriver::Dimension.new(*Capybara::Screenshot.window_size) end - def check_vcs(name, file_name, org_name) + private def check_vcs(name, file_name) svn_file_name = "#{self.class.screenshot_area_abs}/.svn/text-base/#{name}.png.svn-base" if File.exist?(svn_file_name) committed_file_name = svn_file_name else svn_info = `svn info #{file_name} #{SILENCE_ERRORS}` @@ -153,21 +153,25 @@ checksum = svn_info.slice(/(?<=Checksum: ).*$/) if checksum committed_file_name = "#{wc_root}/.svn/pristine/#{checksum[0..1]}/#{checksum}.svn-base" end else - committed_file_name = org_name - redirect_target = "#{committed_file_name} #{SILENCE_ERRORS}" - `git show HEAD~0:./#{self.class.screenshot_area}/#{name}.png > #{redirect_target}` - if File.size(committed_file_name) == 0 - FileUtils.rm_f committed_file_name - end + committed_file_name = restore_git_revision(name, + Capybara::Screenshot::Diff::ImageCompare.annotated_old_file_name(file_name)) end end committed_file_name end + private def restore_git_revision(name, org_name) + committed_file_name = org_name + redirect_target = "#{committed_file_name} #{SILENCE_ERRORS}" + `git show HEAD~0:./#{self.class.screenshot_area}/#{name}.png > #{redirect_target}` + FileUtils.rm_f(committed_file_name) if File.size(committed_file_name) == 0 + committed_file_name + end + IMAGE_WAIT_SCRIPT = <<EOF.freeze function pending_image() { var images = document.images; for (var i = 0; i < images.length; i++) { if (!images[i].complete) { @@ -188,32 +192,37 @@ "Images not loaded after #{timeout}s: #{pending_image.inspect}" sleep 0.1 end end - def take_stable_screenshot(file_name, original_file_size = nil) + private def take_stable_screenshot(comparison) assert_images_loaded - old_file_size = original_file_size + previous_file_size = comparison.old_file_size screeenshot_started_at = last_image_change_at = Time.now loop do - save_screenshot(file_name) + save_screenshot(comparison.new_file_name) # TODO(uwe): Remove when chromedriver take right size screenshots - reduce_retina_image_size(file_name) + reduce_retina_image_size(comparison.new_file_name) # EMXIF break unless Capybara::Screenshot.stability_time_limit - new_file_size = File.size(file_name) - break if new_file_size == original_file_size - break if new_file_size == old_file_size && - (Time.now - last_image_change_at) > Capybara::Screenshot.stability_time_limit - last_image_change_at = Time.now if new_file_size != old_file_size - old_file_size = new_file_size - sleep 0.1 + break if comparison.quick_equal? + if comparison.new_file_size == previous_file_size + if (Time.now - last_image_change_at) > Capybara::Screenshot.stability_time_limit + break + end + else + last_image_change_at = Time.now + end + assert (Time.now - screeenshot_started_at) < Capybara.default_max_wait_time, "Could not get stable screenshot within #{Capybara.default_max_wait_time}s" + + previous_file_size = comparison.new_file_size + comparison.reset end end private def reduce_retina_image_size(file_name) return if !self.class.macos? || !selenium? || !Capybara::Screenshot.window_size @@ -223,14 +232,16 @@ height = (width * saved_image.height) / saved_image.width resized_image = saved_image.resample_bilinear(width, height) resized_image.save(file_name) end - def assert_image_not_changed(caller, name, file_name, committed_file_name, new_name, org_name) - if Capybara::Screenshot::Diff::ImageCompare.compare(committed_file_name, file_name, - Capybara::Screenshot.window_size) - "Screenshot does not match for '#{name}'\n#{file_name}\n#{org_name}\n#{new_name}\nat #{caller}" - end + def assert_image_not_changed(caller, name, comparison) + return unless comparison.different? + "Screenshot does not match for '#{name}' (area: #{comparison.size} #{comparison.dimensions}" \ + ", max_color_distance: #{comparison.max_color_distance.round(1)})\n" \ + "#{comparison.new_file_name}\n#{comparison.annotated_old_file_name}\n" \ + "#{comparison.annotated_new_file_name}\n" \ + "at #{caller}" end end end # rubocop:enable Metrics/ClassLength