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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/CODE_OF_CONDUCT.md +129 -0
- data/docs/RELEASE_PREP.md +15 -31
- data/docs/architecture.md +270 -0
- data/docs/ci-integration.md +107 -77
- data/docs/configuration.md +16 -0
- data/docs/images/snap_diff_annotated.png +0 -0
- data/docs/migration-guide.md +286 -0
- data/docs/organization.md +1 -23
- data/lib/capybara/screenshot/diff/screenshot_matcher.rb +15 -1
- data/lib/capybara/screenshot/diff/version.rb +1 -1
- data/lib/capybara_screenshot_diff/cucumber.rb +9 -0
- data/lib/capybara_screenshot_diff/dsl.rb +28 -7
- data/lib/capybara_screenshot_diff/minitest.rb +6 -3
- data/lib/capybara_screenshot_diff/rspec.rb +8 -2
- data/lib/capybara_screenshot_diff/screenshot_assertion.rb +14 -1
- data/lib/capybara_screenshot_diff.rb +1 -0
- metadata +6 -2
data/docs/ci-integration.md
CHANGED
|
@@ -13,16 +13,7 @@ This sets up Capybara to serve static files and configures screenshot paths auto
|
|
|
13
13
|
|
|
14
14
|
## .gitignore Setup
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
```gitignore
|
|
19
|
-
# Screenshot diff artifacts (generated, not committed)
|
|
20
|
-
*.diff.png
|
|
21
|
-
*.base.png
|
|
22
|
-
*.diff.webp
|
|
23
|
-
*.base.webp
|
|
24
|
-
snap_diff_report.html
|
|
25
|
-
```
|
|
16
|
+
See the [Quick Start section](../README.md#quick-start-5-minutes) in the README for recommended `.gitignore` patterns.
|
|
26
17
|
|
|
27
18
|
Only commit the baseline screenshots (e.g., `homepage.png`). The `.base.png`, `.diff.png`, `.heatmap.diff.png`, and report files are regenerated on every test run.
|
|
28
19
|
|
|
@@ -36,15 +27,19 @@ Add to your test helper:
|
|
|
36
27
|
require 'capybara_screenshot_diff/reporters/html'
|
|
37
28
|
```
|
|
38
29
|
|
|
39
|
-
### 2.
|
|
30
|
+
### 2. Reusable composite action (recommended)
|
|
40
31
|
|
|
41
|
-
|
|
32
|
+
The simplest way — one step handles artifact upload, job summary, and PR comments:
|
|
42
33
|
|
|
43
34
|
```yaml
|
|
44
35
|
# .github/workflows/test.yml
|
|
45
36
|
jobs:
|
|
46
37
|
test:
|
|
47
38
|
runs-on: ubuntu-latest
|
|
39
|
+
permissions:
|
|
40
|
+
contents: read
|
|
41
|
+
pull-requests: write # Required for PR comments
|
|
42
|
+
|
|
48
43
|
steps:
|
|
49
44
|
- uses: actions/checkout@v6
|
|
50
45
|
|
|
@@ -52,38 +47,6 @@ jobs:
|
|
|
52
47
|
with:
|
|
53
48
|
bundler-cache: true
|
|
54
49
|
|
|
55
|
-
# Install libvips for the :vips driver (optional — skip if using :chunky_png)
|
|
56
|
-
- name: Install libvips
|
|
57
|
-
run: sudo apt-get install -y libvips-dev
|
|
58
|
-
|
|
59
|
-
- name: Run tests
|
|
60
|
-
run: bundle exec rake test
|
|
61
|
-
|
|
62
|
-
# Upload HTML report — renders inline in Actions UI (no download needed)
|
|
63
|
-
- name: Upload screenshot report
|
|
64
|
-
if: failure()
|
|
65
|
-
uses: actions/upload-artifact@v7
|
|
66
|
-
with:
|
|
67
|
-
name: screenshot-report
|
|
68
|
-
path: doc/screenshots/snap_diff_report.html
|
|
69
|
-
archive: false
|
|
70
|
-
retention-days: 2
|
|
71
|
-
|
|
72
|
-
# Upload full report with images (for offline review)
|
|
73
|
-
- name: Upload full screenshot report
|
|
74
|
-
if: failure()
|
|
75
|
-
uses: actions/upload-artifact@v7
|
|
76
|
-
with:
|
|
77
|
-
name: screenshot-report-full
|
|
78
|
-
path: doc/screenshots/
|
|
79
|
-
retention-days: 2
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
### 3. Or use the reusable action (one line)
|
|
83
|
-
|
|
84
|
-
Instead of the manual upload steps above, reference our composite action directly:
|
|
85
|
-
|
|
86
|
-
```yaml
|
|
87
50
|
- name: Run tests
|
|
88
51
|
run: bundle exec rake test
|
|
89
52
|
|
|
@@ -92,54 +55,123 @@ Instead of the manual upload steps above, reference our composite action directl
|
|
|
92
55
|
uses: snap-diff/snap_diff-capybara/.github/actions/upload-screenshots@master
|
|
93
56
|
with:
|
|
94
57
|
name: screenshots
|
|
58
|
+
pr-comment: 'true'
|
|
95
59
|
```
|
|
96
60
|
|
|
97
|
-
|
|
61
|
+
That's it. On failure, this will:
|
|
62
|
+
- Upload diff images + HTML report as artifacts
|
|
63
|
+
- Post a PR comment with links to the inline report and full artifact download
|
|
64
|
+
- Add a job summary with report links (visible in the Actions UI)
|
|
98
65
|
|
|
99
|
-
|
|
66
|
+
#### Inputs
|
|
100
67
|
|
|
101
68
|
| Input | Default | Description |
|
|
102
69
|
|-------|---------|-------------|
|
|
103
70
|
| `name` | (required) | Artifact name prefix |
|
|
104
71
|
| `report-path` | `doc/screenshots` | Path to HTML report directory |
|
|
105
72
|
| `retention-days` | `2` | Days to retain artifacts |
|
|
73
|
+
| `pr-comment` | `false` | Post PR comment with report link (requires `pull-requests: write`) |
|
|
106
74
|
|
|
107
|
-
|
|
75
|
+
#### Outputs
|
|
108
76
|
|
|
109
|
-
|
|
77
|
+
| Output | Description |
|
|
78
|
+
|--------|-------------|
|
|
79
|
+
| `report-url` | Direct URL to the inline HTML report artifact |
|
|
80
|
+
| `report-full-url` | Direct URL to the full report artifact (with images) |
|
|
110
81
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
uses: peter-evans/find-comment@v3
|
|
115
|
-
id: find-comment
|
|
116
|
-
with:
|
|
117
|
-
issue-number: ${{ github.event.pull_request.number }}
|
|
118
|
-
comment-author: 'github-actions[bot]'
|
|
119
|
-
body-includes: 'Screenshot diffs detected'
|
|
82
|
+
### 3. Ruby + libvips setup action
|
|
83
|
+
|
|
84
|
+
For consistent CI environments (libvips, font antialiasing disabled), use the setup action:
|
|
120
85
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
uses: peter-evans/create-or-update-comment@v5
|
|
86
|
+
```yaml
|
|
87
|
+
- uses: snap-diff/snap_diff-capybara/.github/actions/setup-ruby-and-dependencies@master
|
|
124
88
|
with:
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
edit-mode: replace
|
|
128
|
-
body: |
|
|
129
|
-
### Screenshot diffs detected
|
|
130
|
-
[View report](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}#artifacts)
|
|
89
|
+
ruby-version: '4.0'
|
|
90
|
+
cache-apt-packages: true
|
|
131
91
|
```
|
|
132
92
|
|
|
133
|
-
|
|
93
|
+
This installs Ruby, libvips (with apt caching), and disables font antialiasing for consistent rendering across CI runs.
|
|
94
|
+
|
|
95
|
+
#### Inputs
|
|
96
|
+
|
|
97
|
+
| Input | Default | Description |
|
|
98
|
+
|-------|---------|-------------|
|
|
99
|
+
| `ruby-version` | (required) | Ruby version to install |
|
|
100
|
+
| `cache-apt-packages` | `false` | Cache libvips apt packages for faster runs |
|
|
101
|
+
| `ruby-cache-version` | — | Bundler cache version key |
|
|
102
|
+
|
|
103
|
+
### 4. Full example with both actions
|
|
134
104
|
|
|
135
105
|
```yaml
|
|
136
106
|
jobs:
|
|
137
107
|
test:
|
|
108
|
+
runs-on: ubuntu-latest
|
|
109
|
+
timeout-minutes: 10
|
|
138
110
|
permissions:
|
|
139
111
|
contents: read
|
|
140
112
|
pull-requests: write
|
|
113
|
+
|
|
114
|
+
steps:
|
|
115
|
+
- uses: actions/checkout@v6
|
|
116
|
+
|
|
117
|
+
- uses: snap-diff/snap_diff-capybara/.github/actions/setup-ruby-and-dependencies@master
|
|
118
|
+
with:
|
|
119
|
+
ruby-version: '4.0'
|
|
120
|
+
cache-apt-packages: true
|
|
121
|
+
|
|
122
|
+
- run: bundle exec rake test
|
|
123
|
+
|
|
124
|
+
- uses: snap-diff/snap_diff-capybara/.github/actions/upload-screenshots@master
|
|
125
|
+
if: failure()
|
|
126
|
+
with:
|
|
127
|
+
name: screenshots
|
|
128
|
+
pr-comment: 'true'
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### 5. Manual setup (without composite actions)
|
|
132
|
+
|
|
133
|
+
If you prefer full control, here's the expanded YAML:
|
|
134
|
+
|
|
135
|
+
<details>
|
|
136
|
+
<summary>Expand manual setup</summary>
|
|
137
|
+
|
|
138
|
+
```yaml
|
|
139
|
+
jobs:
|
|
140
|
+
test:
|
|
141
|
+
runs-on: ubuntu-latest
|
|
142
|
+
steps:
|
|
143
|
+
- uses: actions/checkout@v6
|
|
144
|
+
|
|
145
|
+
- uses: ruby/setup-ruby@v1
|
|
146
|
+
with:
|
|
147
|
+
bundler-cache: true
|
|
148
|
+
|
|
149
|
+
- name: Install libvips
|
|
150
|
+
run: sudo apt-get install -y libvips-dev
|
|
151
|
+
|
|
152
|
+
- name: Run tests
|
|
153
|
+
run: bundle exec rake test
|
|
154
|
+
|
|
155
|
+
- name: Upload screenshot report
|
|
156
|
+
if: failure()
|
|
157
|
+
uses: actions/upload-artifact@v7
|
|
158
|
+
with:
|
|
159
|
+
name: screenshot-report
|
|
160
|
+
path: doc/screenshots/snap_diff_report.html
|
|
161
|
+
archive: false
|
|
162
|
+
retention-days: 2
|
|
163
|
+
|
|
164
|
+
- name: Upload full report with images
|
|
165
|
+
if: failure()
|
|
166
|
+
uses: actions/upload-artifact@v7
|
|
167
|
+
with:
|
|
168
|
+
name: screenshot-report-full
|
|
169
|
+
path: doc/screenshots/
|
|
170
|
+
retention-days: 2
|
|
141
171
|
```
|
|
142
172
|
|
|
173
|
+
</details>
|
|
174
|
+
|
|
143
175
|
## Update Baselines in CI
|
|
144
176
|
|
|
145
177
|
When intentional UI changes are made, baselines need to be re-recorded. You can do this locally:
|
|
@@ -152,6 +184,9 @@ git commit -m "chore: update screenshot baselines"
|
|
|
152
184
|
|
|
153
185
|
Or add a workflow that maintainers can trigger manually:
|
|
154
186
|
|
|
187
|
+
<details>
|
|
188
|
+
<summary>Expand update-baselines workflow</summary>
|
|
189
|
+
|
|
155
190
|
```yaml
|
|
156
191
|
# .github/workflows/update-baselines.yml
|
|
157
192
|
name: Update Screenshot Baselines
|
|
@@ -175,12 +210,10 @@ jobs:
|
|
|
175
210
|
with:
|
|
176
211
|
ref: ${{ inputs.branch }}
|
|
177
212
|
|
|
178
|
-
- uses:
|
|
213
|
+
- uses: snap-diff/snap_diff-capybara/.github/actions/setup-ruby-and-dependencies@master
|
|
179
214
|
with:
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
- name: Install libvips
|
|
183
|
-
run: sudo apt-get install -y libvips-dev
|
|
215
|
+
ruby-version: '4.0'
|
|
216
|
+
cache-apt-packages: true
|
|
184
217
|
|
|
185
218
|
- name: Record new baselines
|
|
186
219
|
run: RECORD_SCREENSHOTS=1 bundle exec rake test
|
|
@@ -195,14 +228,11 @@ jobs:
|
|
|
195
228
|
git push
|
|
196
229
|
```
|
|
197
230
|
|
|
231
|
+
</details>
|
|
232
|
+
|
|
198
233
|
**How it works:**
|
|
199
234
|
1. Go to Actions → "Update Screenshot Baselines" → "Run workflow"
|
|
200
235
|
2. Enter the branch name (e.g. your PR branch)
|
|
201
236
|
3. The workflow records new baselines, commits, and pushes
|
|
202
237
|
|
|
203
|
-
**Safety:**
|
|
204
|
-
- Only maintainers with write access can trigger `workflow_dispatch`
|
|
205
|
-
- The commit uses `git diff --staged --quiet ||` to skip empty commits
|
|
206
|
-
- `GITHUB_TOKEN` pushes don't trigger subsequent CI runs ([by design](https://docs.github.com/actions/using-workflows/events-that-trigger-workflows))
|
|
207
|
-
|
|
208
238
|
[← Back to README](../README.md)
|
data/docs/configuration.md
CHANGED
|
@@ -165,6 +165,22 @@ that does not have a corresponding previous image to compare against.
|
|
|
165
165
|
This can be useful in situations where you want to ensure
|
|
166
166
|
that every screenshot taken by your tests corresponds to an expected state of your application.
|
|
167
167
|
|
|
168
|
+
### Marks new screenshots as pending
|
|
169
|
+
|
|
170
|
+
To mark tests as pending (skipped) if a new screenshot is taken without a baseline, set:
|
|
171
|
+
|
|
172
|
+
```ruby
|
|
173
|
+
Capybara::Screenshot::Diff.pending_if_new = true
|
|
174
|
+
# Required in CI, because fail_if_new defaults to true there and raises before
|
|
175
|
+
# the pending marker is applied.
|
|
176
|
+
Capybara::Screenshot::Diff.fail_if_new = false
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
If `pending_if_new` is set to `true`, the test will be marked as skipped in teardown
|
|
180
|
+
when a new screenshot has no committed baseline to compare against.
|
|
181
|
+
This is complementary to `fail_if_new` (which raises immediately); `fail_if_new` takes precedence since it raises first.
|
|
182
|
+
This option is useful when you want to record new screenshots without blocking CI, but still track them as needing review.
|
|
183
|
+
|
|
168
184
|
### Screen shot save path
|
|
169
185
|
|
|
170
186
|
By default, `Capybara::Screenshot::Diff` saves screenshots to a
|
|
Binary file
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
# Migration Guide
|
|
2
|
+
|
|
3
|
+
Migrate your visual regression testing from other tools to `capybara-screenshot-diff`. This guide covers the most common migration paths.
|
|
4
|
+
|
|
5
|
+
## Why Switch?
|
|
6
|
+
|
|
7
|
+
| Factor | Percy / Chromatic | BackstopJS | `capybara-screenshot-diff` |
|
|
8
|
+
|--------|-------------------|------------|--------------------------|
|
|
9
|
+
| Pricing | Paid SaaS (snapshot limits) | Free | Free (MIT) |
|
|
10
|
+
| Infrastructure | Cloud service, API tokens | Node + Puppeteer | Ruby gem, no external services |
|
|
11
|
+
| Baselines | Hosted on their servers | Local files | Git (committed to repo) |
|
|
12
|
+
| Review | Web dashboard | HTML report | HTML report + GitHub PR comments |
|
|
13
|
+
| PR integration | GitHub app | Manual CI steps | Reusable GitHub Action |
|
|
14
|
+
| Offline | ❌ Requires internet | ✅ | ✅ |
|
|
15
|
+
| Diff in PRs | Screenshot in comment | Manual | Upload artifact + PR comment |
|
|
16
|
+
|
|
17
|
+
## From Percy
|
|
18
|
+
|
|
19
|
+
### Setup changes
|
|
20
|
+
|
|
21
|
+
**Before (Percy):**
|
|
22
|
+
```ruby
|
|
23
|
+
# Gemfile
|
|
24
|
+
gem 'percy-capybara'
|
|
25
|
+
|
|
26
|
+
# test helper
|
|
27
|
+
require 'percy/capybara'
|
|
28
|
+
|
|
29
|
+
# test
|
|
30
|
+
def test_homepage
|
|
31
|
+
visit '/'
|
|
32
|
+
Percy::Capybara.screenshot('homepage')
|
|
33
|
+
end
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**After (capybara-screenshot-diff):**
|
|
37
|
+
```ruby
|
|
38
|
+
# Gemfile
|
|
39
|
+
gem 'capybara-screenshot-diff'
|
|
40
|
+
|
|
41
|
+
# test helper
|
|
42
|
+
require 'capybara_screenshot_diff/minitest'
|
|
43
|
+
|
|
44
|
+
# test class
|
|
45
|
+
class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
|
|
46
|
+
include CapybaraScreenshotDiff::Minitest::Assertions
|
|
47
|
+
|
|
48
|
+
test "homepage" do
|
|
49
|
+
visit '/'
|
|
50
|
+
screenshot 'homepage'
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### What changes
|
|
56
|
+
|
|
57
|
+
| Concept | Percy | capybara-screenshot-diff |
|
|
58
|
+
|---------|-------|-------------------------|
|
|
59
|
+
| Baseline storage | Percy cloud | Committed to git (`doc/screenshots/`) |
|
|
60
|
+
| First run | Uploads to Percy | Saves locally, passes automatically |
|
|
61
|
+
| CI setup | `PERCY_TOKEN` env var | GitHub Action (3 lines) |
|
|
62
|
+
| Diff review | Percy dashboard | `snap_diff_report.html` or PR artifacts |
|
|
63
|
+
| Update baselines | Percy's "Approve" button | Delete file, re-run tests, commit |
|
|
64
|
+
| Snapshot limits | Paid plan dependent | Unlimited |
|
|
65
|
+
| Parallel builds | Built-in | Thread-safe with t-locals + mutex |
|
|
66
|
+
|
|
67
|
+
### CI migration
|
|
68
|
+
|
|
69
|
+
**Before (Percy GitHub Action):**
|
|
70
|
+
```yaml
|
|
71
|
+
- name: Percy Test
|
|
72
|
+
run: PERCY_TOKEN=${{ secrets.PERCY_TOKEN }} bundle exec rake test
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**After (capybara-screenshot-diff):**
|
|
76
|
+
```yaml
|
|
77
|
+
- uses: snap-diff/snap_diff-capybara/.github/actions/setup-ruby-and-dependencies@master
|
|
78
|
+
with:
|
|
79
|
+
ruby-version: '4.0'
|
|
80
|
+
- run: bundle exec rake test
|
|
81
|
+
- uses: snap-diff/snap_diff-capybara/.github/actions/upload-screenshots@master
|
|
82
|
+
if: failure()
|
|
83
|
+
with:
|
|
84
|
+
name: screenshots
|
|
85
|
+
pr-comment: 'true'
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Migration steps
|
|
89
|
+
|
|
90
|
+
1. **Remove Percy gem and configuration**
|
|
91
|
+
2. **Add `capybara-screenshot-diff`** to your Gemfile
|
|
92
|
+
3. **Replace `Percy::Capybara.screenshot` calls** with `screenshot` (or `match_screenshot` for RSpec)
|
|
93
|
+
4. **Run tests once** to generate baselines
|
|
94
|
+
5. **Commit baselines** (`git add doc/screenshots/`)
|
|
95
|
+
6. **Set up CI** with the GitHub Actions upload step
|
|
96
|
+
7. **Remove Percy integration** from CI
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## From Chromatic
|
|
101
|
+
|
|
102
|
+
### Setup changes
|
|
103
|
+
|
|
104
|
+
**Before (Chromatic + Storybook):**
|
|
105
|
+
```js
|
|
106
|
+
// .storybook/preview.js
|
|
107
|
+
import { withScreenshot } from 'chromatic';
|
|
108
|
+
|
|
109
|
+
export const decorators = [withScreenshot];
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**After (capybara-screenshot-diff):**
|
|
113
|
+
```ruby
|
|
114
|
+
# test/system/stories_test.rb
|
|
115
|
+
class StoriesTest < ApplicationSystemTestCase
|
|
116
|
+
test "landing page story" do
|
|
117
|
+
visit '/iframe.html?id=pages-landing--default'
|
|
118
|
+
screenshot 'stories/landing-page'
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Key differences
|
|
124
|
+
|
|
125
|
+
| Concept | Chromatic | capybara-screenshot-diff |
|
|
126
|
+
|---------|-----------|-------------------------|
|
|
127
|
+
| Focus | Storybook components | Full-page system tests |
|
|
128
|
+
| Baseline | Chromatic cloud | Git-committed |
|
|
129
|
+
| Review | Chromatic web UI | HTML report + PR artifacts |
|
|
130
|
+
| CI integration | Chromatic GitHub App | GitHub Actions + PR comments |
|
|
131
|
+
| Thresholds | Visual catch (AI) | Configurable tolerance (numeric) |
|
|
132
|
+
|
|
133
|
+
### Migration approach
|
|
134
|
+
|
|
135
|
+
Chromatic is primarily for Storybook component testing. If you want to continue testing individual components:
|
|
136
|
+
|
|
137
|
+
1. **Replace with Capybara system tests** that visit each component's rendered page
|
|
138
|
+
2. **Use `crop:` option** to isolate specific elements: `screenshot 'button', crop: '.my-button'`
|
|
139
|
+
3. **Use `skip_area:` option** to ignore dynamic regions: `screenshot 'dashboard', skip_area: ['.timestamp']`
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## From BackstopJS
|
|
144
|
+
|
|
145
|
+
### Setup changes
|
|
146
|
+
|
|
147
|
+
**Before (BackstopJS):**
|
|
148
|
+
```json
|
|
149
|
+
// backstop.json
|
|
150
|
+
{
|
|
151
|
+
"id": "homepage",
|
|
152
|
+
"viewports": [{"width": 1280, "height": 1024}],
|
|
153
|
+
"scenarios": [{
|
|
154
|
+
"label": "Homepage",
|
|
155
|
+
"url": "http://localhost:3000",
|
|
156
|
+
"referenceUrl": "http://localhost:3000",
|
|
157
|
+
"selectors": ["document"]
|
|
158
|
+
}],
|
|
159
|
+
"paths": {
|
|
160
|
+
"bitmaps_reference": "backstop_data/bitmaps_reference",
|
|
161
|
+
"bitmaps_test": "backstop_data/bitmaps_test",
|
|
162
|
+
"html_report": "backstop_data/html_report"
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**After (capybara-screenshot-diff):**
|
|
168
|
+
```ruby
|
|
169
|
+
class HomepageTest < ApplicationSystemTestCase
|
|
170
|
+
test "homepage" do
|
|
171
|
+
visit '/'
|
|
172
|
+
screenshot 'homepage'
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Key differences
|
|
178
|
+
|
|
179
|
+
| Concept | BackstopJS | capybara-screenshot-diff |
|
|
180
|
+
|---------|-----------|-------------------------|
|
|
181
|
+
| Language | JavaScript + Node | Ruby (runs in test suite) |
|
|
182
|
+
| Dependencies | Node, Puppeteer/Chromium | Ruby gems + optional libvips |
|
|
183
|
+
| Test runner | Standalone CLI | Minitest, RSpec, Cucumber |
|
|
184
|
+
| Selectors | CSS selectors for scenarios | CSS selectors for crop/skip_area |
|
|
185
|
+
| Viewports | Per-scenario config | Global `window_size` setting |
|
|
186
|
+
| CI report | HTML report | HTML report + GitHub Actions |
|
|
187
|
+
| Stability | `misMatchThreshold` + `delay` | `tolerance` + `stability_time_limit` |
|
|
188
|
+
|
|
189
|
+
### Configuration mapping
|
|
190
|
+
|
|
191
|
+
| BackstopJS option | capybara-screenshot-diff equivalent |
|
|
192
|
+
|-------------------|-------------------------------------|
|
|
193
|
+
| `misMatchThreshold` | `tolerance` (0.0-1.0 scale, e.g. `0.01` = 1%) |
|
|
194
|
+
| `delay` | `stability_time_limit` (seconds) |
|
|
195
|
+
| `selectors` | `crop:` option with CSS selector |
|
|
196
|
+
| `hideSelectors` | `skip_area:` option with CSS selectors |
|
|
197
|
+
| `removeSelectors` | N/A — use `skip_area` or modify DOM before screenshot |
|
|
198
|
+
| `waitTimeout` | `wait:` option (defaults to `Capybara.default_max_wait_time`) |
|
|
199
|
+
| `viewports` | `window_size: [width, height]` |
|
|
200
|
+
| `onReadyScript` | Custom setup in your test's `setup` block |
|
|
201
|
+
|
|
202
|
+
### CI migration
|
|
203
|
+
|
|
204
|
+
**Before (BackstopJS in CI):**
|
|
205
|
+
```yaml
|
|
206
|
+
- run: npx backstop test --config=backstop.json
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
**After (capybara-screenshot-diff in CI):**
|
|
210
|
+
```yaml
|
|
211
|
+
- uses: snap-diff/snap_diff-capybara/.github/actions/setup-ruby-and-dependencies@master
|
|
212
|
+
- run: bundle exec rake test
|
|
213
|
+
- uses: snap-diff/snap_diff-capybara/.github/actions/upload-screenshots@master
|
|
214
|
+
if: failure()
|
|
215
|
+
with:
|
|
216
|
+
name: screenshots
|
|
217
|
+
pr-comment: 'true'
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Migration steps
|
|
221
|
+
|
|
222
|
+
1. **Remove BackstopJS configuration** (`backstop.json`, npm dependencies)
|
|
223
|
+
2. **Convert scenarios to Capybara tests** — each scenario becomes a `screenshot` call
|
|
224
|
+
3. **Map threshold and delay settings** to `tolerance` and `stability_time_limit`
|
|
225
|
+
4. **Run tests** to generate baselines
|
|
226
|
+
5. **Commit baselines** (`git add doc/screenshots/`)
|
|
227
|
+
6. **Update CI** to use the GitHub Actions setup
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## General Migration Checklist
|
|
232
|
+
|
|
233
|
+
- [ ] Remove old gem/npm dependencies
|
|
234
|
+
- [ ] Add `capybara-screenshot-diff` to Gemfile
|
|
235
|
+
- [ ] Require the appropriate adapter (`minitest`, `rspec`, or `cucumber`)
|
|
236
|
+
- [ ] Replace screenshot calls with `screenshot` / `match_screenshot`
|
|
237
|
+
- [ ] Configure `window_size` for consistent viewport dimensions
|
|
238
|
+
- [ ] Set `tolerance` or `perceptual_threshold` if your previous tool had a mismatch threshold
|
|
239
|
+
- [ ] Add `.gitignore` patterns for diff artifacts
|
|
240
|
+
- [ ] Run tests to generate baseline screenshots
|
|
241
|
+
- [ ] Commit baselines to git
|
|
242
|
+
- [ ] Set up CI with artifact upload
|
|
243
|
+
- [ ] Optional: add HTML reporter and PR commenting
|
|
244
|
+
|
|
245
|
+
## Common Gotchas
|
|
246
|
+
|
|
247
|
+
### "My baselines are on Percy/Chromatic servers"
|
|
248
|
+
|
|
249
|
+
You'll need to take fresh screenshots. Either:
|
|
250
|
+
- Visit each page and capture manually
|
|
251
|
+
- Run tests with `RECORD_SCREENSHOTS=1` to generate all baselines at once
|
|
252
|
+
|
|
253
|
+
### "I had hundreds of BackstopJS scenarios"
|
|
254
|
+
|
|
255
|
+
Start small. Migrate one test file at a time. The `screenshot_group` feature helps organize related screenshots:
|
|
256
|
+
```ruby
|
|
257
|
+
screenshot_group 'checkout'
|
|
258
|
+
screenshot 'step1'
|
|
259
|
+
screenshot 'step2'
|
|
260
|
+
# Produces: doc/screenshots/checkout/00_step1.png, 01_step2.png
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### "My tests are slow now"
|
|
264
|
+
|
|
265
|
+
Use the VIPS driver for ~50ms comparisons per image:
|
|
266
|
+
```ruby
|
|
267
|
+
gem 'ruby-vips'
|
|
268
|
+
Capybara::Screenshot::Diff.driver = :vips
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### "The diffs look different from what I'm used to"
|
|
272
|
+
|
|
273
|
+
Each tool uses different comparison algorithms:
|
|
274
|
+
- **Percy:** Proprietary pixel-level comparison with AI smoothing
|
|
275
|
+
- **Chromatic:** Visual catch algorithm (structure-aware)
|
|
276
|
+
- **BackstopJS:** Resemble.js pixel comparison
|
|
277
|
+
- **capybara-screenshot-diff:** Raw pixel difference with configurable tolerance
|
|
278
|
+
|
|
279
|
+
Start with default settings, then adjust `tolerance` or `perceptual_threshold` based on your needs.
|
|
280
|
+
|
|
281
|
+
## Need Help?
|
|
282
|
+
|
|
283
|
+
- [Architecture Overview](docs/architecture.md) — understanding how comparisons work
|
|
284
|
+
- [Configuration Reference](docs/configuration.md) — all available options
|
|
285
|
+
- [CI Integration](docs/ci-integration.md) — setting up in CI
|
|
286
|
+
- [GitHub Issues](https://github.com/snap-diff/snap_diff-capybara/issues) — ask questions
|
data/docs/organization.md
CHANGED
|
@@ -33,29 +33,7 @@ version control system (git).
|
|
|
33
33
|
|
|
34
34
|
Screenshots are compared to the previously COMMITTED version of the same screenshot.
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
When a screenshot differs, the gem generates temporary diff files alongside the baseline:
|
|
39
|
-
|
|
40
|
-
| Pattern | Description |
|
|
41
|
-
|---------|-------------|
|
|
42
|
-
| `*.base.png` | VCS checkout of the committed baseline |
|
|
43
|
-
| `*.diff.png` | Annotated diff with changes highlighted |
|
|
44
|
-
| `*.base.diff.png` | Annotated baseline with diff region marked |
|
|
45
|
-
| `*.heatmap.diff.png` | Heatmap of pixel differences |
|
|
46
|
-
| `snap_diff_report.html` | Interactive Web UI report |
|
|
47
|
-
|
|
48
|
-
Add these to `.gitignore`:
|
|
49
|
-
|
|
50
|
-
```gitignore
|
|
51
|
-
*.diff.png
|
|
52
|
-
*.base.png
|
|
53
|
-
*.diff.webp
|
|
54
|
-
*.base.webp
|
|
55
|
-
snap_diff_report.html
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
Clean up artifacts with `rake snap_diff:clean`.
|
|
36
|
+
**Note:** When a screenshot differs, diff artifacts (`.diff.png`, `.heatmap.diff.png`, etc.) are generated alongside the baseline. Add `*.diff.png`, `*.base.png`, `*.diff.webp`, `*.base.webp`, and `snap_diff_report.html` to your `.gitignore`. Clean up artifacts with `rake snap_diff:clean`.
|
|
59
37
|
|
|
60
38
|
## Screenshot groups
|
|
61
39
|
|
|
@@ -32,11 +32,25 @@ module Capybara
|
|
|
32
32
|
|
|
33
33
|
# Pre-computation: No need to compare without base screenshot
|
|
34
34
|
# NOTE: Consider to return PreValid Assertion Value Object with hard coded valid result
|
|
35
|
-
|
|
35
|
+
unless need_to_compare?
|
|
36
|
+
CapybaraScreenshotDiff.record_new_screenshot(screenshot_full_name)
|
|
37
|
+
return
|
|
38
|
+
end
|
|
36
39
|
|
|
37
40
|
create_screenshot_assertion(skip_stack_frames + 1, comparison_options)
|
|
38
41
|
end
|
|
39
42
|
|
|
43
|
+
# Captures a screenshot without comparing it to a baseline.
|
|
44
|
+
def capture
|
|
45
|
+
check_window_size!
|
|
46
|
+
prepare_screenshot_options
|
|
47
|
+
|
|
48
|
+
capture_options, comparison_options = extract_capture_and_comparison_options!(driver_options)
|
|
49
|
+
|
|
50
|
+
@snapshot.manager.create_output_directory_for(@snapshot.path)
|
|
51
|
+
capture_screenshot(capture_options, comparison_options)
|
|
52
|
+
end
|
|
53
|
+
|
|
40
54
|
private
|
|
41
55
|
|
|
42
56
|
def need_to_compare?
|
|
@@ -9,4 +9,13 @@ Before do
|
|
|
9
9
|
Capybara::Screenshot::BrowserHelpers.resize_window_if_needed
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
+
After do |scenario|
|
|
13
|
+
if !scenario.failed? && Capybara::Screenshot::Diff.pending_if_new && CapybaraScreenshotDiff.new_screenshots_present?
|
|
14
|
+
names = CapybaraScreenshotDiff.new_screenshots
|
|
15
|
+
skip_this_scenario("No baseline for: #{names.join(", ")}. Commit the captured screenshots to record them.")
|
|
16
|
+
end
|
|
17
|
+
ensure
|
|
18
|
+
CapybaraScreenshotDiff.reset
|
|
19
|
+
end
|
|
20
|
+
|
|
12
21
|
AfterAll { CapybaraScreenshotDiff.finalize_reporters! }
|