capybara-screenshot-diff 1.6.3 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ecb7108c89946f6489787b491c0cd831f096d09ee656e68674887952682aee7a
4
- data.tar.gz: d41e23dae6a64663d26b586235ccc4cdc10d02a43b3fefa6a8563327cde563bd
3
+ metadata.gz: c2aaf70ea2e2737e435920bc94a4504a2d2d3fe9d92874a4f1a9ac2f66527ed1
4
+ data.tar.gz: '087a7e5e2636a56318884f7d272126e62faea68c49401e96fa40a4a0d43bfb8b'
5
5
  SHA512:
6
- metadata.gz: 89501dc8c7ab1b540d182dacd10f8bf2d3b24521851db20bed42eb7c066b484d5a5cfbc766a4a0d5c80539500c1eef342f55be4069da455ba1d2ba14524d2463
7
- data.tar.gz: 12c02e086af0df03206eaa5ac332306b0b199c33d70b6393c64a60a70a5777e4598b4aedf67afc0a6aa06166247efd7e6a0c21652aa4c2587e13009566363b87
6
+ metadata.gz: 7c636d231583f4b3df1404aff861ef94000752e8b07edc829e2c16d56e34e2ba7418849c7e875a9e625832a6b8259f854c3ff3e0883c20d5942350d34181bc7d
7
+ data.tar.gz: f706ccc8937cd86a53b0a0dd04cb2429e77d4ef1ac643b898ce7bc08c4b623c976ce3f402136fccf0851c99509ec346102a48ef724a4711f70e73e438cf2a973
@@ -0,0 +1,8 @@
1
+ ---
2
+ version: 2
3
+
4
+ updates:
5
+ - package-ecosystem: "github-actions"
6
+ directory: "/"
7
+ schedule:
8
+ interval: "weekly"
@@ -13,7 +13,7 @@ jobs:
13
13
 
14
14
  steps:
15
15
  - name: Checkout code
16
- uses: actions/checkout@v2
16
+ uses: actions/checkout@v3
17
17
 
18
18
  - name: Set up Ruby
19
19
  uses: ruby/setup-ruby@v1
@@ -14,19 +14,24 @@ env:
14
14
  FERRUM_PROCESS_TIMEOUT: '15'
15
15
  WD_CACHE_TIME: '864000' # 10 days
16
16
 
17
+ concurrency:
18
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
19
+ cancel-in-progress: true
20
+
17
21
  jobs:
18
22
  test:
19
23
  name: Functional Testing
20
- runs-on: ubuntu-20.04 # In order to install libvips 8.9+ version
24
+ runs-on: ubuntu-22.04 # In order to install libvips 8.9+ version
25
+ timeout-minutes: 5
21
26
 
22
27
  steps:
23
28
  - name: Checkout code
24
- uses: actions/checkout@v2
29
+ uses: actions/checkout@v3
25
30
 
26
31
  - name: Set up Ruby
27
32
  uses: ruby/setup-ruby@v1
28
33
  with:
29
- ruby-version: '3.0'
34
+ ruby-version: '3.1'
30
35
  bundler-cache: true
31
36
 
32
37
  - name: Install libvips
@@ -38,42 +43,44 @@ jobs:
38
43
  COVERAGE: enabled
39
44
 
40
45
  - name: Upload Screenshots
41
- if: ${{ always() }}
42
- uses: actions/upload-artifact@v2
46
+ if: always()
47
+ uses: actions/upload-artifact@v3
43
48
  with:
44
- path: test/fixtures/app/doc/screenshots/
49
+ name: screenshots
50
+ retention-days: 1
51
+ path: |
52
+ test/fixtures/app/doc/screenshots/
53
+ tmp/capybara/screenshots-diffs/
45
54
 
46
55
  - name: Upload Coverage
47
- uses: actions/upload-artifact@v2
56
+ uses: actions/upload-artifact@v3
48
57
  with:
49
58
  name: coverage
59
+ retention-days: 1
50
60
  path: coverage
51
61
 
52
62
  matrix:
53
63
  name: Test Integration Rails & Ruby
54
64
  needs: [ 'test' ]
55
65
  runs-on: ubuntu-20.04
66
+ timeout-minutes: 5
56
67
 
57
68
  strategy:
58
69
  matrix:
59
- ruby-version: [ '3.1', '3.0', '2.7', '2.6', 'jruby' ]
70
+ ruby-version: [ '3.1', '3.0', '2.7', 'jruby' ]
60
71
  gemfile:
