capybara-screenshot-diff 1.12.0 → 1.13.0

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.
@@ -25,7 +25,7 @@ module CapybaraScreenshotDiff
25
25
  screenshot_namer.group = name
26
26
  end
27
27
 
28
- # Takes a screenshot and optionally compares it against a baseline image.
28
+ # Takes a screenshot and compares it against a baseline image.
29
29
  #
30
30
  # The method follows a layered optimization strategy for comparison:
31
31
  # 1. First checks if screenshot functionality is active
@@ -53,7 +53,7 @@ module CapybaraScreenshotDiff
53
53
  # @raise [CapybaraScreenshotDiff::ExpectationNotMet] If comparison fails and immediate validation is enabled.
54
54
  # @raise [CapybaraScreenshotDiff::UnstableImage] If the image comparison is unstable.
55
55
  # @raise [CapybaraScreenshotDiff::WindowSizeMismatchError] If the window size doesn't match expectations.
56
- def screenshot(name, skip_stack_frames: 0, **options)
56
+ def assert_matches_screenshot(name, skip_stack_frames: 0, **options)
57
57
  return false unless Capybara::Screenshot.active?
58
58
 
59
59
  # Get the full name with section and group information
@@ -76,15 +76,36 @@ module CapybaraScreenshotDiff
76
76
  true
77
77
  end
78
78
 
79
- # Alias for backward compatibility with older test suites.
80
- # @see #screenshot
81
- alias_method :assert_matches_screenshot, :screenshot
79
+ # Convenience wrapper around {#assert_matches_screenshot} and {#capture_screenshot}.
80
+ # @param compare [Boolean] When false, only captures the screenshot without comparing it to a baseline.
81
+ # @see #assert_matches_screenshot
82
+ # @see #capture_screenshot
83
+ def screenshot(name, skip_stack_frames: 0, compare: true, **options)
84
+ if compare
85
+ assert_matches_screenshot(name, skip_stack_frames: skip_stack_frames + 1, **options)
86
+ else
87
+ capture_screenshot(name, **options)
88
+ end
89
+ end
90
+
91
+ # Captures a screenshot without comparing it to a baseline.
92
+ # @param name [String] The base name of the screenshot, used to generate the filename.
93
+ # @param options [Hash] Additional options for taking the screenshot. See {#assert_matches_screenshot}.
94
+ # @return [Boolean] True if the screenshot was successfully captured.
95
+ def capture_screenshot(name, **options)
96
+ return false unless Capybara::Screenshot.active?
97
+
98
+ full_name = CapybaraScreenshotDiff.screenshot_namer.full_name(name)
99
+ Capybara::Screenshot::Diff::ScreenshotMatcher.new(full_name, options).capture
100
+
101
+ true
102
+ end
82
103
 
83
104
  # Asserts the current page has no visual changes from the baseline.
84
105
  # Override in your base test class to add project-specific behavior
85
106
  # (e.g., waiting for Turbo, default skip areas).
86
107
  def assert_no_screenshot_changes(name, skip_stack_frames: 0, **opts)
87
- screenshot(name, skip_stack_frames: skip_stack_frames + 1, **opts)
108
+ assert_matches_screenshot(name, skip_stack_frames: skip_stack_frames + 1, **opts)
88
109
  end
89
110
 
90
111
  private
@@ -96,7 +117,7 @@ module CapybaraScreenshotDiff
96
117
  #
97
118
  # @param name [String] The full name of the screenshot, including any section/group context.
98
119
  # @param options [Hash] Options for screenshot taking and comparison.
99
- # See {#screenshot} for available options.
120
+ # See {#assert_matches_screenshot} for available options.
100
121
  # @param skip_stack_frames [Integer] Number of stack frames to skip for error reporting.
101
122
  # @return [ScreenshotAssertion, nil] The assertion object or nil if no assertion is needed.
102
123
  # @see ScreenshotAssertion
@@ -19,7 +19,7 @@ module CapybaraScreenshotDiff
19
19
  module Assertions
20
20
  include ::CapybaraScreenshotDiff::DSL
21
21
 
22
- def screenshot(*args, skip_stack_frames: 0, **opts)
22
+ def assert_matches_screenshot(*args, skip_stack_frames: 0, **opts)
23
23
  self.assertions += 1
24
24
 
25
25
  super(*args, skip_stack_frames: skip_stack_frames + 1, **opts)
@@ -27,8 +27,6 @@ module CapybaraScreenshotDiff
27
27
  raise ::Minitest::Assertion, e.message
28
28
  end
29
29
 
30
- alias_method :assert_matches_screenshot, :screenshot
31
-
32
30
  def setup
33
31
  super
34
32
  ::Capybara::Screenshot::BrowserHelpers.resize_window_if_needed
@@ -37,6 +35,11 @@ module CapybaraScreenshotDiff
37
35
  def before_teardown
38
36
  super
39
37
  CapybaraScreenshotDiff.verify
38
+
39
+ if ::Capybara::Screenshot::Diff.pending_if_new && CapybaraScreenshotDiff.new_screenshots_present?
40
+ names = CapybaraScreenshotDiff.new_screenshots
41
+ skip "No baseline for: #{names.join(", ")}. Commit the captured screenshots to record them."
42
+ end
40
43
  rescue CapybaraScreenshotDiff::ExpectationNotMet => e
