capybara-screenshot-diff 1.6.2 → 1.8.3

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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +29 -0
  3. data/capybara-screenshot-diff.gemspec +6 -3
  4. data/gems.rb +8 -2
  5. data/lib/capybara/screenshot/diff/browser_helpers.rb +102 -0
  6. data/lib/capybara/screenshot/diff/cucumber.rb +11 -0
  7. data/lib/capybara/screenshot/diff/difference.rb +63 -0
  8. data/lib/capybara/screenshot/diff/drivers/base_driver.rb +42 -0
  9. data/lib/capybara/screenshot/diff/drivers/chunky_png_driver.rb +193 -252
  10. data/lib/capybara/screenshot/diff/drivers/utils.rb +25 -0
  11. data/lib/capybara/screenshot/diff/drivers/vips_driver.rb +65 -100
  12. data/lib/capybara/screenshot/diff/drivers.rb +16 -0
  13. data/lib/capybara/screenshot/diff/image_compare.rb +138 -154
  14. data/lib/capybara/screenshot/diff/os.rb +1 -1
  15. data/lib/capybara/screenshot/diff/region.rb +86 -0
  16. data/lib/capybara/screenshot/diff/screenshot_matcher.rb +128 -0
  17. data/lib/capybara/screenshot/diff/screenshoter.rb +136 -0
  18. data/lib/capybara/screenshot/diff/stabilization.rb +0 -210
  19. data/lib/capybara/screenshot/diff/stable_screenshoter.rb +106 -0
  20. data/lib/capybara/screenshot/diff/test_methods.rb +57 -63
  21. data/lib/capybara/screenshot/diff/vcs.rb +48 -21
  22. data/lib/capybara/screenshot/diff/version.rb +1 -1
  23. data/lib/capybara/screenshot/diff.rb +38 -35
  24. data/sig/capybara/screenshot/diff/diff.rbs +28 -0
  25. data/sig/capybara/screenshot/diff/difference.rbs +33 -0
  26. data/sig/capybara/screenshot/diff/drivers/base_driver.rbs +63 -0
  27. data/sig/capybara/screenshot/diff/drivers/browser_helpers.rbs +36 -0
  28. data/sig/capybara/screenshot/diff/drivers/chunky_png_driver.rbs +89 -0
  29. data/sig/capybara/screenshot/diff/drivers/utils.rbs +13 -0
  30. data/sig/capybara/screenshot/diff/drivers/vips_driver.rbs +25 -0
  31. data/sig/capybara/screenshot/diff/image_compare.rbs +93 -0
  32. data/sig/capybara/screenshot/diff/os.rbs +11 -0
  33. data/sig/capybara/screenshot/diff/region.rbs +43 -0
  34. data/sig/capybara/screenshot/diff/screenshot_matcher.rbs +60 -0
  35. data/sig/capybara/screenshot/diff/screenshoter.rbs +48 -0
  36. data/sig/capybara/screenshot/diff/stable_screenshoter.rbs +29 -0
  37. data/sig/capybara/screenshot/diff/test_methods.rbs +39 -0
  38. data/sig/capybara/screenshot/diff/vcs.rbs +17 -0
  39. metadata +30 -25
  40. data/.gitattributes +0 -4
  41. data/.github/workflows/lint.yml +0 -25
  42. data/.github/workflows/test.yml +0 -120
  43. data/.gitignore +0 -12
  44. data/.standard.yml +0 -12
  45. data/CONTRIBUTING.md +0 -22
  46. data/Dockerfile +0 -60
  47. data/README.md +0 -555
  48. data/bin/bundle +0 -114
  49. data/bin/console +0 -15
  50. data/bin/install-vips +0 -11
  51. data/bin/rake +0 -27
  52. data/bin/setup +0 -8
  53. data/bin/standardrb +0 -29
  54. data/gemfiles/rails52.gemfile +0 -6
  55. data/gemfiles/rails60_gems.rb +0 -8
  56. data/gemfiles/rails61_gems.rb +0 -7
  57. data/gemfiles/rails70_gems.rb +0 -7
  58. data/tmp/.keep +0 -0
