capybara-screenshot-diff 1.15.1 → 2.0.0.beta1
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/CHANGELOG.md +72 -0
- data/docs/UPGRADING.md +227 -0
- data/docs/architecture.md +64 -42
- data/docs/thread_safety.md +15 -0
- data/lib/capybara/screenshot/diff/annotation_service.rb +5 -77
- data/lib/capybara/screenshot/diff/area_calculator.rb +5 -54
- data/lib/capybara/screenshot/diff/browser_helpers.rb +5 -119
- data/lib/capybara/screenshot/diff/config_legacy.rb +113 -0
- data/lib/capybara/screenshot/diff/cucumber.rb +1 -1
- data/lib/capybara/screenshot/diff/difference.rb +6 -102
- data/lib/capybara/screenshot/diff/drivers/base_driver.rb +7 -39
- data/lib/capybara/screenshot/diff/drivers/chunky_png_driver.rb +5 -299
- data/lib/capybara/screenshot/diff/drivers/vips_driver.rb +5 -169
- data/lib/capybara/screenshot/diff/drivers.rb +7 -14
- data/lib/capybara/screenshot/diff/image_compare.rb +10 -228
- data/lib/capybara/screenshot/diff/image_preprocessor.rb +5 -70
- data/lib/capybara/screenshot/diff/os.rb +8 -13
- data/lib/capybara/screenshot/diff/reporters/default.rb +5 -3
- data/lib/capybara/screenshot/diff/screenshot_matcher.rb +5 -129
- data/lib/capybara/screenshot/diff/screenshoter.rb +5 -127
- data/lib/capybara/screenshot/diff/stable_screenshoter.rb +5 -104
- data/lib/capybara/screenshot/diff/utils.rb +5 -40
- data/lib/capybara/screenshot/diff/vcs.rb +5 -37
- data/lib/capybara/screenshot/diff/version.rb +7 -1
- data/lib/capybara_screenshot_diff/attempts_reporter.rb +5 -47
- data/lib/capybara_screenshot_diff/cucumber.rb +5 -17
- data/lib/capybara_screenshot_diff/dsl.rb +7 -129
- data/lib/capybara_screenshot_diff/error_with_filtered_backtrace.rb +6 -30
- data/lib/capybara_screenshot_diff/minitest.rb +6 -56
- data/lib/capybara_screenshot_diff/reporters/html.rb +5 -135
- data/lib/capybara_screenshot_diff/rspec.rb +5 -63
- data/lib/capybara_screenshot_diff/screenshot_assertion.rb +39 -157
- data/lib/capybara_screenshot_diff/screenshot_namer.rb +5 -79
- data/lib/capybara_screenshot_diff/snap.rb +5 -64
- data/lib/capybara_screenshot_diff/snap_manager.rb +5 -82
- data/lib/capybara_screenshot_diff/static.rb +3 -5
- data/lib/capybara_screenshot_diff.rb +29 -100
- data/lib/snap_diff/annotation_service.rb +84 -0
- data/lib/snap_diff/area_calculator.rb +56 -0
- data/lib/snap_diff/attempts_reporter.rb +51 -0
- data/lib/snap_diff/browser_helpers.rb +121 -0
- data/lib/snap_diff/capture/viewport.rb +40 -0
- data/lib/snap_diff/comparison.rb +238 -0
- data/lib/snap_diff/comparison_result.rb +104 -0
- data/lib/snap_diff/config.rb +6 -2
- data/lib/snap_diff/deprecation.rb +84 -0
- data/lib/snap_diff/driver.rb +37 -0
- data/lib/snap_diff/drivers/chunky_png_driver.rb +298 -0
- data/lib/snap_diff/drivers/vips_driver.rb +171 -0
- data/lib/snap_diff/drivers.rb +14 -0
- data/lib/snap_diff/dsl.rb +143 -0
- data/lib/snap_diff/error_with_filtered_backtrace.rb +32 -0
- data/lib/snap_diff/image_preprocessor.rb +68 -0
- data/lib/snap_diff/integrations/cucumber.rb +22 -0
- data/lib/snap_diff/integrations/minitest.rb +70 -0
- data/lib/snap_diff/integrations/rspec.rb +68 -0
- data/lib/snap_diff/legacy_shims.rb +99 -0
- data/lib/snap_diff/os.rb +17 -0
- data/lib/snap_diff/reporters/html.rb +143 -0
- data/lib/snap_diff/reporting.rb +53 -0
- data/lib/snap_diff/screenshot_assertion.rb +143 -0
- data/lib/snap_diff/screenshot_matcher.rb +113 -0
- data/lib/snap_diff/screenshot_namer.rb +81 -0
- data/lib/snap_diff/screenshoter.rb +129 -0
- data/lib/snap_diff/snap.rb +66 -0
- data/lib/snap_diff/snap_manager.rb +125 -0
- data/lib/snap_diff/stable_screenshoter.rb +103 -0
- data/lib/snap_diff/static.rb +11 -0
- data/lib/snap_diff/utils.rb +38 -0
- data/lib/snap_diff/vcs.rb +35 -0
- data/lib/snap_diff/version.rb +5 -0
- data/lib/snap_diff.rb +22 -6
- metadata +36 -2
- /data/lib/{capybara_screenshot_diff → snap_diff}/reporters/templates/report.html.erb +0 -0
|
@@ -1,56 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
@crop_coordinates = crop_coordinates
|
|
9
|
-
@skip_area = skip_area
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def calculate_crop
|
|
13
|
-
return @_calculated_crop if defined?(@_calculated_crop)
|
|
14
|
-
return @_calculated_crop = nil unless @crop_coordinates
|
|
15
|
-
|
|
16
|
-
# TODO: Move out from this class, this should be done on before screenshot and should not depend on Browser
|
|
17
|
-
@crop_coordinates = BrowserHelpers.bounds_for_css(@crop_coordinates).first if @crop_coordinates.is_a?(String)
|
|
18
|
-
@_calculated_crop = Region.from_edge_coordinates(*@crop_coordinates)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
# Cast skip areas params into Region
|
|
22
|
-
# and if there is crop then makes absolute coordinates to eb relative to crop top left corner
|
|
23
|
-
def calculate_skip_area
|
|
24
|
-
return nil unless @skip_area
|
|
25
|
-
|
|
26
|
-
crop_region = calculate_crop
|
|
27
|
-
skip_area = Array(@skip_area)
|
|
28
|
-
|
|
29
|
-
css_selectors, coords_list = skip_area.compact.partition { |region| region.is_a? String }
|
|
30
|
-
regions, coords_list = coords_list.partition { |region| region.is_a? Region }
|
|
31
|
-
|
|
32
|
-
regions.concat(build_regions_for(BrowserHelpers.bounds_for_css(*css_selectors))) unless css_selectors.empty?
|
|
33
|
-
regions.concat(build_regions_for(coords_list.flatten.each_slice(4))) unless coords_list.empty?
|
|
34
|
-
|
|
35
|
-
regions.compact!
|
|
36
|
-
|
|
37
|
-
if crop_region
|
|
38
|
-
regions
|
|
39
|
-
.map! { |region| crop_region.find_relative_intersect(region) }
|
|
40
|
-
.filter! { |region| region&.present? }
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
regions
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
private
|
|
47
|
-
|
|
48
|
-
def build_regions_for(coordinates)
|
|
49
|
-
coordinates
|
|
50
|
-
.map { |entry| Region.from_edge_coordinates(*entry) }
|
|
51
|
-
.tap { |region| region.compact! }
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
|
3
|
+
# Forwarder (ADR-004 v2 step 6): Capybara::Screenshot::Diff::AreaCalculator
|
|
4
|
+
# now resolves lazily via snap_diff/legacy_shims' const_missing, with a
|
|
5
|
+
# deprecation warning pointing at SnapDiff::AreaCalculator.
|
|
6
|
+
require "snap_diff/area_calculator"
|
|
7
|
+
require "snap_diff/legacy_shims"
|
|
@@ -1,121 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def self.resize_window_if_needed
|
|
9
|
-
if ::Capybara::Screenshot.respond_to?(:window_size) && ::Capybara::Screenshot.window_size
|
|
10
|
-
resize_to(::Capybara::Screenshot.window_size)
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def self.resize_to(window_size)
|
|
15
|
-
if session.driver.respond_to?(:resize)
|
|
16
|
-
session.driver.resize(*window_size)
|
|
17
|
-
elsif BrowserHelpers.selenium?
|
|
18
|
-
session.driver.browser.manage.window.resize_to(*window_size)
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def self.selenium?
|
|
23
|
-
current_capybara_driver_class <= Capybara::Selenium::Driver
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def self.window_size_is_wrong?(expected_window_size = nil)
|
|
27
|
-
selenium? && expected_window_size &&
|
|
28
|
-
session.driver.browser.manage.window.size != ::Selenium::WebDriver::Dimension.new(*expected_window_size)
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def self.bounds_for_css(*css_selectors)
|
|
32
|
-
css_selectors.reduce([]) do |regions, selector|
|
|
33
|
-
regions.concat(all_visible_regions_for(selector))
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
IMAGE_WAIT_SCRIPT = <<~JS
|
|
38
|
-
function pending_image() {
|
|
39
|
-
const images = document.images
|
|
40
|
-
for (var i = 0; i < images.length; i++) {
|
|
41
|
-
if (!images[i].complete && images[i].loading !== "lazy") {
|
|
42
|
-
return images[i].src
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return false
|
|
46
|
-
}(window)
|
|
47
|
-
JS
|
|
48
|
-
|
|
49
|
-
HIDE_CARET_SCRIPT = <<~JS
|
|
50
|
-
if (!document.getElementById('csdHideCaretStyle')) {
|
|
51
|
-
let style = document.createElement('style');
|
|
52
|
-
style.setAttribute('id', 'csdHideCaretStyle');
|
|
53
|
-
document.head.appendChild(style);
|
|
54
|
-
let styleSheet = style.sheet;
|
|
55
|
-
styleSheet.insertRule("* { caret-color: transparent !important; }", 0);
|
|
56
|
-
}
|
|
57
|
-
JS
|
|
58
|
-
|
|
59
|
-
def self.hide_caret
|
|
60
|
-
session.execute_script(HIDE_CARET_SCRIPT)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
DISABLE_ANIMATIONS_SCRIPT = <<~JS
|
|
64
|
-
if (!document.getElementById('csdDisableAnimationsStyle')) {
|
|
65
|
-
let style = document.createElement('style');
|
|
66
|
-
style.setAttribute('id', 'csdDisableAnimationsStyle');
|
|
67
|
-
style.textContent = '*, *::before, *::after { animation-duration: 0s !important; animation-delay: 0s !important; transition-duration: 0s !important; transition-delay: 0s !important; }';
|
|
68
|
-
document.head.appendChild(style);
|
|
69
|
-
}
|
|
70
|
-
JS
|
|
71
|
-
|
|
72
|
-
def self.disable_animations
|
|
73
|
-
session.execute_script(DISABLE_ANIMATIONS_SCRIPT)
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
FIND_ACTIVE_ELEMENT_SCRIPT = <<~JS
|
|
77
|
-
function activeElement(){
|
|
78
|
-
const ae = document.activeElement;
|
|
79
|
-
if (ae.nodeName === "INPUT" || ae.nodeName === "TEXTAREA") {
|
|
80
|
-
ae.blur();
|
|
81
|
-
return ae;
|
|
82
|
-
}
|
|
83
|
-
return null;
|
|
84
|
-
}(window);
|
|
85
|
-
JS
|
|
86
|
-
|
|
87
|
-
def self.blur_from_focused_element
|
|
88
|
-
session.evaluate_script(FIND_ACTIVE_ELEMENT_SCRIPT)
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
GET_BOUNDING_CLIENT_RECT_SCRIPT = <<~JS
|
|
92
|
-
[
|
|
93
|
-
this.getBoundingClientRect().left,
|
|
94
|
-
this.getBoundingClientRect().top,
|
|
95
|
-
this.getBoundingClientRect().right,
|
|
96
|
-
this.getBoundingClientRect().bottom
|
|
97
|
-
]
|
|
98
|
-
JS
|
|
99
|
-
|
|
100
|
-
def self.all_visible_regions_for(selector)
|
|
101
|
-
BrowserHelpers.session.all(selector, visible: true).map { |el| region_for(el) }
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def self.region_for(element)
|
|
105
|
-
element.evaluate_script(GET_BOUNDING_CLIENT_RECT_SCRIPT).map { |point| point.negative? ? 0 : point.ceil.to_i }
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
def self.session
|
|
109
|
-
Capybara.current_session
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
def self.pending_image_to_load
|
|
113
|
-
BrowserHelpers.session.evaluate_script(IMAGE_WAIT_SCRIPT)
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
def self.current_capybara_driver_class
|
|
117
|
-
session.driver.class
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
end
|
|
121
|
-
end
|
|
3
|
+
# Forwarder (ADR-004 v2 step 6): Capybara::Screenshot::BrowserHelpers now
|
|
4
|
+
# resolves lazily via snap_diff/legacy_shims' const_missing, with a
|
|
5
|
+
# deprecation warning pointing at SnapDiff::BrowserHelpers.
|
|
6
|
+
require "snap_diff/browser_helpers"
|
|
7
|
+
require "snap_diff/legacy_shims"
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Legacy Capybara::Screenshot / Capybara::Screenshot::Diff mattr_accessor
|
|
4
|
+
# config module, extracted out of capybara_screenshot_diff.rb so it is a
|
|
5
|
+
# leaf: it can be required by both capybara_screenshot_diff.rb (the old
|
|
6
|
+
# umbrella entry point) and snap_diff.rb (the canonical entry point)
|
|
7
|
+
# without either of *those* requiring the other back.
|
|
8
|
+
#
|
|
9
|
+
# Why this file has to exist at all: several lib/snap_diff/* units
|
|
10
|
+
# (Screenshoter, SnapManager, Utils) are referenced here at class-body
|
|
11
|
+
# eval time (mattr_accessor default blocks, AVAILABLE_DRIVERS) rather
|
|
12
|
+
# than at call time, so they must be real, already-loaded classes before
|
|
13
|
+
# this module body runs. Since v2 step 6 they are pulled in and referenced
|
|
14
|
+
# under their canonical SnapDiff names: the old-name aliases are lazy
|
|
15
|
+
# const_missing shims that emit deprecation warnings, and the gem's own
|
|
16
|
+
# code must stay warning-free. Everything else this module references
|
|
17
|
+
# (Os, Comparison) is referenced only inside method bodies, resolved
|
|
18
|
+
# lazily at call time by whichever entry point loaded them.
|
|
19
|
+
require "snap_diff/screenshoter"
|
|
20
|
+
require "snap_diff/snap_manager"
|
|
21
|
+
require "snap_diff/utils"
|
|
22
|
+
|
|
23
|
+
module Capybara
|
|
24
|
+
module Screenshot
|
|
25
|
+
mattr_accessor :add_driver_path
|
|
26
|
+
mattr_accessor :add_os_path
|
|
27
|
+
mattr_accessor(:blur_active_element) { true }
|
|
28
|
+
mattr_accessor :enabled
|
|
29
|
+
mattr_accessor(:hide_caret) { true }
|
|
30
|
+
mattr_accessor :disable_animations
|
|
31
|
+
mattr_reader(:root) { (defined?(Rails) && defined?(Rails.root) && Rails.root) || Pathname(".").expand_path }
|
|
32
|
+
mattr_accessor :stability_time_limit
|
|
33
|
+
mattr_accessor :window_size
|
|
34
|
+
mattr_accessor(:save_path) { "doc/screenshots" }
|
|
35
|
+
mattr_accessor(:use_lfs)
|
|
36
|
+
mattr_accessor(:screenshot_format) { "png" }
|
|
37
|
+
mattr_accessor(:capybara_screenshot_options) { {} }
|
|
38
|
+
|
|
39
|
+
class << self
|
|
40
|
+
def root=(path)
|
|
41
|
+
@@root = Pathname(path).expand_path
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def active?
|
|
45
|
+
enabled || (enabled.nil? && Diff.enabled)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def screenshot_area
|
|
49
|
+
parts = [Screenshot.save_path]
|
|
50
|
+
parts << SnapDiff::Os.name if Screenshot.add_os_path
|
|
51
|
+
parts << Capybara.current_driver.to_s if Screenshot.add_driver_path
|
|
52
|
+
File.join(*parts)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def screenshot_area_abs
|
|
56
|
+
root / screenshot_area
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Module to track screenshot changes
|
|
61
|
+
module Diff
|
|
62
|
+
mattr_accessor(:delayed) { true }
|
|
63
|
+
mattr_accessor :area_size_limit
|
|
64
|
+
mattr_accessor(:fail_if_new) { !ENV["CI"].nil? && !ENV["CI"].empty? }
|
|
65
|
+
mattr_accessor(:pending_if_new) { false }
|
|
66
|
+
mattr_accessor(:fail_on_difference) { true }
|
|
67
|
+
mattr_accessor :color_distance_limit
|
|
68
|
+
mattr_accessor(:enabled) { true }
|
|
69
|
+
mattr_accessor :shift_distance_limit
|
|
70
|
+
mattr_accessor :skip_area
|
|
71
|
+
mattr_accessor(:driver) { :auto }
|
|
72
|
+
mattr_accessor :tolerance
|
|
73
|
+
mattr_accessor :perceptual_threshold
|
|
74
|
+
|
|
75
|
+
mattr_accessor(:screenshoter) { SnapDiff::Screenshoter }
|
|
76
|
+
mattr_accessor(:manager) { SnapDiff::SnapManager }
|
|
77
|
+
|
|
78
|
+
AVAILABLE_DRIVERS = SnapDiff::Utils.detect_available_drivers.freeze
|
|
79
|
+
|
|
80
|
+
# Configure screenshot and diff settings in one block.
|
|
81
|
+
#
|
|
82
|
+
# Capybara::Screenshot::Diff.configure do |screenshot, diff|
|
|
83
|
+
# screenshot.window_size = [1280, 1024]
|
|
84
|
+
# screenshot.stability_time_limit = 1
|
|
85
|
+
# diff.driver = :vips
|
|
86
|
+
# diff.tolerance = 0.0005
|
|
87
|
+
# end
|
|
88
|
+
def self.configure
|
|
89
|
+
yield Screenshot, self
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def self.compare(baseline_path, current_path, **options)
|
|
93
|
+
SnapDiff::Comparison.new(current_path, baseline_path, default_options.merge(options))
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def self.default_options
|
|
97
|
+
{
|
|
98
|
+
area_size_limit: area_size_limit,
|
|
99
|
+
color_distance_limit: color_distance_limit,
|
|
100
|
+
driver: driver,
|
|
101
|
+
screenshot_format: Screenshot.screenshot_format,
|
|
102
|
+
capybara_screenshot_options: Screenshot.capybara_screenshot_options,
|
|
103
|
+
perceptual_threshold: perceptual_threshold,
|
|
104
|
+
shift_distance_limit: shift_distance_limit,
|
|
105
|
+
skip_area: skip_area,
|
|
106
|
+
stability_time_limit: Screenshot.stability_time_limit,
|
|
107
|
+
tolerance: tolerance || ((driver == :vips) ? 0.001 : nil),
|
|
108
|
+
wait: Capybara.default_max_wait_time
|
|
109
|
+
}
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -1,104 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
#
|
|
10
|
-
# This value object encapsulates the result of an image comparison operation.
|
|
11
|
-
# It follows the Single Responsibility Principle by focusing solely on representing
|
|
12
|
-
# the difference state, including:
|
|
13
|
-
# - Whether images are different or equal
|
|
14
|
-
# - Why they differ (dimensions, pixels, etc.)
|
|
15
|
-
# - The specific region of difference
|
|
16
|
-
# - Whether differences are tolerable based on configured thresholds
|
|
17
|
-
#
|
|
18
|
-
# As part of the layered comparison architecture, this class represents the final
|
|
19
|
-
# output of the comparison process, containing all data needed for reporting.
|
|
20
|
-
# Represents a difference between two images
|
|
21
|
-
class Difference < Struct.new(:region, :meta, :comparison, :failed_by, :base_image_path, :image_path, keyword_init: nil)
|
|
22
|
-
def self.build_null(comparison, base_image_path, new_image_path, failed_by = nil)
|
|
23
|
-
Difference.new(
|
|
24
|
-
nil,
|
|
25
|
-
{difference_level: nil, max_color_distance: 0},
|
|
26
|
-
comparison,
|
|
27
|
-
failed_by,
|
|
28
|
-
base_image_path,
|
|
29
|
-
new_image_path
|
|
30
|
-
).freeze
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def different?
|
|
34
|
-
failed? || !(blank? || tolerable?)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def equal?
|
|
38
|
-
!different?
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def failed?
|
|
42
|
-
!!failed_by
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def options
|
|
46
|
-
comparison.options
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def tolerance
|
|
50
|
-
options[:tolerance]
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def skip_area
|
|
54
|
-
comparison.skip_area
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def area_size_limit
|
|
58
|
-
options[:area_size_limit]
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def blank?
|
|
62
|
-
region.nil? || region_area_size.zero?
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def region_area_size
|
|
66
|
-
@region_area_size ||= region&.size || 0
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def ratio
|
|
70
|
-
meta[:difference_level]
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def to_h
|
|
74
|
-
{area_size: region_area_size, region: coordinates}.merge!(meta)
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def coordinates
|
|
78
|
-
region&.to_edge_coordinates
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def inspect
|
|
82
|
-
to_h.to_json
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
def tolerable?
|
|
86
|
-
!!((area_size_limit && area_size_limit >= region_area_size) || (tolerance && tolerance >= ratio))
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
# Path accessors for backward compatibility
|
|
90
|
-
def new_image_path
|
|
91
|
-
image_path || comparison&.new_image_path
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def original_image_path
|
|
95
|
-
base_image_path || comparison&.base_image_path
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def diff_mask
|
|
99
|
-
meta[:diff_mask]
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
end
|
|
3
|
+
# Forwarder (ADR-004 v2 step 6): the comparison-result value object lives at
|
|
4
|
+
# SnapDiff::ComparisonResult (ex-Difference); the old name now resolves
|
|
5
|
+
# lazily via snap_diff/legacy_shims' const_missing, with a deprecation
|
|
6
|
+
# warning.
|
|
7
|
+
require "snap_diff/comparison_result"
|
|
8
|
+
require "snap_diff/legacy_shims"
|
|
@@ -1,41 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
module Drivers
|
|
11
|
-
class BaseDriver
|
|
12
|
-
PNG_EXTENSION = ".png"
|
|
13
|
-
|
|
14
|
-
def same_dimension?(comparison)
|
|
15
|
-
dimension(comparison.base_image) == dimension(comparison.new_image)
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def height_for(image)
|
|
19
|
-
image.height
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def width_for(image)
|
|
23
|
-
image.width
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def image_area_size(image)
|
|
27
|
-
width_for(image) * height_for(image)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def dimension(image)
|
|
31
|
-
[width_for(image), height_for(image)]
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def supports?(feature)
|
|
35
|
-
respond_to?(feature)
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|
|
3
|
+
# BaseDriver was dissolved into the SnapDiff::Driver mixin (ADR-004 v2
|
|
4
|
+
# step 4); since step 6 the old name resolves lazily via
|
|
5
|
+
# snap_diff/legacy_shims' const_missing, with a deprecation warning.
|
|
6
|
+
# Note it is now a module -- `class MyDriver < BaseDriver` becomes
|
|
7
|
+
# `include SnapDiff::Driver`.
|
|
8
|
+
require "snap_diff/driver"
|
|
9
|
+
require "snap_diff/legacy_shims"
|