41
44
  assertion = ::Minitest::Assertion.new(e)
42
45
  assertion.set_backtrace(e.backtrace)
@@ -7,7 +7,7 @@ RSpec::Matchers.define :match_screenshot do |name, **options|
7
7
  description { "match screenshot '#{name}'" }
8
8
 
9
9
  match do |_page|
10
- screenshot(name, **options)
10
+ assert_matches_screenshot(name, **options)
11
11
  true
12
12
  end
13
13
 
@@ -30,10 +30,16 @@ RSpec.configure do |config|
30
30
  end
31
31
  end
32
32
 
33
- config.after do
33
+ config.after do |example|
34
34
  if self.class.include?(CapybaraScreenshotDiff::DSL)
35
35
  begin
36
36
  CapybaraScreenshotDiff.verify
37
+
38
+ # Never mask a real failure with a pending marker.
39
+ if example.exception.nil? && Capybara::Screenshot::Diff.pending_if_new && CapybaraScreenshotDiff.new_screenshots_present?
40
+ names = CapybaraScreenshotDiff.new_screenshots
41
+ skip "No baseline for: #{names.join(", ")}. Commit the captured screenshots to record them."
42
+ end
37
43
  rescue CapybaraScreenshotDiff::ExpectationNotMet => e
38
44
  raise RSpec::Expectations::ExpectationNotMetError.new(e.message).tap { |ex| ex.set_backtrace(e.backtrace) }
39
45
  ensure
@@ -65,10 +65,11 @@ module CapybaraScreenshotDiff
65
65
  end
66
66
 
67
67
  class AssertionRegistry
68
- attr_reader :assertions, :screenshot_namer
68
+ attr_reader :assertions, :screenshot_namer, :new_screenshots
69
69
 
70
70
  def initialize
71
71
  @assertions = []
72
+ @new_screenshots = []
72
73
  @screenshot_namer = CapybaraScreenshotDiff::ScreenshotNamer.new
73
74
  end
74
75
 
@@ -84,6 +85,14 @@ module CapybaraScreenshotDiff
84
85
  !@assertions.empty?
85
86
  end
86
87
 
88
+ def record_new_screenshot(name)
89
+ @new_screenshots.push(name)
90
+ end
91
+
92
+ def new_screenshots_present?
93
+ !@new_screenshots.empty?
94
+ end
95
+
87
96
  def verify(screenshots = CapybaraScreenshotDiff.assertions)
88
97
  return unless ::Capybara::Screenshot.active? && ::Capybara::Screenshot::Diff.fail_on_difference
89
98
 
@@ -102,6 +111,7 @@ module CapybaraScreenshotDiff
102
111
 
103
112
  def reset
104
113
  @assertions.clear
114
+ @new_screenshots.clear
105
115
  @screenshot_namer = CapybaraScreenshotDiff::ScreenshotNamer.new
106
116
  end
107
117
  end
@@ -120,6 +130,9 @@ module CapybaraScreenshotDiff
120
130
  def_delegator :registry, :assertions
121
131
  def_delegator :registry, :assertions_present?
122
132
  def_delegator :registry, :failed_assertions
133
+ def_delegator :registry, :record_new_screenshot
134
+ def_delegator :registry, :new_screenshots
135
+ def_delegator :registry, :new_screenshots_present?
123
136
  def reset
124
137
  notify_reporters(registry.assertions)
125
138
  registry.reset
@@ -65,6 +65,7 @@ module Capybara
65
65
  mattr_accessor(:delayed) { true }
66
66
  mattr_accessor :area_size_limit
67
67
  mattr_accessor(:fail_if_new) { !ENV["CI"].nil? && !ENV["CI"].empty? }
68
+ mattr_accessor(:pending_if_new) { false }
68
69
  mattr_accessor(:fail_on_difference) { true }
69
70
  mattr_accessor :color_distance_limit
70
71
  mattr_accessor(:enabled) { true }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capybara-screenshot-diff
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.12.0
4
+ version: 1.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Uwe Kubosch
@@ -77,17 +77,21 @@ extensions: []
77
77
  extra_rdoc_files: []
78
78
  files:
79
79
  - CHANGELOG.md
80
+ - CODE_OF_CONDUCT.md
80
81
  - LICENSE.txt
81
82
  - Rakefile
82
83
  - capybara-screenshot-diff.gemspec
83
84
  - docs/RELEASE_PREP.md
84
85
  - docs/UPGRADING.md
86
+ - docs/architecture.md
85
87
  - docs/ci-integration.md
86
88
  - docs/configuration.md
87
89
  - docs/docker-testing.md
88
90
  - docs/drivers.md
89
91
  - docs/framework-setup.md
92
+ - docs/images/snap_diff_annotated.png
90
93
  - docs/images/snap_diff_web_ui.png
94
+ - docs/migration-guide.md
91
95
  - docs/organization.md
92
96
  - docs/reporters.md
93
97
  - docs/thread_safety.md
@@ -149,7 +153,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
149
153
  - !ruby/object:Gem::Version
150
154
  version: '0'
151
155
  requirements: []
152
- rubygems_version: 4.0.6
156
+ rubygems_version: 4.0.16
153
157
  specification_version: 4
154
158
  summary: Track your GUI changes with diff assertions
155
159
  test_files: []