@@ -5,48 +5,41 @@ require "capybara"
5
5
  require "action_controller"
6
6
  require "action_dispatch"
7
7
  require "active_support/core_ext/string/strip"
8
+ require "pathname"
9
+
10
+ require_relative "drivers"
8
11
  require_relative "image_compare"
9
- require_relative "stabilization"
10
12
  require_relative "vcs"
13
+ require_relative "browser_helpers"
14
+ require_relative "region"
15
+
16
+ require_relative "screenshot_matcher"
11
17
 
12
18
  # Add the `screenshot` method to ActionDispatch::IntegrationTest
13
19
  module Capybara
14
20
  module Screenshot
15
21
  module Diff
16
22
  module TestMethods
17
- include Stabilization
18
- include Vcs
19
-
20
23
  def initialize(*)
21
24
  super
22
25
  @screenshot_counter = nil
23
26
  @screenshot_group = nil
24
27
  @screenshot_section = nil
25
28
  @test_screenshot_errors = nil
26
- @test_screenshots = nil
29
+ @test_screenshots = []
27
30
  end
28
31
 
29
- def group_parts
30
- parts = []
31
- parts << @screenshot_section if @screenshot_section.present?
32
- parts << @screenshot_group if @screenshot_group.present?
33
- parts
34
- end
32
+ def build_full_name(name)
33
+ if @screenshot_counter
34
+ name = format("%02i_#{name}", @screenshot_counter)
35
+ @screenshot_counter += 1
36
+ end
35
37
 
36
- def full_name(name)
37
- File.join group_parts.<<(name).map(&:to_s)
38
+ File.join(*group_parts.push(name.to_s))
38
39
  end
39
40
 
40
41
  def screenshot_dir
41
- File.join [Screenshot.screenshot_area] + group_parts
42
- end
43
-
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
42
+ File.join(*([Screenshot.screenshot_area] + group_parts))
50
43
  end
51
44
 
52
45
  def screenshot_section(name)
@@ -55,66 +48,67 @@ module Capybara
55
48
 
56
49
  def screenshot_group(name)
57
50
  @screenshot_group = name.to_s
58
- @screenshot_counter = 0
51
+ @screenshot_counter = @screenshot_group.present? ? 0 : nil
59
52
  return unless Screenshot.active? && name.present?
60
53
 
61
54
  FileUtils.rm_rf screenshot_dir
62
55
  end
63
56
 
64
- # @return [Boolean] whether a screenshot was taken
65
- def screenshot(name, options = {})
57
+ def schedule_match_job(job)
58
+ (@test_screenshots ||= []) << job
59
+ true
60
+ end
61
+
62
+ def group_parts
63
+ parts = []
64
+ parts << @screenshot_section if @screenshot_section.present?
65
+ parts << @screenshot_group if @screenshot_group.present?
66
+ parts
67
+ end
68
+
69
+ def screenshot(name, skip_stack_frames: 0, **options)
66
70
  return false unless Screenshot.active?
67
- return false if window_size_is_wrong?
68
71
 
69
- driver_options = Diff.default_options.merge(options)
72
+ screenshot_full_name = build_full_name(name)
73
+ job = build_screenshot_matches_job(screenshot_full_name, options)
70
74
 
71
- stability_time_limit = driver_options[:stability_time_limit]
72
- wait = driver_options[:wait]
73
- crop = driver_options.delete(:crop)
75
+ return false unless job
74
76
 
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
77
+ job.prepend(caller[skip_stack_frames])
79
78
 
80
- if @screenshot_counter
81
- name = "#{format("%02i", @screenshot_counter)}_#{name}"
82
- @screenshot_counter += 1
83
- end
84
- name = full_name(name)
85
- file_name = "#{Screenshot.screenshot_area_abs}/#{name}.png"
86
-
87
- FileUtils.mkdir_p File.dirname(file_name)
88
- comparison = ImageCompare.new(file_name, nil, driver_options)
89
- checkout_vcs(name, comparison)
90
- begin
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)
79
+ if Screenshot::Diff.delayed
80
+ schedule_match_job(job)
81
+ else
82
+ error_msg = assert_image_not_changed(*job)
83
+ if error_msg
84
+ error = ASSERTION.new(error_msg)
85
+ error.set_backtrace(caller(2))
86
+ raise error
96
87
  end