72
+ - 'rails70_gems.rb'
61
73
  - 'rails61_gems.rb'
62
74
  - 'rails60_gems.rb'
63
- - 'rails52.gemfile'
64
- include:
65
- - ruby-version: 2.7
66
- gemfile: rails70_gems.rb
67
- - ruby-version: 3.0
68
- gemfile: rails70_gems.rb
69
- - ruby-version: 3.1
70
- gemfile: rails70_gems.rb
75
+ exclude:
76
+ - ruby-version: 'jruby'
77
+ gemfile: 'rails70_gems.rb'
71
78
  env:
72
79
  BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }}
73
80
 
74
81
  steps:
75
82
  - name: Checkout code
76
- uses: actions/checkout@v2
83
+ uses: actions/checkout@v3
77
84
 
78
85
  - name: Set up Ruby
79
86
  uses: ruby/setup-ruby@v1
@@ -91,6 +98,7 @@ jobs:
91
98
  name: Test Integration Capybara & Image Drivers
92
99
  needs: [ 'test' ]
93
100
  runs-on: ubuntu-20.04
101
+ timeout-minutes: 5
94
102
 
95
103
  strategy:
96
104
  matrix:
@@ -102,7 +110,7 @@ jobs:
102
110
 
103
111
  steps:
104
112
  - name: Checkout code
105
- uses: actions/checkout@v2
113
+ uses: actions/checkout@v3
106
114
 
107
115
  - name: Set up Ruby
108
116
  uses: ruby/setup-ruby@v1
@@ -118,3 +126,13 @@ jobs:
118
126
  env:
119
127
  SCREENSHOT_DRIVER: ${{ matrix.screenshot-driver }}
120
128
  CAPYBARA_DRIVER: ${{ matrix.capybara-driver }}
129
+
130
+ - name: Upload Screenshots
131
+ uses: actions/upload-artifact@v3
132
+ if: failure()
133
+ with:
134
+ name: screenshots-${{ matrix.screenshot-driver }}-${{ matrix.capybara-driver }}
135
+ retention-days: 1
136
+ path: |
137
+ test/fixtures/app/doc/screenshots/
138
+ tmp/capybara/screenshots-diffs/
data/.gitignore CHANGED
@@ -10,3 +10,5 @@
10
10
  /pkg/
11
11
  /spec/reports/
12
12
  /tmp/
13
+ /test/fixtures/**/*.committed.png
14
+ /test/fixtures/**/*.latest.png
data/CONTRIBUTING.md CHANGED
@@ -19,4 +19,6 @@ Run the tests for a matrix of configurations of Ruby implementations and Rails v
19
19
 
20
20
  ## Merging to master
21
21
 
22
- Before merging to master, please have a member of the project review your changes, and make sure the tests are green in travis-ci.
22
+ Before merging to `master`,
23
+ please have a member of the project review your changes,
24
+ and make sure the tests are green.
data/Dockerfile CHANGED
@@ -3,9 +3,7 @@
3
3
  # $ docker build . -t csd
4
4
  # $ docker run -v $(pwd):/app -ti csd rake test
5
5
 
6
- ARG RUBY_VERSION=2.7.2
7
-
8
- FROM circleci/ruby:2.7.2-node-browsers
6
+ FROM jetthoughts/cimg-ruby:3.1-chrome
9
7
 
10
8
  RUN \
11
9
  # Install dependencies
@@ -47,6 +45,7 @@ RUN sudo /app/bin/install-vips
47
45
  ADD ./lib/capybara/screenshot/diff/version.rb /app/lib/capybara/screenshot/diff/
48
46
  ADD ./capybara-screenshot-diff.gemspec /app/
49
47
  ADD ./gems.rb /app/
48
+ ADD ./Rakefile /app/
50
49
 
51
50
  RUN bundle install
