Skip to content

refactor: explicit baseline archiving + #inspect on assertion/result - #214

Merged
pftg merged 2 commits into
masterfrom
refactor/v2-immutable-assertion
Aug 22, 2026
Merged

refactor: explicit baseline archiving + #inspect on assertion/result#214
pftg merged 2 commits into
masterfrom
refactor/v2-immutable-assertion

Conversation

@pftg

@pftg pftg commented Aug 22, 2026

Copy link
Copy Markdown
Collaborator

5.5-lite items 5 + 8 (v2-core-redesign amendment). Behavior-preserving; no pre-existing test expectation changed.

Item 5 — explicit archive_baseline!

The verify path hid a file mutation inside the read-like validate call: on a passing comparison, ScreenshotAssertion.assert_image_not_changed silently FileUtils.mv-ed the base image over the actual image (D5/B1 — the reason validate was not idempotent).

  • ScreenshotAssertion#validate now asks the pure difference question, then calls the new named, idempotent #archive_baseline! on pass — same files written at the same times.
  • The legacy assert_image_not_changed class method delegates to the instance flow (dsl_test pins its combined behavior; kept byte-identical).
  • Class keeps the name ScreenshotAssertion per the 5.5-lite trim — no Verifier, no Result type, no rename.

Item 8 — #inspect

  • ScreenshotAssertion#inspect: one line with name, state (pending/matches/different), new/base paths — never triggers the lazy comparison.
  • ComparisonResult#inspect: one line with different?, failed_by, area size, region, difference level, paths. The reporter error message keeps its exact former byte format by using to_h.to_json directly (previously routed through inspect).

Gate evidence

Guard-first: 4 end-to-end guards pinning archive-on-pass / keep-on-failure through both validate! and delayed CapybaraScreenshotDiff.verify (commit 1), plus dsl_test's existing class-method pins.

Mutation checks (each applied, run, reverted):

  • (a) validate silently skips archive_baseline!3 tests red (the 2 new guards plus the pre-existing "cleans up base image when images are identical" pin in dsl_test.rb:247).
  • (b) both #inspect return nil3 inspect tests red (2 assertion + 1 result).

Tests: rake test:unit 448 runs / 0 failures (baseline 439 at 99c71a6, +9 new); rake test 481 runs / 0 failures / 6 skips; standardrb clean on changed files.

🤖 Generated with Claude Code

Summary by Sourcery

Separate baseline archiving from comparison validation and improve debugging visibility for assertions and results.

Bug Fixes:

  • Prevent baseline archiving from being an implicit side effect of validation while preserving archive-on-pass and retain-on-failure behavior.

Enhancements:

  • Make baseline archiving an explicit, idempotent assertion operation.
  • Add non-evaluating, one-line inspection summaries for screenshot assertions and comparison results while preserving the reporter’s existing error format.

Tests:

  • Add coverage for baseline lifecycle behavior across direct and delayed verification flows, explicit archiving, and inspection output.

pftg added 2 commits August 22, 2026 21:21
Guards the file-level side effect (base image moved over the actual
image on pass, kept on failure) through both validate! and the delayed
CapybaraScreenshotDiff.verify path, ahead of extracting the mutation
into an explicit archive step.
Extract the hidden file mutation from the verify read path into an
explicit ScreenshotAssertion#archive_baseline! (amendment item 5,
5.5-lite): validate now asks the pure difference question and then
archives the baseline as a named, idempotent step; the legacy
assert_image_not_changed class method delegates to the instance flow
unchanged. Behavior-preserving: same files written at the same times,
all pre-existing tests pass untouched.

Add one-line #inspect to ScreenshotAssertion (name, state, paths;
never triggers the comparison) and ComparisonResult (difference
metrics + paths) for 3am debugging (item 8). The reporter error
message keeps its exact byte format via to_h.to_json.
@sourcery-ai

sourcery-ai Bot commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Refactors screenshot verification so that baseline archiving is an explicit, idempotent operation and adds lightweight #inspect debug summaries to both screenshot assertions and comparison results while preserving existing external behavior and error formats.