97
- ensure
98
- blurred_input&.click
99
88
  end
89
+ end
100
90
 
101
- return false unless comparison.old_file_exists?
91
+ def assert_image_not_changed(caller, name, comparison)
92
+ result = comparison.different?
102
93
 
103
- (@test_screenshots ||= []) << [caller(1..1).first, name, comparison]
94
+ # Cleanup after comparisons
95
+ if !result && comparison.base_image_path.exist?
96
+ FileUtils.mv(comparison.base_image_path, comparison.image_path, force: true)
97
+ else
98
+ FileUtils.rm_rf(comparison.base_image_path)
99
+ end
104
100
 
105
- true
106
- end
101
+ return unless result
107
102
 
108
- def window_size_is_wrong?
109
- selenium? && Screenshot.window_size &&
110
- page.driver.browser.manage.window.size !=
111
- ::Selenium::WebDriver::Dimension.new(*Screenshot.window_size)
103
+ "Screenshot does not match for '#{name}' #{comparison.error_message}\n#{caller}"
112
104
  end
113
105
 
114
- def assert_image_not_changed(caller, name, comparison)
115
- return unless comparison.different?
106
+ private
116
107
 
117
- "Screenshot does not match for '#{name}' #{comparison.error_message}\nat #{caller}"
108
+ def build_screenshot_matches_job(screenshot_full_name, options)
109
+ ScreenshotMatcher
110
+ .new(screenshot_full_name, options)
111
+ .build_screenshot_matches_job
118
112
  end
119
113
  end
120
114
  end
@@ -1,41 +1,68 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "os"
4
+
4
5
  module Capybara
5
6
  module Screenshot
6
7
  module Diff
7
8
  module Vcs
8
9
  SILENCE_ERRORS = Os::ON_WINDOWS ? "2>nul" : "2>/dev/null"
9
10
 
10
- def restore_git_revision(name, target_file_name)
11
- redirect_target = "#{target_file_name} #{SILENCE_ERRORS}"
12
- show_command = "git show HEAD~0:./#{Capybara::Screenshot.screenshot_area}/#{name}.png"
13
- if Capybara::Screenshot.use_lfs
14
- `#{show_command} | git lfs smudge > #{redirect_target}`
11
+ def self.restore_git_revision(screenshot_path, checkout_path)
12
+ vcs_file_path = screenshot_path.relative_path_from(Screenshot.root)
13
+
14
+ redirect_target = "#{checkout_path} #{SILENCE_ERRORS}"
15
+ show_command = "git show HEAD~0:./#{vcs_file_path}"
16
+ if Screenshot.use_lfs
17
+ `#{show_command} > #{checkout_path}.tmp #{SILENCE_ERRORS}`
18
+ if $CHILD_STATUS == 0
19
+ `git lfs smudge < #{checkout_path}.tmp > #{redirect_target}`
20
+ end
21
+ File.delete "#{checkout_path}.tmp"
15
22
  else
16
23
  `#{show_command} > #{redirect_target}`
17
24
  end
18
- FileUtils.rm_f(target_file_name) unless $CHILD_STATUS == 0
25
+
26
+ if $CHILD_STATUS != 0
27
+ FileUtils.rm_f(checkout_path)
28
+ false
29
+ else
30
+ true
31
+ end
19
32
  end
20
33
 
21
- def checkout_vcs(name, comparison)
22
- svn_file_name = "#{Capybara::Screenshot.screenshot_area_abs}/.svn/text-base/#{name}.png.svn-base"
23
- if File.exist?(svn_file_name)
24
- committed_file_name = svn_file_name
25
- FileUtils.cp committed_file_name, comparison.old_file_name
34
+ def self.checkout_vcs(screenshot_path, checkout_path)
35
+ if svn?
36
+ restore_svn_revision(screenshot_path, checkout_path)
26
37
  else
