snap_diff-capybara 0.0.1 → 2.0.0.alpha1
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 +167 -0
- data/CODE_OF_CONDUCT.md +129 -0
- data/LICENSE.txt +21 -0
- data/Rakefile +65 -0
- data/capybara-screenshot-diff.gemspec +29 -0
- data/docs/RELEASE_PREP.md +44 -0
- data/docs/UPGRADING.md +475 -0
- data/docs/architecture.md +267 -0
- data/docs/ci-integration.md +238 -0
- data/docs/configuration.md +395 -0
- data/docs/docker-testing.md +24 -0
- data/docs/drivers.md +102 -0
- data/docs/framework-setup.md +87 -0
- data/docs/images/snap_diff_annotated.png +0 -0
- data/docs/images/snap_diff_web_ui.png +0 -0
- data/docs/migration-guide.md +286 -0
- data/docs/organization.md +204 -0
- data/docs/reporters.md +46 -0
- data/docs/thread_safety.md +112 -0
- data/gems.rb +39 -0
- data/lib/capybara/screenshot/diff/annotation_service.rb +7 -0
- data/lib/capybara/screenshot/diff/area_calculator.rb +7 -0
- data/lib/capybara/screenshot/diff/browser_helpers.rb +7 -0
- data/lib/capybara/screenshot/diff/config_legacy.rb +113 -0
- data/lib/capybara/screenshot/diff/cucumber.rb +3 -0
- data/lib/capybara/screenshot/diff/difference.rb +8 -0
- data/lib/capybara/screenshot/diff/drivers/base_driver.rb +9 -0
- data/lib/capybara/screenshot/diff/drivers/chunky_png_driver.rb +7 -0
- data/lib/capybara/screenshot/diff/drivers/vips_driver.rb +7 -0
- data/lib/capybara/screenshot/diff/drivers.rb +9 -0
- data/lib/capybara/screenshot/diff/image_compare.rb +12 -0
- data/lib/capybara/screenshot/diff/image_preprocessor.rb +7 -0
- data/lib/capybara/screenshot/diff/os.rb +14 -0
- data/lib/capybara/screenshot/diff/region.rb +107 -0
- data/lib/capybara/screenshot/diff/reporters/default.rb +109 -0
- data/lib/capybara/screenshot/diff/screenshot_matcher.rb +7 -0
- data/lib/capybara/screenshot/diff/screenshoter.rb +7 -0
- data/lib/capybara/screenshot/diff/stable_screenshoter.rb +7 -0
- data/lib/capybara/screenshot/diff/utils.rb +7 -0
- data/lib/capybara/screenshot/diff/vcs.rb +7 -0
- data/lib/capybara/screenshot/diff/version.rb +15 -0
- data/lib/capybara/screenshot/diff.rb +3 -0
- data/lib/capybara-screenshot-diff.rb +3 -0
- data/lib/capybara_screenshot_diff/attempts_reporter.rb +7 -0
- data/lib/capybara_screenshot_diff/cucumber.rb +8 -0
- data/lib/capybara_screenshot_diff/dsl.rb +12 -0
- data/lib/capybara_screenshot_diff/error_with_filtered_backtrace.rb +8 -0
- data/lib/capybara_screenshot_diff/minitest.rb +14 -0
- data/lib/capybara_screenshot_diff/reporters/html.rb +7 -0
- data/lib/capybara_screenshot_diff/rspec.rb +8 -0
- data/lib/capybara_screenshot_diff/screenshot_assertion.rb +71 -0
- data/lib/capybara_screenshot_diff/screenshot_namer.rb +7 -0
- data/lib/capybara_screenshot_diff/snap.rb +7 -0
- data/lib/capybara_screenshot_diff/snap_manager.rb +7 -0
- data/lib/capybara_screenshot_diff/static.rb +9 -0
- data/lib/capybara_screenshot_diff.rb +50 -0
- 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 +78 -0
- 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/reporters/templates/report.html.erb +463 -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 +65 -0
- metadata +160 -10
- data/README.md +0 -3
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
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
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
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"
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
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"
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Forwarder (ADR-004 v2 step 4): ChunkyPNGDriver lives in SnapDiff::Drivers
|
|
4
|
+
# now; the module alias in capybara/screenshot/diff/drivers.rb makes it
|
|
5
|
+
# reachable as Capybara::Screenshot::Diff::Drivers::ChunkyPNGDriver.
|
|
6
|
+
require "capybara/screenshot/diff/drivers"
|
|
7
|
+
require "snap_diff/drivers/chunky_png_driver"
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Forwarder (ADR-004 v2 step 4): VipsDriver lives in SnapDiff::Drivers now;
|
|
4
|
+
# the module alias in capybara/screenshot/diff/drivers.rb makes it reachable
|
|
5
|
+
# as Capybara::Screenshot::Diff::Drivers::VipsDriver.
|
|
6
|
+
require "capybara/screenshot/diff/drivers"
|
|
7
|
+
require "snap_diff/drivers/vips_driver"
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Forwarder (ADR-004 v2 step 6): Capybara::Screenshot::Diff::Drivers now
|
|
4
|
+
# resolves lazily via snap_diff/legacy_shims' const_missing, with a
|
|
5
|
+
# deprecation warning pointing at SnapDiff::Drivers. The forwarded module is
|
|
6
|
+
# the same object, so Drivers.for and the Drivers::VipsDriver /
|
|
7
|
+
# Drivers::ChunkyPNGDriver constants keep resolving through the old name.
|
|
8
|
+
require "snap_diff/drivers"
|
|
9
|
+
require "snap_diff/legacy_shims"
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Forwarder (ADR-004 v2 step 6): the comparison class lives at
|
|
4
|
+
# SnapDiff::Comparison (ex-ImageCompare); the old name now resolves lazily
|
|
5
|
+
# via snap_diff/legacy_shims' const_missing, with a deprecation warning.
|
|
6
|
+
# snap_diff/comparison itself pulls in the ComparisonResult and Drivers
|
|
7
|
+
# units, and the shims keep the old ::Difference / ::Drivers names
|
|
8
|
+
# resolvable, so this path still provides everything the pre-move
|
|
9
|
+
# image_compare.rb did. The internal Comparison struct and LOADED_DRIVERS
|
|
10
|
+
# keep their legacy names and are defined by snap_diff/comparison.rb itself.
|
|
11
|
+
require "snap_diff/comparison"
|
|
12
|
+
require "snap_diff/legacy_shims"
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Forwarder (ADR-004 v2 step 6): Capybara::Screenshot::Diff::ImagePreprocessor
|
|
4
|
+
# now resolves lazily via snap_diff/legacy_shims' const_missing, with a
|
|
5
|
+
# deprecation warning pointing at SnapDiff::ImagePreprocessor.
|
|
6
|
+
require "snap_diff/image_preprocessor"
|
|
7
|
+
require "snap_diff/legacy_shims"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "snap_diff/os"
|
|
4
|
+
|
|
5
|
+
# Deliberately EAGER and silent (v2 step 6 exception): Os is an advertised
|
|
6
|
+
# entry-point constant probed with Object.const_defined? by
|
|
7
|
+
# support_load_probe_test.rb, and const_defined? never triggers
|
|
8
|
+
# const_missing -- a lazy shim would break that contract. See
|
|
9
|
+
# snap_diff/legacy_shims.rb for the full exception list.
|
|
10
|
+
module Capybara
|
|
11
|
+
module Screenshot
|
|
12
|
+
Os = SnapDiff::Os
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Region
|
|
4
|
+
attr_accessor :x, :y, :width, :height
|
|
5
|
+
|
|
6
|
+
def initialize(x, y, width, height)
|
|
7
|
+
@x, @y, @width, @height = x, y, width, height
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def self.from_edge_coordinates(left, top, right, bottom)
|
|
11
|
+
return nil unless left && top && right && bottom
|
|
12
|
+
return nil if right < left || bottom < top
|
|
13
|
+
|
|
14
|
+
Region.new(left, top, right - left, bottom - top)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def to_edge_coordinates
|
|
18
|
+
[left, top, right, bottom]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def to_top_left_corner_coordinates
|
|
22
|
+
[x, y, width, height]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def top
|
|
26
|
+
y
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def bottom
|
|
30
|
+
y + height
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def left
|
|
34
|
+
x
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def right
|
|
38
|
+
x + width
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def size
|
|
42
|
+
return 0 if width < 0 || height < 0
|
|
43
|
+
|
|
44
|
+
result = width * height
|
|
45
|
+
result.zero? ? 1 : result
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def to_a
|
|
49
|
+
[@x, @y, @width, @height]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def find_intersect_with(region)
|
|
53
|
+
return nil unless intersect?(region)
|
|
54
|
+
|
|
55
|
+
new_left = [x, region.x].max
|
|
56
|
+
new_top = [y, region.y].max
|
|
57
|
+
|
|
58
|
+
Region.new(new_left, new_top, [right, region.right].min - new_left, [bottom, region.bottom].min - new_top)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def intersect?(region)
|
|
62
|
+
left <= region.right && right >= region.left && top <= region.bottom && bottom >= region.top
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def move_by(right_by, down_by)
|
|
66
|
+
Region.new(x + right_by, y + down_by, width, height)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def find_relative_intersect(region)
|
|
70
|
+
intersect = find_intersect_with(region)
|
|
71
|
+
return nil unless intersect
|
|
72
|
+
|
|
73
|
+
intersect.move_by(-x, -y)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def cover?(x, y)
|
|
77
|
+
x.between?(left, right) && y.between?(top, bottom)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def empty?
|
|
81
|
+
width.zero? || height.zero?
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def blank?
|
|
85
|
+
empty?
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def present?
|
|
89
|
+
!empty?
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def inspect
|
|
93
|
+
"Region(x: #{x}, y: #{y}, width: #{width}, height: #{height})"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# need to add this method to make it work with assert_equal
|
|
97
|
+
def ==(other)
|
|
98
|
+
case other
|
|
99
|
+
when Region
|
|
100
|
+
x == other.x && y == other.y && width == other.width && height == other.height
|
|
101
|
+
when Array
|
|
102
|
+
to_a == other
|
|
103
|
+
else
|
|
104
|
+
false
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "snap_diff/annotation_service"
|
|
4
|
+
# Defines the Capybara::Screenshot::Diff namespace this file reopens.
|
|
5
|
+
require "snap_diff/legacy_shims"
|
|
6
|
+
|
|
7
|
+
module Capybara::Screenshot::Diff
|
|
8
|
+
module Reporters
|
|
9
|
+
class Default
|
|
10
|
+
attr_reader :difference
|
|
11
|
+
|
|
12
|
+
def initialize(difference)
|
|
13
|
+
@difference = difference
|
|
14
|
+
@annotation_service = SnapDiff::AnnotationService.new(difference)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def annotated_image_path
|
|
18
|
+
annotation_service.annotated_image_path
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def annotated_base_image_path
|
|
22
|
+
annotation_service.annotated_base_image_path
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def heatmap_diff_path
|
|
26
|
+
annotation_service.heatmap_diff_path
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def generate
|
|
30
|
+
if difference.equal?
|
|
31
|
+
# NOTE: Delete previous run runtime files
|
|
32
|
+
clean_tmp_files
|
|
33
|
+
return nil
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
if difference.failed? && difference.failed_by[:different_dimensions]
|
|
37
|
+
return build_error_for_different_dimensions
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
annotate_and_save_images
|
|
41
|
+
build_error_message
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def clean_tmp_files
|
|
45
|
+
annotation_service.clean_tmp_files
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def annotate_and_save_images
|
|
49
|
+
annotation_service.annotate_and_save_images
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def save_annotation_for(image, image_path)
|
|
53
|
+
annotation_service.save_annotation_for(image, image_path)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def annotate_difference(image, region)
|
|
57
|
+
annotation_service.annotate_difference(image, region)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def annotate_skip_areas(image, skip_areas)
|
|
61
|
+
annotation_service.annotate_skip_areas(image, skip_areas)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def save(image, image_path)
|
|
65
|
+
annotation_service.save(image, image_path)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def build_error_for_different_dimensions
|
|
69
|
+
change_msg = [comparison.base_image, comparison.new_image]
|
|
70
|
+
.map { |image| driver.dimension(image).join("x") }
|
|
71
|
+
.join(" => ")
|
|
72
|
+
|
|
73
|
+
"Dimensions have changed: #{change_msg}\n#{base_image_path.to_path}\n#{image_path.to_path}"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
NEW_LINE = "\n"
|
|
77
|
+
|
|
78
|
+
def build_error_message
|
|
79
|
+
[
|
|
80
|
+
"(#{difference.to_h.to_json})",
|
|
81
|
+
image_path.to_path,
|
|
82
|
+
annotated_base_image_path.to_path,
|
|
83
|
+
annotated_image_path.to_path,
|
|
84
|
+
heatmap_diff_path.to_path
|
|
85
|
+
].join(NEW_LINE)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
private
|
|
89
|
+
|
|
90
|
+
attr_reader :annotation_service
|
|
91
|
+
|
|
92
|
+
def base_image_path
|
|
93
|
+
comparison.base_image_path
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def image_path
|
|
97
|
+
comparison.new_image_path
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def driver
|
|
101
|
+
@_driver ||= comparison.driver
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def comparison
|
|
105
|
+
@_comparison ||= difference.comparison
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Forwarder (ADR-004 v2 step 6): Capybara::Screenshot::Diff::ScreenshotMatcher
|
|
4
|
+
# now resolves lazily via snap_diff/legacy_shims' const_missing, with a
|
|
5
|
+
# deprecation warning pointing at SnapDiff::ScreenshotMatcher.
|
|
6
|
+
require "snap_diff/screenshot_matcher"
|
|
7
|
+
require "snap_diff/legacy_shims"
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Forwarder (ADR-004 v2 step 6): Capybara::Screenshot::Screenshoter now
|
|
4
|
+
# resolves lazily via snap_diff/legacy_shims' const_missing, with a
|
|
5
|
+
# deprecation warning pointing at SnapDiff::Screenshoter.
|
|
6
|
+
require "snap_diff/screenshoter"
|
|
7
|
+
require "snap_diff/legacy_shims"
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Forwarder (ADR-004 v2 step 6): Capybara::Screenshot::Diff::StableScreenshoter
|
|
4
|
+
# now resolves lazily via snap_diff/legacy_shims' const_missing, with a
|
|
5
|
+
# deprecation warning pointing at SnapDiff::StableScreenshoter.
|
|
6
|
+
require "snap_diff/stable_screenshoter"
|
|
7
|
+
require "snap_diff/legacy_shims"
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Forwarder (ADR-004 v2 step 6): Capybara::Screenshot::Diff::Utils now
|
|
4
|
+
# resolves lazily via snap_diff/legacy_shims' const_missing, with a
|
|
5
|
+
# deprecation warning pointing at SnapDiff::Utils.
|
|
6
|
+
require "snap_diff/utils"
|
|
7
|
+
require "snap_diff/legacy_shims"
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Forwarder (ADR-004 v2 step 6): Capybara::Screenshot::Diff::Vcs now
|
|
4
|
+
# resolves lazily via snap_diff/legacy_shims' const_missing, with a
|
|
5
|
+
# deprecation warning pointing at SnapDiff::Vcs.
|
|
6
|
+
require "snap_diff/vcs"
|
|
7
|
+
require "snap_diff/legacy_shims"
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "snap_diff/version"
|
|
4
|
+
|
|
5
|
+
# Deliberately EAGER and silent (v2 step 6 exception): the gemspec resolves
|
|
6
|
+
# Capybara::Screenshot::Diff::VERSION at build time, so a lazy warning shim
|
|
7
|
+
# would make every `gem build` warn. See snap_diff/legacy_shims.rb for the
|
|
8
|
+
# full exception list.
|
|
9
|
+
module Capybara
|
|
10
|
+
module Screenshot
|
|
11
|
+
module Diff
|
|
12
|
+
VERSION = SnapDiff::VERSION
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Forwarder (ADR-004 v2 step 6): CapybaraScreenshotDiff::AttemptsReporter now
|
|
4
|
+
# resolves lazily via snap_diff/legacy_shims' const_missing, with a
|
|
5
|
+
# deprecation warning pointing at SnapDiff::AttemptsReporter.
|
|
6
|
+
require "snap_diff/attempts_reporter"
|
|
7
|
+
require "snap_diff/legacy_shims"
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Legacy entry point: pre-move, this path transitively loaded the whole gem
|
|
4
|
+
# (via dsl -> umbrella). Preserve that contract for consumers who require
|
|
5
|
+
# only this file.
|
|
6
|
+
require "capybara_screenshot_diff"
|
|
7
|
+
|
|
8
|
+
require "snap_diff/integrations/cucumber"
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "snap_diff/dsl"
|
|
4
|
+
|
|
5
|
+
# Deliberately EAGER and silent (v2 step 6 exception): DSL is an advertised
|
|
6
|
+
# entry-point constant probed with Object.const_defined? by
|
|
7
|
+
# support_load_probe_test.rb, and const_defined? never triggers
|
|
8
|
+
# const_missing -- a lazy shim would break that contract. See
|
|
9
|
+
# snap_diff/legacy_shims.rb for the full exception list.
|
|
10
|
+
module CapybaraScreenshotDiff
|
|
11
|
+
DSL = SnapDiff::DSL
|
|
12
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Forwarder (ADR-004 v2 step 6): CapybaraScreenshotDiff::BacktraceFilter and
|
|
4
|
+
# CapybaraScreenshotDiff::ErrorWithFilteredBacktrace now resolve lazily via
|
|
5
|
+
# snap_diff/legacy_shims' const_missing, with deprecation warnings pointing
|
|
6
|
+
# at their SnapDiff:: replacements.
|
|
7
|
+
require "snap_diff/error_with_filtered_backtrace"
|
|
8
|
+
require "snap_diff/legacy_shims"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Legacy entry point: pre-move, this path transitively loaded the whole gem
|
|
4
|
+
# (via dsl -> umbrella). Preserve that contract for consumers who require
|
|
5
|
+
# only this file.
|
|
6
|
+
require "capybara_screenshot_diff"
|
|
7
|
+
|
|
8
|
+
require "snap_diff/integrations/minitest"
|
|
9
|
+
|
|
10
|
+
module CapybaraScreenshotDiff
|
|
11
|
+
module Minitest
|
|
12
|
+
Assertions = SnapDiff::Minitest::Assertions
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Forwarder (ADR-004 v2 step 6): CapybaraScreenshotDiff::Reporters::HTML now
|
|
4
|
+
# resolves lazily via snap_diff/legacy_shims' const_missing, with a
|
|
5
|
+
# deprecation warning pointing at SnapDiff::Reporters::HTML.
|
|
6
|
+
require "snap_diff/reporters/html"
|
|
7
|
+
require "snap_diff/legacy_shims"
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Legacy entry point: pre-move, this path transitively loaded the whole gem
|
|
4
|
+
# (via dsl -> umbrella). Preserve that contract for consumers who require
|
|
5
|
+
# only this file.
|
|
6
|
+
require "capybara_screenshot_diff"
|
|
7
|
+
|
|
8
|
+
require "snap_diff/integrations/rspec"
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "snap_diff/screenshot_assertion"
|
|
4
|
+
require "snap_diff/reporting"
|
|
5
|
+
# ScreenshotAssertion / AssertionRegistry forward lazily (with deprecation
|
|
6
|
+
# warnings) via snap_diff/legacy_shims' const_missing since v2 step 6.
|
|
7
|
+
require "snap_diff/legacy_shims"
|
|
8
|
+
|
|
9
|
+
# CapybaraScreenshotDiff's module methods cover two lifecycles with
|
|
10
|
+
# different scopes, kept separate below:
|
|
11
|
+
#
|
|
12
|
+
# - Session lifecycle: thread-local, per-test. The AssertionRegistry holds
|
|
13
|
+
# the assertions and screenshot names of the test running on this thread;
|
|
14
|
+
# `reset` clears it between tests.
|
|
15
|
+
# - Reporter lifecycle: process-global, suite-long. Owned by
|
|
16
|
+
# SnapDiff::Reporting; the methods here are thin public shims over it.
|
|
17
|
+
#
|
|
18
|
+
# `reset` is the one deliberate bridge between the two: a finished test's
|
|
19
|
+
# assertions are handed to the reporters before the registry is cleared.
|
|
20
|
+
module CapybaraScreenshotDiff
|
|
21
|
+
class << self
|
|
22
|
+
require "forwardable"
|
|
23
|
+
extend Forwardable
|
|
24
|
+
|
|
25
|
+
# --- Session lifecycle (thread-local, per-test) ---
|
|
26
|
+
|
|
27
|
+
def registry
|
|
28
|
+
Thread.current[:capybara_screenshot_diff_registry] ||= SnapDiff::AssertionRegistry.new
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def_delegators :registry, :add_assertion, :assertions, :assertions_present?,
|
|
32
|
+
:failed_assertions, :record_new_screenshot, :new_screenshots,
|
|
33
|
+
:new_screenshots_present?, :screenshot_namer, :verify
|
|
34
|
+
|
|
35
|
+
def reset
|
|
36
|
+
notify_reporters(registry.assertions)
|
|
37
|
+
registry.reset
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Message to skip the test with when a new screenshot has no baseline yet
|
|
41
|
+
# and `pending_if_new` is enabled. Adapters call this after verifying
|
|
42
|
+
# screenshots, and skip the test with the returned message when present.
|
|
43
|
+
#
|
|
44
|
+
# @return [String, nil] the pending message, or nil when there is nothing to report
|
|
45
|
+
def pending_screenshots_message
|
|
46
|
+
return unless ::Capybara::Screenshot::Diff.pending_if_new && new_screenshots_present?
|
|
47
|
+
|
|
48
|
+
"No baseline for: #{new_screenshots.join(", ")}. Commit the captured screenshots to record them."
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# --- Reporter lifecycle (process-global, suite-long) ---
|
|
52
|
+
|
|
53
|
+
def reporters
|
|
54
|
+
SnapDiff::Reporting.reporters
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def reporters_mutex
|
|
58
|
+
SnapDiff::Reporting.mutex
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def finalize_reporters!
|
|
62
|
+
SnapDiff::Reporting.finalize!
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def notify_reporters(assertions)
|
|
68
|
+
SnapDiff::Reporting.notify(assertions)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Forwarder (ADR-004 v2 step 6): CapybaraScreenshotDiff::ScreenshotNamer now
|
|
4
|
+
# resolves lazily via snap_diff/legacy_shims' const_missing, with a
|
|
5
|
+
# deprecation warning pointing at SnapDiff::ScreenshotNamer.
|
|
6
|
+
require "snap_diff/screenshot_namer"
|
|
7
|
+
require "snap_diff/legacy_shims"
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Forwarder (ADR-004 v2 step 6): CapybaraScreenshotDiff::Snap now resolves
|
|
4
|
+
# lazily via snap_diff/legacy_shims' const_missing, with a deprecation
|
|
5
|
+
# warning pointing at SnapDiff::Snap.
|
|
6
|
+
require "snap_diff/snap"
|
|
7
|
+
require "snap_diff/legacy_shims"
|