52
51
 
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- [![Build Status](https://travis-ci.org/donv/capybara-screenshot-diff.svg?branch=master)](https://travis-ci.org/donv/capybara-screenshot-diff)
1
+ [![Test](https://github.com/donv/capybara-screenshot-diff/actions/workflows/test.yml/badge.svg)](https://github.com/donv/capybara-screenshot-diff/actions/workflows/test.yml)
2
2
 
3
3
  # Capybara::Screenshot::Diff
4
4
 
@@ -40,14 +40,14 @@ In your test class, include the `Capybara::Screenshot::Diff` module:
40
40
  ```ruby
41
41
  class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
42
42
  include Capybara::Screenshot::Diff
43
- ...
43
+ # ...
44
44
  end
45
45
  ```
46
46
 
47
- ### rspec
47
+ ### RSpec
48
48
 
49
49
  ```ruby
50
- describe 'Permissions admin', :type => :feature, :js => true do
50
+ describe 'Permissions admin', type: :feature, js: true do
51
51
 
52
52
  include Capybara::Screenshot::Diff
53
53
 
@@ -64,7 +64,7 @@ But it's better to include it within your *_helper.rb file so that it can used a
64
64
  require 'capybara/screenshot/diff'
65
65
 
66
66
  RSpec.configure do |config|
67
- config.include Capybara::Screenshot::Diff::TestMethods
67
+ config.include Capybara::Screenshot::Diff
68
68
  end
69
69
  ```
70
70
 
@@ -97,8 +97,8 @@ doc
97
97
  ```
98
98
 
99
99
  To store the screen shot history, add the `doc/screenshots` directory to your
100
- version control system (git, svn, etc).
101
-
100
+ version control system (git, svn, etc).
101
+
102
102
  Screen shots are compared to the previously COMMITTED version of the same screen shot.
103
103
 
104
104
  ### Screenshot groups
@@ -186,20 +186,14 @@ end
186
186
  test.
187
187
 
188
188
 
189
-
190
189
  ### Capturing one area instead of the whole page
191
190
 
191
+ You can crop images before comparison to be run, by providing region to crop as `[left, top, right, bottom]` or by css selector like `body .tag`
192
+
192
193
  ```ruby
193
194
  test 'the cool' do
194
195
  visit '/feature'
195
- screenshot 'cool_element', crop: bounds('#my_element')
196
- end
197
-
198
- private
199
-
200
- def bounds(selector)
201
- element = evaluate_script("document.querySelector('#{selector}').getBoundingClientRect()")
202
- [element['left'], element['top'], element['right'], element['bottom']]
196
+ screenshot 'cool_element', crop: '#my_element'
203
197
  end
204
198
  ```
205
199
 
@@ -305,7 +299,7 @@ Capybara::Screenshot::Diff.enabled = ENV['COMPARE_SCREENSHOTS']
305
299
 
306
300
  By default, `Capybara::Screenshot::Diff` saves screenshots to a
307
301
  `doc/screenshots` folder, relative to either `Rails.root` (if you're in Rails),
308
- or your current directory otherwise.
302
+ or your current directory otherwise.
309
303
 
310
304
  If you want to change where screenshots are saved to, then there are two
311
305
  configuration options that that are relevant.
@@ -370,7 +364,6 @@ Capybara::Screenshot.hide_caret = true
370
364
  This will make the cursor (caret) transparent (invisible), so the blinking does not delay the screen shot.
371
365
 
372
366
 
373
-
374
367
  ### Removing focus from the active element
375
368
 
376
369
  Another way to avoid the cursor blinking is to set the `blur_active_element` option:
@@ -428,7 +421,7 @@ Capybara::Screenshot::Diff.shift_distance_limit = 1
428
421
  this will impact performance **severely** if a match cannot be found.
429
422
 
430
423
  If `shift_distance_limit` is `nil` shift distance is not measured. If `shift_distance_limit` is set,
431
- even to `0`, shift distabnce is measured and reported on image differences.
424
+ even to `0`, shift distance is measured and reported on image differences.
432
425
 
433
426
  ### Allowed difference size
434
427
 
@@ -452,25 +445,26 @@ Capybara::Screenshot::Diff.area_size_limit = 42
452
445
  ### Skipping an area
453
446
 
454
447
  Sometimes you have expected change that you want to ignore.
455
- You can use the `skip_area` option to the `screenshot` method to ignore an area:
448
+ You can use the `skip_area` option with `[left, top, right, bottom]`
449
+ or css selector like `'#footer'` or `'.container .skipped_element'` to the `screenshot` method to ignore an area:
456
450
 
457
451
  ```ruby
458
452
  test 'unstable area' do
459
453
  visit '/'
460
- screenshot 'index', skip_area: [17, 6, 27, 16]
454
+ screenshot 'index', skip_area: [[17, 6, 27, 16], '.container .skipped_element', '#footer']
461
455
  end
462
456
  ```
463
457
 
464
- The arguments are [x1, y1, x2, y2] for the area you want to ignore. You can also set this globally:
458
+ The arguments are `[left, top, right, bottom]` for the area you want to ignore. You can also set this globally:
465
459
 
466
460
  ```ruby
467
461
  Capybara::Screenshot::Diff.skip_area = [0, 0, 64, 48]
468
462
  ```
469
463
 
470
- If you need to ignore multiple areas, you can supply an array of arrays:
464
+ If you need to ignore multiple areas:
471
465
 
472
466
  ```ruby
473
- screenshot 'index', skip_area: [[0, 0, 64, 48], [17, 6, 27, 16]]
467
+ screenshot 'index', skip_area: [[0, 0, 64, 48], [17, 6, 27, 16], 'css_selector .element']
474
468
  ```
475
469
 
476
470
  ### Available Image Processing Drivers
@@ -479,7 +473,7 @@ There are several image processing supported by this gem.
479
473
  There are several options to setup active driver: `:auto`, `:chunky_png` and `:vips`.
480
474
 
481
475
  * `:auto` - will try to load `:vips` if there is gem `ruby-vips`, in other cases will load `:chunky_png`
482
- * `:chunky_png` and `:vips` will load correspondent driver
476
+ * `:chunky_png` and `:vips` will load correspondent driver
483
477
 
484
478
  ### Enable VIPS image processing
485
479
 
@@ -488,8 +482,8 @@ and could be enabled by adding `ruby-vips` to `Gemfile`.
488
482
 
489
483
  If need to setup explicitly Vips driver, there are several ways to do this:
490
484
 
491
- * Globally: `Capybara::Screenshot::Diff.driver = :vips`
492
- * Per screenshot option: `screenshot 'index', driver: :vips`
485
+ * Globally: `Capybara::Screenshot::Diff.driver = :vips`
486
+ * Per screenshot option: `screenshot 'index', driver: :vips`
493
487
 
494
488
  With enabled VIPS there are new alternatives to process differences, which easier to find and support.
495
489
  For example, `shift_distance_limit` is very heavy operation. Instead better to use `median_filter_window_size`.
@@ -532,6 +526,24 @@ test 'unstable area' do
532
526
  end
533
527
  ```
534
528
 
529
+ ### Skipping stack frames in the error output
530
+
531
+ If you would like to override the `screenshot` method or for some other reason would like to skip stack
532
+ frames when reporting image differences, you can use the `skip_stack_frames` option:
533
+
534
+ ```ruby
535
+ test 'test visiting the index' do
536
+ visit root_path
537
+ screenshot :index
538
+ end
539
+
540
+ private
541
+
542
+ def screenshot(name, **options)
543
+ super(name, skip_stack_frames: 1, **options)
544
+ end
545
+ ```
546
+
535
547
  ## Development
536
548
 
537
549
  After checking out the repo, run `bin/setup` to install dependencies.
data/bin/install-vips CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  set -e
4
4
 
5
- version=${VIPS_VERSION:-8.10.0}
5
+ version=${VIPS_VERSION:-8.12.2}
6
6
 
7
7
  wget "https://github.com/libvips/libvips/releases/download/v$version/vips-$version.tar.gz"
8
8
  tar xf "vips-$version.tar.gz"
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
12
12
  spec.summary = "Track your GUI changes with diff assertions"
13
13
  spec.description = "Save screen shots and track changes with graphical diff"
14
14
  spec.homepage = "https://github.com/donv/capybara-screenshot-diff"
15
- spec.required_ruby_version = ">= 2.5.0"
15
+ spec.required_ruby_version = defined?(JRUBY_VERSION) ? ">= 2.6.0" : ">= 2.7.0"
16
16
  spec.license = "MIT"
17
17
  spec.metadata["allowed_push_host"] = "https://rubygems.org/"
18
18
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
20
20
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
21
  spec.require_paths = ["lib"]
22
22
 
23
- spec.add_runtime_dependency "actionpack", ">= 4.2", "< 8"
23
+ spec.add_runtime_dependency "actionpack", ">= 6.0", "< 8"
24
24
  spec.add_runtime_dependency "capybara", ">= 2", "< 4"
25
25
  spec.add_runtime_dependency "chunky_png", "~> 1.3"
26
26
  end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "region"
4
+
5
+ module Capybara
6
+ module Screenshot
7
+ module BrowserHelpers
8
+ def current_capybara_driver_class
9
+ Capybara.current_session.driver.class
10
+ end
11
+
12
+ def selenium?
13
+ current_capybara_driver_class <= Capybara::Selenium::Driver
14
+ end
15
+
16
+ def window_size_is_wrong?
17
+ selenium? &&
18
+ Screenshot.window_size &&
19
+ page.driver.browser.manage.window.size != ::Selenium::WebDriver::Dimension.new(*Screenshot.window_size)
20
+ end
21
+
22
+ def rect_for(css_selector)
23
+ all_visible_regions_for(css_selector).first
24
+ end
25
+
26
+ def bounds_for_css(*css_selectors)
27
+ css_selectors.reduce([]) do |regions, selector|
28
+ regions.concat(all_visible_regions_for(selector))
29
+ end
30
+ end
31
+
32
+ IMAGE_WAIT_SCRIPT = <<~JS
33
+ function pending_image() {
34
+ var images = document.images;
35
+ for (var i = 0; i < images.length; i++) {
36
+ if (!images[i].complete) {
37
+ return images[i].src;
38
+ }
39
+ }
40
+ return false;
41
+ }()
42
+ JS
43
+
44
+ def pending_image_to_load
45
+ evaluate_script IMAGE_WAIT_SCRIPT
46
+ end
47
+
48
+ HIDE_CARET_SCRIPT = <<~JS
49
+ if (!document.getElementById('csdHideCaretStyle')) {
50
+ let style = document.createElement('style');
51
+ style.setAttribute('id', 'csdHideCaretStyle');
52
+ document.head.appendChild(style);
53
+ let styleSheet = style.sheet;
54
+ styleSheet.insertRule("* { caret-color: transparent !important; }", 0);
55
+ }
56
+ JS
57
+
58
+ def hide_caret
59
+ execute_script(HIDE_CARET_SCRIPT)
60
+ end
61
+
62
+ FIND_ACTIVE_ELEMENT_SCRIPT = <<~JS
63
+ function activeElement(){
64
+ const ae = document.activeElement;
65
+ if (ae.nodeName === "INPUT" || ae.nodeName === "TEXTAREA") {
66
+ ae.blur();
67
+ return ae;
68
+ }
69
+ return null;
70
+ }();
71
+ JS
72
+
73
+ def blur_from_focused_element
74
+ page.evaluate_script(FIND_ACTIVE_ELEMENT_SCRIPT)
75
+ end
76
+
77
+ GET_BOUNDING_CLIENT_RECT_SCRIPT = <<~JS
78
+ [
79
+ this.getBoundingClientRect().left,
80
+ this.getBoundingClientRect().top,
81
+ this.getBoundingClientRect().right,
82
+ this.getBoundingClientRect().bottom
83
+ ]
84
+ JS
85
+
86
+ def all_visible_regions_for(selector)
87
+ all(selector, visible: true).map(&method(:region_for))
88
+ end
89
+
90
+ def region_for(element)
91
+ element.evaluate_script(GET_BOUNDING_CLIENT_RECT_SCRIPT).map { |point| point.negative? ? 0 : point.to_i }
92
+ end
93
+
94
+ private
95
+
96
+ def create_output_directory_for(file_name)
97
+ FileUtils.mkdir_p File.dirname(file_name)
98
+ end
99
+ end
100
+ end
101
+ end
@@ -12,6 +12,7 @@ module Capybara
12
12
  include ChunkyPNG::Color
13
13
 
14
14
  attr_reader :new_file_name, :old_file_name
15
+ attr_accessor :skip_area, :color_distance_limit, :shift_distance_limit
15
16
 
16
17
  def initialize(new_file_name, old_file_name = nil, options = {})
17
18
  options = old_file_name if old_file_name.is_a?(Hash)
@@ -69,7 +70,7 @@ module Capybara
69
70
  return nil, nil if new_image.pixels == old_image.pixels
70
71
 
71
72
  if fast_fail && !(color_distance_limit || shift_distance_limit || area_size_limit)
72
- return [0, 0, width_for(new_image), height_for(new_image)], nil
73
+ return build_region_for_whole_image(new_image), nil
73
74
  end
74
75
 
75
76
  region = find_top(old_image, new_image)
@@ -90,12 +91,6 @@ module Capybara
90
91
  image.width
91
92
  end
92
93
 
93
- def size(region)
94
- return 0 unless region
95
-
96
- (region[2] - region[0] + 1) * (region[3] - region[1] + 1)
97
- end
98
-
99
94
  def max_color_distance
100
95
  calculate_metrics unless @max_color_distance
101
96
  @max_color_distance
@@ -114,8 +109,8 @@ module Capybara
114
109
  log.merge!(max_shift_distance: max_shift_distance) if max_shift_distance
115
110
  end
116
111
 
117
- def crop(dimensions, i)
118
- i.crop(*dimensions)
112
+ def crop(region, i)
113
+ i.crop(*region.to_top_left_corner_coordinates)
119
114
  end
120
115
 
121
116
  def from_file(filename)
@@ -183,20 +178,29 @@ module Capybara
183
178
  true
184
179
  end
185
180
 
186
- def draw_rectangles(images, (left, top, right, bottom), (r, g, b))
181
+ def draw_rectangles(images, region, (r, g, b))
182
+ border_color = ChunkyPNG::Color.rgb(r, g, b)
183
+ border_shadow = ChunkyPNG::Color.rgba(r, g, b, 100)
184
+
187
185
  images.map do |image|
188
186
  new_img = image.dup
189
- new_img.rect(left - 1, top - 1, right + 1, bottom + 1, ChunkyPNG::Color.rgb(r, g, b))
187
+ new_img.rect(region.left - 1, region.top - 1, region.right + 1, region.bottom + 1, border_color)
188
+ new_img.rect(region.left, region.top, region.right, region.bottom, border_shadow)
190
189
  new_img
191
190
  end
192
191
  end
193
192
 
194
193
  private
195
194
 
196
- def find_diff_rectangle(org_img, new_img, region)
197
- left, top, right, bottom = find_left_right_and_top(org_img, new_img, region)
195
+ def build_region_for_whole_image(new_image)
196
+ Region.from_edge_coordinates(0, 0, width_for(new_image), height_for(new_image))
197
+ end
198
+
199
+ def find_diff_rectangle(org_img, new_img, area_coordinates)
200
+ left, top, right, bottom = find_left_right_and_top(org_img, new_img, area_coordinates)
198
201
  bottom = find_bottom(org_img, new_img, left, right, bottom)
199
- [left, top, right, bottom]
202
+
203
+ Region.from_edge_coordinates(left, top, right, bottom)
200
204
  end
201
205
 
202
206
  def find_top(old_img, new_img)
@@ -209,10 +213,13 @@ module Capybara
209
213
  end
210
214
 
211
215
  def find_left_right_and_top(old_img, new_img, region)
216
+ region = region.is_a?(Region) ? region.to_edge_coordinates : region
217
+
212
218
  left = region[0] || old_img.width - 1
213
219
  top = region[1]
214
220
  right = region[2] || 0
215
221
  bottom = region[3]
222
+
216
223
  old_img.height.times do |y|
217
224
  (0...left).find do |x|
218
225
  next if same_color?(old_img, new_img, x, y)
@@ -230,6 +237,7 @@ module Capybara
230
237
  end
231
238
  end
232
239
  end
240
+
233
241
  [left, top, right, bottom]
234
242
  end
235
243
 
@@ -241,13 +249,12 @@ module Capybara
241
249
  end
242
250
  end
243
251
  end
252
+
244
253
  bottom
245
254
  end
246
255
 
247
256
  def same_color?(old_img, new_img, x, y)
248
- @skip_area&.each do |skip_start_x, skip_start_y, skip_end_x, skip_end_y|
249
- return true if skip_start_x <= x && x <= skip_end_x && skip_start_y <= y && y <= skip_end_y
250
- end
257
+ return true if skipped_region?(x, y)
251
258
 
252
259
  color_distance =
253
260
  color_distance_at(new_img, old_img, x, y, shift_distance_limit: @shift_distance_limit)
@@ -266,6 +273,12 @@ module Capybara
266
273
  color_matches
267
274
  end
268
275
 
276
+ def skipped_region?(x, y)
277
+ return false unless @skip_area
278
+
279
+ @skip_area.any? { |region| region.cover?(x, y) }
280
+ end
281
+
269
282
  def color_distance_at(new_img, old_img, x, y, shift_distance_limit:)
270
283
  org_color = old_img[x, y]
271
284
  if shift_distance_limit