27
- svn_info = `svn info #{comparison.new_file_name} #{SILENCE_ERRORS}`
28
- if svn_info.present?
29
- wc_root = svn_info.slice(/(?<=Working Copy Root Path: ).*$/)
30
- checksum = svn_info.slice(/(?<=Checksum: ).*$/)
31
- if checksum
32
- committed_file_name = "#{wc_root}/.svn/pristine/#{checksum[0..1]}/#{checksum}.svn-base"
33
- FileUtils.cp committed_file_name, comparison.old_file_name
34
- end
35
- else
36
- restore_git_revision(name, comparison.old_file_name)
38
+ restore_git_revision(screenshot_path, checkout_path)
39
+ end
40
+ end
41
+
42
+ def self.restore_svn_revision(screenshot_path, checkout_path)
43
+ committed_file_name = screenshot_path + "../.svn/text-base/" + "#{screenshot_path.basename}.svn-base"
44
+ if committed_file_name.exist?
45
+ FileUtils.cp(committed_file_name, checkout_path)
46
+ return true
47
+ end
48
+
49
+ svn_info = `svn info #{screenshot_path} #{SILENCE_ERRORS}`
50
+ if svn_info.present?
51
+ wc_root = svn_info.slice(/(?<=Working Copy Root Path: ).*$/)
52
+ checksum = svn_info.slice(/(?<=Checksum: ).*$/)
53
+
54
+ if checksum
55
+ committed_file_name = "#{wc_root}/.svn/pristine/#{checksum[0..1]}/#{checksum}.svn-base"
56
+ FileUtils.cp(committed_file_name, checkout_path)
57
+ return true
37
58
  end
38
59
  end
60
+
61
+ false
62
+ end
63
+
64
+ def self.svn?
65
+ (Screenshot.screenshot_area_abs / ".svn").exist?
39
66
  end
40
67
  end
41
68
  end
@@ -3,7 +3,7 @@
3
3
  module Capybara
4
4
  module Screenshot
5
5
  module Diff
6
- VERSION = "1.6.2"
6
+ VERSION = "1.8.3"
7
7
  end
8
8
  end
9
9
  end
@@ -5,10 +5,10 @@ require "capybara/screenshot/diff/version"
5
5
  require "capybara/screenshot/diff/drivers/utils"
6
6
  require "capybara/screenshot/diff/image_compare"
7
7
  require "capybara/screenshot/diff/test_methods"
8
+ require "capybara/screenshot/diff/screenshoter"
8
9
 
9
10
  module Capybara
10
11
  module Screenshot
11
- extend Os
12
12
  mattr_accessor :add_driver_path
13
13
  mattr_accessor :add_os_path
14
14
  mattr_accessor :blur_active_element
@@ -30,10 +30,10 @@ module Capybara
30
30
  end
31
31
 
32
32
  def screenshot_area
33
- parts = [Capybara::Screenshot.save_path]
34
- parts << Capybara.current_driver.to_s if Capybara::Screenshot.add_driver_path
35
- parts << os_name if Capybara::Screenshot.add_os_path
36
- File.join parts
33
+ parts = [Screenshot.save_path]
34
+ parts << Capybara.current_driver.to_s if Screenshot.add_driver_path
35
+ parts << Os.name if Screenshot.add_os_path
36
+ File.join(*parts)
37
37
  end
38
38
 
39
39
  def screenshot_area_abs
@@ -44,23 +44,20 @@ module Capybara
44
44
  # Module to track screen shot changes
45
45
  module Diff
46
46
  include Capybara::DSL
47
- include Capybara::Screenshot::Os
48
47
 
48
+ mattr_accessor(:delayed) { true }
49
49
  mattr_accessor :area_size_limit
50
50
  mattr_accessor :color_distance_limit
51
51
  mattr_accessor(:enabled) { true }
52
52
  mattr_accessor :shift_distance_limit
53
53
  mattr_accessor :skip_area
54
54
  mattr_accessor(:driver) { :auto }
55
- mattr_accessor(:tolerance) { 0.001 }
55
+ mattr_accessor :tolerance
56
+
57
+ mattr_accessor(:screenshoter) { Screenshoter }
56
58
 
57
59
  AVAILABLE_DRIVERS = Utils.detect_available_drivers.freeze
58
- begin
59
- require "minitest"
60
- ASSERTION = Minitest::Assertion
61
- rescue
62
- ASSERTION = RuntimeError
63
- end
60
+ ASSERTION = Utils.detect_test_framework_assert
64
61
 
65
62
  def self.default_options
66
63
  {
@@ -70,7 +67,7 @@ module Capybara
70
67
  shift_distance_limit: shift_distance_limit,
71
68
  skip_area: skip_area,
72
69
  stability_time_limit: Screenshot.stability_time_limit,
73
- tolerance: tolerance,
70
+ tolerance: tolerance || ((driver == :vips) ? 0.001 : nil),
74
71
  wait: Capybara.default_max_wait_time
75
72
  }
76
73
  end
@@ -78,30 +75,36 @@ module Capybara
78
75
  def self.included(klass)
79
76
  klass.include TestMethods
80
77
  klass.setup do
81
- if Capybara::Screenshot.window_size
82
- if page.driver.respond_to?(:resize)
83
- page.driver.resize(*Capybara::Screenshot.window_size)
84
- elsif selenium?
85
- page.driver.browser.manage.window.resize_to(*Capybara::Screenshot.window_size)
86
- end
87
- end
78
+ BrowserHelpers.resize_to(Screenshot.window_size) if Screenshot.window_size
88
79
  end
89
80
 
90
81
  klass.teardown do
91
- if Capybara::Screenshot.active? && @test_screenshots
92
- test_screenshot_errors = @test_screenshots
93
- .map { |caller, name, compare| assert_image_not_changed(caller, name, compare) }
94
- @test_screenshots = nil # release the comparison objects from memory
95
- test_screenshot_errors.compact!
96
- if test_screenshot_errors.any?
97
- e = ASSERTION.new(test_screenshot_errors.join("\n\n"))
98
- e.set_backtrace(caller)
99
- if defined?(failures)
100
- failures << e
101
- else
102
- raise e
103
- end
104
- end
82
+ if Screenshot.active? && @test_screenshots.present?
83
+ track_failures(@test_screenshots)
84
+ @test_screenshots.clear
85
+ end
86
+ end
87
+ end
88
+
89
+ private
90
+
91
+ EMPTY_LINE = "\n\n"
92
+
93
+ def track_failures(screenshots)
94
+ test_screenshot_errors = screenshots.map do |caller, name, compare|
95
+ assert_image_not_changed(caller, name, compare)
96
+ end
97
+
98
+ test_screenshot_errors.compact!
99
+
100
+ unless test_screenshot_errors.empty?
101
+ error = ASSERTION.new(test_screenshot_errors.join(EMPTY_LINE))
102
+ error.set_backtrace([])
103
+
104
+ if is_a?(::Minitest::Runnable)
105
+ failures << error
106
+ else
107
+ raise error
105
108
  end
106
109
  end
107
110
  end