Sequence diagram for explicit baseline archiving during validation

sequenceDiagram
    participant Caller
    participant ScreenshotAssertion
    participant Comparison
    participant FileSystem

    Caller->>ScreenshotAssertion: validate
    ScreenshotAssertion->>Comparison: different?
    alt comparison differs
        Comparison-->>ScreenshotAssertion: true
        ScreenshotAssertion->>Comparison: error_message
        ScreenshotAssertion-->>Caller: validation error
    else comparison matches
        Comparison-->>ScreenshotAssertion: false
        ScreenshotAssertion->>ScreenshotAssertion: archive_baseline!
        ScreenshotAssertion->>Comparison: base_image_path
        ScreenshotAssertion->>Comparison: image_path
        ScreenshotAssertion->>FileSystem: FileUtils.mv(base, image, force: true)
        ScreenshotAssertion-->>Caller: nil
    end
Loading

File-Level Changes

Change Details Files
Make baseline archiving an explicit, idempotent step in the screenshot verification flow while keeping validate/verify behavior byte-identical.
  • Refactor ScreenshotAssertion#validate to return the error string on differences and call #archive_baseline! on matches, instead of delegating directly to the class method.
  • Introduce ScreenshotAssertion#archive_baseline! that conditionally moves the base image over the actual image only when the comparison passes and the base exists, and make it safe to call multiple times.
  • Update ScreenshotAssertion.validate! and CapybaraScreenshotDiff.verify behavior via tests to ensure passing comparisons archive baselines and failing ones keep baselines for reporters.
  • Change ScreenshotAssertion.assert_image_not_changed to construct an instance, set caller/comparison, and delegate to the instance validate flow so legacy entry points retain semantics.
lib/snap_diff/screenshot_assertion.rb
test/unit/screenshot_assertion_test.rb
Add explicit one-line debug #inspect implementations for assertions and comparison results, ensuring they don’t trigger expensive comparisons and are distinct from error serialization.
  • Implement ScreenshotAssertion#inspect to report name, state (no comparison/pending/matches/different), and new/base image paths without forcing the comparison to run.
  • Implement ComparisonResult#inspect as a detailed, single-line summary of difference metrics (different?, failed_by, area_size, region, difference_level, paths).
  • Add unit tests verifying ScreenshotAssertion#inspect does not process comparisons, correctly reflects state after validation, and stays single-line.
  • Add a unit test verifying ComparisonResult#inspect includes key metrics and stays single-line.
lib/snap_diff/screenshot_assertion.rb
lib/snap_diff/comparison_result.rb
test/unit/screenshot_assertion_test.rb
test/unit/difference_test.rb
Preserve the exact reporter error message format by switching to direct JSON serialization of the difference hash.
  • Change Default reporter’s build_error_message to use difference.to_h.to_json instead of difference.inspect so that inspect can be repurposed for human-readable summaries.
  • Confirm via tests and description that reporter error output remains byte-identical to previous behavior.
lib/capybara/screenshot/diff/reporters/default.rb

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Aug 22, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@pftg, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 19 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 621bf409-899f-4cdc-86e9-d06b587516b7

📥 Commits

Reviewing files that changed from the base of the PR and between 99c71a6 and 92c28af.

📒 Files selected for processing (5)
  • lib/capybara/screenshot/diff/reporters/default.rb
  • lib/snap_diff/comparison_result.rb
  • lib/snap_diff/screenshot_assertion.rb
  • test/unit/difference_test.rb
  • test/unit/screenshot_assertion_test.rb

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've reviewed your changes and they look great!

Sourcery assessment

Needs a human reviewer. On a passing comparison, the code moves the baseline file over the captured image and removes the temporary baseline, so a mistaken result can leave filesystem artifacts altered after the code is reverted. The affected screenshots can be regenerated or repaired, making the impact bounded rather than permanent application-data loss.


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@pftg
pftg merged commit cb05144 into master Aug 22, 2026
8 checks passed
@pftg
pftg deleted the refactor/v2-immutable-assertion branch August 22, 2026 19:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant