capybara-screenshot-diff 1.6.2 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.<<(name).map(&:to_s)
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, options = {})
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.delete(:crop)
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
- FileUtils.mkdir_p File.dirname(file_name)
77
+ create_output_directory_for(file_name)
78
+
88
79
  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)
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
- (@test_screenshots ||= []) << [caller(1..1).first, name, comparison]
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
- true
106
- end
90
+ (@test_screenshots ||= []) << [caller[skip_stack_frames], name, comparison]
107
91
 
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)
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, comparison)
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, comparison.old_file_name
26
+ FileUtils.cp committed_file_name, old_file_name
26
27
  else
27
- svn_info = `svn info #{comparison.new_file_name} #{SILENCE_ERRORS}`
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, comparison.old_file_name
34
+ FileUtils.cp committed_file_name, old_file_name
34
35
  end
35
36
  else
36
- restore_git_revision(name, comparison.old_file_name)
37
+ restore_git_revision(name, old_file_name)
37
38
  end
38
39
  end
39
40
  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.7.0"
7
7
  end
8
8
  end
9
9
  end
@@ -52,15 +52,10 @@ module Capybara
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
56
 
57
57
  AVAILABLE_DRIVERS = Utils.detect_available_drivers.freeze
58
- begin
59
- require "minitest"
60
- ASSERTION = Minitest::Assertion
61
- rescue
62
- ASSERTION = RuntimeError
63
- end
58
+ ASSERTION = Utils.detect_test_framework_assert
64
59
 
65
60
  def self.default_options
66
61
  {
@@ -70,7 +65,7 @@ module Capybara
70
65
  shift_distance_limit: shift_distance_limit,
71
66
  skip_area: skip_area,
72
67
  stability_time_limit: Screenshot.stability_time_limit,
73
- tolerance: tolerance,
68
+ tolerance: tolerance || (driver == :vips ? 0.001 : nil),
74
69
  wait: Capybara.default_max_wait_time
75
70
  }
76
71
  end
@@ -89,19 +84,31 @@ module Capybara
89
84
 
90
85
  klass.teardown do
91
86
  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
87
+ track_failures(@test_screenshots, caller)
88
+ @test_screenshots = nil
89
+ end
90
+ end
91
+ end
92
+
93
+ private
94
+
95
+ EMPTY_LINE = "\n\n"
96
+
97
+ def track_failures(screenshots, original_caller)
98
+ test_screenshot_errors = screenshots.map do |caller, name, compare|
99
+ assert_image_not_changed(caller, name, compare)
100
+ end
101
+
102
+ test_screenshot_errors.compact!
103
+
104
+ unless test_screenshot_errors.empty?
105
+ error = ASSERTION.new(test_screenshot_errors.join(EMPTY_LINE))
106
+ error.set_backtrace(original_caller)
107
+
108
+ if is_a?(::Minitest::Runnable)
109
+ failures << error
110
+ else
111
+ raise error
105
112
  end
106
113
  end
107
114
  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.6.2
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-05-10 00:00:00.000000000 Z
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: '4.2'
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: '4.2'
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.5.0
123
+ version: 2.7.0
122
124
  required_rubygems_version: !ruby/object:Gem::Requirement
123
125
  requirements:
124
126
  - - ">="
@@ -1,6 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- gems = "#{File.dirname __dir__}/gems.rb"
4
- eval File.read(gems), binding, gems
5
-
6
- gem "actionpack", "~>5.2.1"