@@ -0,0 +1,28 @@
1
+ module Capybara
2
+ module Screenshot
3
+ def self.root=: ((String | Pathname) path) -> Pathname
4
+
5
+ def self.root: -> Pathname
6
+
7
+ def self.active?: () -> boolish
8
+
9
+ def self.screenshot_area: () -> String
10
+
11
+ def self.screenshot_area_abs: () -> Pathname
12
+
13
+ # Module to track screen shot changes
14
+ module Diff
15
+ AVAILABLE_DRIVERS: Array[(:vips | :chunky_png)]
16
+
17
+ ASSERTION: (top | RuntimeError)
18
+
19
+ def self.default_options: () -> ScreenshotMatcher::input_options
20
+
21
+ def self.included: (top klass) -> void
22
+
23
+ private
24
+
25
+ def track_failures: (Array[untyped] screenshots) -> void
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,33 @@
1
+ module Capybara
2
+ module Screenshot
3
+ module Diff
4
+ class Difference
5
+ attr_reader comparison: ImageCompare::Comparison
6
+
7
+ def different?: () -> bool
8
+
9
+ def base_image: () -> top
10
+
11
+ def options: () -> Drivers::BaseDriver::options_entity
12
+
13
+ def tolerance: () -> Numeric?
14
+
15
+ def area_size_limit: () -> Numeric?
16
+
17
+ def blank?: () -> bool
18
+
19
+ def region_area_size: () -> Numeric
20
+
21
+ def ratio: () -> Numeric?
22
+
23
+ def to_h: () -> Hash[Symbol, untyped]
24
+
25
+ def coordinates: () -> Region::raw_region_entity
26
+
27
+ def inspect: () -> String
28
+
29
+ def tolerable?: () -> bool
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,63 @@
1
+ module Capybara
2
+ module Screenshot
3
+ module Diff
4
+ module Drivers
5
+ class BaseDriver[ImageEntity]
6
+
7
+ type images_entity[out T] = [T, T]
8
+ type dimension_entity = [Numeric, Numeric]
9
+
10
+ type options_entity = {
11
+ area_size_limit?: Numeric?,
12
+ color_distance_limit?: Numeric?,
13
+ driver: (:auto | :vips | :chunky_png | VipsDriver | ChunkyPNGDriver)?,
14
+ dimensions: dimension_entity?,
15
+ median_filter_window_size: Numeric?,
16
+ shift_distance_limit?: Numeric?,
17
+ skip_area?: Array[Region]?,
18
+ stability_time_limit?: Numeric?,
19
+ tolerance?: Numeric?,
20
+ wait?: Numeric?
21
+ }
22
+
23
+ type color = [Integer, Integer, Integer, Integer]
24
+
25
+ def find_difference_region: (ImageEntity new_image, ImageEntity old_image, Numeric color_distance_limit, Numeric _shift_distance_limit, Integer _area_size_limit, ?fast_fail: bool) -> Difference
26
+
27
+ def inscribed?: (dimension_entity dimensions, ImageEntity i) -> boolish
28
+
29
+ def crop: (Region region, ImageEntity i) -> ImageEntity
30
+
31
+ def filter_image_with_median: (ImageEntity image, Numeric median_filter_window_size) -> ImageEntity
32
+
33
+ def add_black_box: (ImageEntity memo, Region region) -> void
34
+
35
+ def difference_level: (ImageEntity diff_mask, ImageEntity old_img, Region _region) -> Float
36
+
37
+ def image_area_size: (ImageEntity old_img) -> Integer
38
+
39
+ def height_for: (ImageEntity image) -> Integer
40
+
41
+ def width_for: (ImageEntity image) -> Integer
42
+
43
+ # Vips could not work with the same file. Per each process we require to create new file
44
+ def save_image_to: (ImageEntity image, String filename) -> void
45
+
46
+ def resize_image_to: (ImageEntity image, Integer new_width, Integer new_height) -> ImageEntity
47
+
48
+ def load_images: (String old_file_name, String new_file_name) -> images_entity[ImageEntity]
49
+
50
+ def from_file: (TestMethods::path_entity filename) -> ImageEntity
51
+
52
+ def dimension: (ImageEntity image) -> dimension_entity
53
+
54
+ def draw_rectangles: (images_entity[ImageEntity] images, Region region, color rgba, Integer offset) -> void
55
+
56
+ def same_pixels?: () -> boolish
57
+ end
58
+
59
+ def self.for: (ScreenshotMatcher::input_options) -> (VipsDriver | ChunkyPNGDriver)
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,36 @@
1
+ module Capybara
2
+ class Result
3
+ def map: () -> Result
4
+ end
5
+ module Screenshot
6
+ module BrowserHelpers
7
+ def self.current_capybara_driver_class: () -> top
8
+
9
+ def self.selenium?: () -> boolish?
10
+
11
+ def self.window_size_is_wrong?: () -> boolish
12
+
13
+ def self.bounds_for_css: (*String css_selectors) -> Array[Region::raw_region_entity]
14
+
15
+ IMAGE_WAIT_SCRIPT: String
16
+
17
+ def self.pending_image_to_load: () -> top?
18
+
19
+ HIDE_CARET_SCRIPT: String
20
+
21
+ def self.hide_caret: () -> void
22
+
23
+ FIND_ACTIVE_ELEMENT_SCRIPT: String
24
+
25
+ type capybara_element = top
26
+
27
+ def self.blur_from_focused_element: () -> capybara_element?
28
+
29
+ GET_BOUNDING_CLIENT_RECT_SCRIPT: String
30
+
31
+ def self.all_visible_regions_for: (String selector) -> Array[Region::raw_region_entity]
32
+
33
+ def self.region_for: (Result element) -> Region::raw_region_entity
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,89 @@
1
+ module ChunkyPNG
2
+ class Canvas
3
+ end
4
+
5
+ class Image
6
+ def self.from_blob: (String str) -> Image
7
+
8
+ def self.from_file: (String filename) -> Image
9
+ end
10
+ end
11
+
12
+ module Capybara
13
+ module Screenshot
14
+ module Diff
15
+ module Drivers
16
+ class ChunkyPNGDriver < BaseDriver[ChunkyPNG::Canvas]
17
+
18
+ def _load_images: (String old_file, String new_file) -> [ChunkyPNG::Image, ChunkyPNG::Image]
19
+
20
+ class DifferenceRegionFinder
21
+ def find_diff_rectangle: (
22
+ ChunkyPNG::Image org_img,
23
+ ChunkyPNG::Image new_img,
24
+ (Region | Region::raw_region_entity) area_coordinates,
25
+ cache: ImageCompare::cache_entity
26
+ ) -> Region?
27
+
28
+ def find_top: (
29
+ ChunkyPNG::Image old_img,
30
+ ChunkyPNG::Image new_img,
31
+ cache: ImageCompare::cache_entity
32
+ ) -> Region::raw_region_entity?
33
+
34
+ def find_left_right_and_top: (
35
+ ChunkyPNG::Image old_img,
36
+ ChunkyPNG::Image new_img,
37
+ (Region | Region::raw_region_entity) region,
38
+ cache: ImageCompare::cache_entity
39
+ ) -> Region::raw_region_entity
40
+
41
+ def find_bottom: (
42
+ ChunkyPNG::Image old_img,
43
+ ChunkyPNG::Image new_img,
44
+ Integer left,
45
+ Integer right,
46
+ Integer bottom,
47
+ cache: ImageCompare::cache_entity
48
+ ) -> Integer
49
+
50
+ def same_color?: (
51
+ ChunkyPNG::Image old_img,
52
+ ChunkyPNG::Image new_img,
53
+ Integer x,
54
+ Integer y,
55
+ ?cache: ImageCompare::cache_entity
56
+ ) -> boolish
57
+
58
+ def skipped_region?: (Integer x, Integer y) -> boolish
59
+
60
+ def color_distance_at: (
61
+ ChunkyPNG::Image new_img,
62
+ ChunkyPNG::Image old_img,
63
+ Integer x,
64
+ Integer y,
65
+ shift_distance_limit: Numeric?
66
+ ) -> Float
67
+
68
+ def shift_distance_at: (
69
+ ChunkyPNG::Image new_img,
70
+ ChunkyPNG::Image old_img,
71
+ Integer x,
72
+ Integer y,
73
+ color_distance_limit: Numeric?
74
+ ) -> Numeric
75
+
76
+ def color_matches: (
77
+ ChunkyPNG::Image new_img,
78
+ Integer org_color,
79
+ Integer x,
80
+ Integer y,
81
+ Numeric? color_distance_limit
82
+ ) -> boolish
83
+ end
84
+
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,13 @@
1
+ module Capybara
2
+ module Screenshot
3
+ module Diff
4
+ module Utils
5
+ def self.detect_available_drivers: () -> Array[(:vips | :chunky_png)]
6
+
7
+ def self.find_driver_class_for: [T] (Symbol driver) -> T
8
+
9
+ def self.detect_test_framework_assert: [T < Exception] () -> T
10
+ end
11
+ end
12
+ end
13
+ end