capybara-screenshot-diff 1.6.3 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +8 -0
- data/.github/workflows/lint.yml +1 -1
- data/.github/workflows/test.yml +36 -18
- data/.gitignore +2 -0
- data/CONTRIBUTING.md +3 -1
- data/Dockerfile +2 -3
- data/README.md +39 -27
- data/bin/install-vips +1 -1
- data/capybara-screenshot-diff.gemspec +2 -2
- data/lib/capybara/screenshot/diff/browser_helpers.rb +101 -0
- data/lib/capybara/screenshot/diff/drivers/chunky_png_driver.rb +30 -17
- data/lib/capybara/screenshot/diff/drivers/vips_driver.rb +26 -17
- data/lib/capybara/screenshot/diff/image_compare.rb +85 -72
- data/lib/capybara/screenshot/diff/region.rb +86 -0
- data/lib/capybara/screenshot/diff/stabilization.rb +14 -38
- data/lib/capybara/screenshot/diff/test_methods.rb +68 -35
- data/lib/capybara/screenshot/diff/vcs.rb +6 -5
- data/lib/capybara/screenshot/diff/version.rb +1 -1
- metadata +8 -6
- data/gemfiles/rails52.gemfile +0 -6
| @@ -8,6 +8,8 @@ require "active_support/core_ext/string/strip" | |
| 8 8 | 
             
            require_relative "image_compare"
         | 
| 9 9 | 
             
            require_relative "stabilization"
         | 
| 10 10 | 
             
            require_relative "vcs"
         | 
| 11 | 
            +
            require_relative "browser_helpers"
         | 
| 12 | 
            +
            require_relative "region"
         | 
| 11 13 |  | 
| 12 14 | 
             
            # Add the `screenshot` method to ActionDispatch::IntegrationTest
         | 
| 13 15 | 
             
            module Capybara
         | 
| @@ -16,6 +18,7 @@ module Capybara | |
| 16 18 | 
             
                  module TestMethods
         | 
| 17 19 | 
             
                    include Stabilization
         | 
| 18 20 | 
             
                    include Vcs
         | 
| 21 | 
            +
                    include BrowserHelpers
         | 
| 19 22 |  | 
| 20 23 | 
             
                    def initialize(*)
         | 
| 21 24 | 
             
                      super
         | 
| @@ -34,21 +37,13 @@ module Capybara | |
| 34 37 | 
             
                    end
         | 
| 35 38 |  | 
| 36 39 | 
             
                    def full_name(name)
         | 
| 37 | 
            -
                      File.join group_parts | 
| 40 | 
            +
                      File.join group_parts.push(name).map(&:to_s)
         | 
| 38 41 | 
             
                    end
         | 
| 39 42 |  | 
| 40 43 | 
             
                    def screenshot_dir
         | 
| 41 44 | 
             
                      File.join [Screenshot.screenshot_area] + group_parts
         | 
| 42 45 | 
             
                    end
         | 
| 43 46 |  | 
| 44 | 
            -
                    def current_capybara_driver_class
         | 
| 45 | 
            -
                      Capybara.current_session.driver.class
         | 
| 46 | 
            -
                    end
         | 
| 47 | 
            -
             | 
| 48 | 
            -
                    def selenium?
         | 
| 49 | 
            -
                      current_capybara_driver_class <= Capybara::Selenium::Driver
         | 
| 50 | 
            -
                    end
         | 
| 51 | 
            -
             | 
| 52 47 | 
             
                    def screenshot_section(name)
         | 
| 53 48 | 
             
                      @screenshot_section = name.to_s
         | 
| 54 49 | 
             
                    end
         | 
| @@ -62,7 +57,7 @@ module Capybara | |
| 62 57 | 
             
                    end
         | 
| 63 58 |  | 
| 64 59 | 
             
                    # @return [Boolean] whether a screenshot was taken
         | 
| 65 | 
            -
                    def screenshot(name,  | 
| 60 | 
            +
                    def screenshot(name, skip_stack_frames: 0, **options)
         | 
| 66 61 | 
             
                      return false unless Screenshot.active?
         | 
| 67 62 | 
             
                      return false if window_size_is_wrong?
         | 
| 68 63 |  | 
| @@ -70,12 +65,7 @@ module Capybara | |
| 70 65 |  | 
| 71 66 | 
             
                      stability_time_limit = driver_options[:stability_time_limit]
         | 
| 72 67 | 
             
                      wait = driver_options[:wait]
         | 
| 73 | 
            -
                      crop = driver_options | 
| 74 | 
            -
             | 
| 75 | 
            -
                      # Allow nil or single or multiple areas
         | 
| 76 | 
            -
                      if driver_options[:skip_area]
         | 
| 77 | 
            -
                        driver_options[:skip_area] = driver_options[:skip_area].compact.flatten&.each_slice(4)&.to_a
         | 
| 78 | 
            -
                      end
         | 
| 68 | 
            +
                      crop = calculate_crop_region(driver_options)
         | 
| 79 69 |  | 
| 80 70 | 
             
                      if @screenshot_counter
         | 
| 81 71 | 
             
                        name = "#{format("%02i", @screenshot_counter)}_#{name}"
         | 
| @@ -84,31 +74,22 @@ module Capybara | |
| 84 74 | 
             
                      name = full_name(name)
         | 
| 85 75 | 
             
                      file_name = "#{Screenshot.screenshot_area_abs}/#{name}.png"
         | 
| 86 76 |  | 
| 87 | 
            -
                       | 
| 77 | 
            +
                      create_output_directory_for(file_name)
         | 
| 78 | 
            +
             | 
| 88 79 | 
             
                      comparison = ImageCompare.new(file_name, nil, driver_options)
         | 
| 89 | 
            -
                      checkout_vcs(name, comparison)
         | 
| 90 | 
            -
                       | 
| 91 | 
            -
                        blurred_input = prepare_page_for_screenshot(timeout: wait)
         | 
| 92 | 
            -
                        if stability_time_limit
         | 
| 93 | 
            -
                          take_stable_screenshot(comparison, stability_time_limit: stability_time_limit, wait: wait, crop: crop)
         | 
| 94 | 
            -
                        else
         | 
| 95 | 
            -
                          take_right_size_screenshot(comparison, crop: crop)
         | 
| 96 | 
            -
                        end
         | 
| 97 | 
            -
                      ensure
         | 
| 98 | 
            -
                        blurred_input&.click
         | 
| 99 | 
            -
                      end
         | 
| 80 | 
            +
                      checkout_vcs(name, comparison.old_file_name, comparison.new_file_name)
         | 
| 81 | 
            +
                      take_screenshot(comparison, crop, stability_time_limit, wait)
         | 
| 100 82 |  | 
| 101 83 | 
             
                      return false unless comparison.old_file_exists?
         | 
| 102 84 |  | 
| 103 | 
            -
                       | 
| 85 | 
            +
                      # Allow nil or single or multiple areas
         | 
| 86 | 
            +
                      if driver_options[:skip_area]
         | 
| 87 | 
            +
                        comparison.skip_area = calculate_skip_area(driver_options[:skip_area], crop)
         | 
| 88 | 
            +
                      end
         | 
| 104 89 |  | 
| 105 | 
            -
                       | 
| 106 | 
            -
                    end
         | 
| 90 | 
            +
                      (@test_screenshots ||= []) << [caller[skip_stack_frames], name, comparison]
         | 
| 107 91 |  | 
| 108 | 
            -
             | 
| 109 | 
            -
                      selenium? && Screenshot.window_size &&
         | 
| 110 | 
            -
                        page.driver.browser.manage.window.size !=
         | 
| 111 | 
            -
                          ::Selenium::WebDriver::Dimension.new(*Screenshot.window_size)
         | 
| 92 | 
            +
                      true
         | 
| 112 93 | 
             
                    end
         | 
| 113 94 |  | 
| 114 95 | 
             
                    def assert_image_not_changed(caller, name, comparison)
         | 
| @@ -116,6 +97,58 @@ module Capybara | |
| 116 97 |  | 
| 117 98 | 
             
                      "Screenshot does not match for '#{name}' #{comparison.error_message}\nat #{caller}"
         | 
| 118 99 | 
             
                    end
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                    private
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                    def calculate_crop_region(driver_options)
         | 
| 104 | 
            +
                      crop_coordinates = driver_options.delete(:crop)
         | 
| 105 | 
            +
                      return nil unless crop_coordinates
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                      crop_coordinates = bounds_for_css(crop_coordinates).first if crop_coordinates.is_a?(String)
         | 
| 108 | 
            +
                      Region.from_edge_coordinates(*crop_coordinates)
         | 
| 109 | 
            +
                    end
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                    def create_output_directory_for(file_name)
         | 
| 112 | 
            +
                      FileUtils.mkdir_p File.dirname(file_name)
         | 
| 113 | 
            +
                    end
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                    def take_screenshot(comparison, crop, stability_time_limit, wait)
         | 
| 116 | 
            +
                      blurred_input = prepare_page_for_screenshot(timeout: wait)
         | 
| 117 | 
            +
                      if stability_time_limit
         | 
| 118 | 
            +
                        take_stable_screenshot(
         | 
| 119 | 
            +
                          comparison,
         | 
| 120 | 
            +
                          crop: crop,
         | 
| 121 | 
            +
                          stability_time_limit: stability_time_limit,
         | 
| 122 | 
            +
                          wait: wait
         | 
| 123 | 
            +
                        )
         | 
| 124 | 
            +
                      else
         | 
| 125 | 
            +
                        take_right_size_screenshot(comparison, crop: crop)
         | 
| 126 | 
            +
                      end
         | 
| 127 | 
            +
                    ensure
         | 
| 128 | 
            +
                      blurred_input&.click
         | 
| 129 | 
            +
                    end
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                    def calculate_skip_area(skip_area, crop)
         | 
| 132 | 
            +
                      crop_region = crop && Region.new(*crop)
         | 
| 133 | 
            +
                      skip_area = Array(skip_area)
         | 
| 134 | 
            +
             | 
| 135 | 
            +
                      css_selectors, regions = skip_area.compact.partition { |region| region.is_a? String }
         | 
| 136 | 
            +
             | 
| 137 | 
            +
                      result = []
         | 
| 138 | 
            +
                      result.concat(build_regions_for(bounds_for_css(*css_selectors))) unless css_selectors.empty?
         | 
| 139 | 
            +
                      result.concat(build_regions_for(regions.flatten&.each_slice(4))) unless regions.empty?
         | 
| 140 | 
            +
                      result.compact!
         | 
| 141 | 
            +
             | 
| 142 | 
            +
                      result.map! { |region| crop_region.find_relative_intersect(region) } if crop_region
         | 
| 143 | 
            +
             | 
| 144 | 
            +
                      result
         | 
| 145 | 
            +
                    end
         | 
| 146 | 
            +
             | 
| 147 | 
            +
                    def build_regions_for(coordinates)
         | 
| 148 | 
            +
                      coordinates.map do |region_coordinates|
         | 
| 149 | 
            +
                        Region.from_edge_coordinates(*region_coordinates)
         | 
| 150 | 
            +
                      end
         | 
| 151 | 
            +
                    end
         | 
| 119 152 | 
             
                  end
         | 
| 120 153 | 
             
                end
         | 
| 121 154 | 
             
              end
         | 
| @@ -18,22 +18,23 @@ module Capybara | |
| 18 18 | 
             
                      FileUtils.rm_f(target_file_name) unless $CHILD_STATUS == 0
         | 
| 19 19 | 
             
                    end
         | 
| 20 20 |  | 
| 21 | 
            -
                    def checkout_vcs(name,  | 
| 21 | 
            +
                    def checkout_vcs(name, old_file_name, new_file_name)
         | 
| 22 22 | 
             
                      svn_file_name = "#{Capybara::Screenshot.screenshot_area_abs}/.svn/text-base/#{name}.png.svn-base"
         | 
| 23 | 
            +
             | 
| 23 24 | 
             
                      if File.exist?(svn_file_name)
         | 
| 24 25 | 
             
                        committed_file_name = svn_file_name
         | 
| 25 | 
            -
                        FileUtils.cp committed_file_name,  | 
| 26 | 
            +
                        FileUtils.cp committed_file_name, old_file_name
         | 
| 26 27 | 
             
                      else
         | 
| 27 | 
            -
                        svn_info = `svn info #{ | 
| 28 | 
            +
                        svn_info = `svn info #{new_file_name} #{SILENCE_ERRORS}`
         | 
| 28 29 | 
             
                        if svn_info.present?
         | 
| 29 30 | 
             
                          wc_root = svn_info.slice(/(?<=Working Copy Root Path: ).*$/)
         | 
| 30 31 | 
             
                          checksum = svn_info.slice(/(?<=Checksum: ).*$/)
         | 
| 31 32 | 
             
                          if checksum
         | 
| 32 33 | 
             
                            committed_file_name = "#{wc_root}/.svn/pristine/#{checksum[0..1]}/#{checksum}.svn-base"
         | 
| 33 | 
            -
                            FileUtils.cp committed_file_name,  | 
| 34 | 
            +
                            FileUtils.cp committed_file_name, old_file_name
         | 
| 34 35 | 
             
                          end
         | 
| 35 36 | 
             
                        else
         | 
| 36 | 
            -
                          restore_git_revision(name,  | 
| 37 | 
            +
                          restore_git_revision(name, old_file_name)
         | 
| 37 38 | 
             
                        end
         | 
| 38 39 | 
             
                      end
         | 
| 39 40 | 
             
                    end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: capybara-screenshot-diff
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 1. | 
| 4 | 
            +
              version: 1.7.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Uwe Kubosch
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2022- | 
| 11 | 
            +
            date: 2022-09-27 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: actionpack
         | 
| @@ -16,7 +16,7 @@ dependencies: | |
| 16 16 | 
             
                requirements:
         | 
| 17 17 | 
             
                - - ">="
         | 
| 18 18 | 
             
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            -
                    version: ' | 
| 19 | 
            +
                    version: '6.0'
         | 
| 20 20 | 
             
                - - "<"
         | 
| 21 21 | 
             
                  - !ruby/object:Gem::Version
         | 
| 22 22 | 
             
                    version: '8'
         | 
| @@ -26,7 +26,7 @@ dependencies: | |
| 26 26 | 
             
                requirements:
         | 
| 27 27 | 
             
                - - ">="
         | 
| 28 28 | 
             
                  - !ruby/object:Gem::Version
         | 
| 29 | 
            -
                    version: ' | 
| 29 | 
            +
                    version: '6.0'
         | 
| 30 30 | 
             
                - - "<"
         | 
| 31 31 | 
             
                  - !ruby/object:Gem::Version
         | 
| 32 32 | 
             
                    version: '8'
         | 
| @@ -72,6 +72,7 @@ extensions: [] | |
| 72 72 | 
             
            extra_rdoc_files: []
         | 
| 73 73 | 
             
            files:
         | 
| 74 74 | 
             
            - ".gitattributes"
         | 
| 75 | 
            +
            - ".github/dependabot.yml"
         | 
| 75 76 | 
             
            - ".github/workflows/lint.yml"
         | 
| 76 77 | 
             
            - ".github/workflows/test.yml"
         | 
| 77 78 | 
             
            - ".gitignore"
         | 
| @@ -88,18 +89,19 @@ files: | |
| 88 89 | 
             
            - bin/setup
         | 
| 89 90 | 
             
            - bin/standardrb
         | 
| 90 91 | 
             
            - capybara-screenshot-diff.gemspec
         | 
| 91 | 
            -
            - gemfiles/rails52.gemfile
         | 
| 92 92 | 
             
            - gemfiles/rails60_gems.rb
         | 
| 93 93 | 
             
            - gemfiles/rails61_gems.rb
         | 
| 94 94 | 
             
            - gemfiles/rails70_gems.rb
         | 
| 95 95 | 
             
            - gems.rb
         | 
| 96 96 | 
             
            - lib/capybara-screenshot-diff.rb
         | 
| 97 97 | 
             
            - lib/capybara/screenshot/diff.rb
         | 
| 98 | 
            +
            - lib/capybara/screenshot/diff/browser_helpers.rb
         | 
| 98 99 | 
             
            - lib/capybara/screenshot/diff/drivers/chunky_png_driver.rb
         | 
| 99 100 | 
             
            - lib/capybara/screenshot/diff/drivers/utils.rb
         | 
| 100 101 | 
             
            - lib/capybara/screenshot/diff/drivers/vips_driver.rb
         | 
| 101 102 | 
             
            - lib/capybara/screenshot/diff/image_compare.rb
         | 
| 102 103 | 
             
            - lib/capybara/screenshot/diff/os.rb
         | 
| 104 | 
            +
            - lib/capybara/screenshot/diff/region.rb
         | 
| 103 105 | 
             
            - lib/capybara/screenshot/diff/stabilization.rb
         | 
| 104 106 | 
             
            - lib/capybara/screenshot/diff/test_methods.rb
         | 
| 105 107 | 
             
            - lib/capybara/screenshot/diff/vcs.rb
         | 
| @@ -118,7 +120,7 @@ required_ruby_version: !ruby/object:Gem::Requirement | |
| 118 120 | 
             
              requirements:
         | 
| 119 121 | 
             
              - - ">="
         | 
| 120 122 | 
             
                - !ruby/object:Gem::Version
         | 
| 121 | 
            -
                  version: 2. | 
| 123 | 
            +
                  version: 2.7.0
         | 
| 122 124 | 
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 123 125 | 
             
              requirements:
         | 
| 124 126 | 
             
              - - ">="
         |