|
4 | 4 |
|
5 | 5 | # Capybara::Screenshot::Diff |
6 | 6 |
|
7 | | -Catch visual regressions before they ship. Screenshots taken during tests are automatically compared against committed baselines — if the UI changed, the test fails. |
| 7 | +Stop shipping UI bugs. Take screenshots in your Rails tests, commit baselines to git, and let CI catch visual regressions in pull requests — no cloud service, no subscription, runs entirely in your test suite. |
| 8 | + |
| 9 | +**Why this gem?** Percy and Chromatic cost money and send your screenshots to a third party. BackstopJS requires Node. This gem integrates directly into your Capybara tests, stores baselines in git, and works offline. |
8 | 10 |
|
9 | 11 | ## Quick Start |
10 | 12 |
|
11 | 13 | ```ruby |
12 | 14 | # Gemfile |
13 | 15 | gem 'capybara-screenshot-diff' |
| 16 | +gem 'ruby-vips' # Optional: 10x faster comparisons |
14 | 17 | ``` |
15 | 18 |
|
16 | 19 | ```ruby |
@@ -42,104 +45,108 @@ git commit -m "chore: add screenshot baselines" |
42 | 45 | bundle exec rake test # Second run compares against committed baselines |
43 | 46 | ``` |
44 | 47 |
|
45 | | -That's it. The first run saves baseline screenshots (always passes). Subsequent runs compare against them — if the UI changed, the test fails. Commit baselines to git so CI catches regressions. |
| 48 | +First run saves baseline screenshots to `doc/screenshots/` (always passes). Commit them to git. Subsequent runs compare against committed baselines — if the UI changed, the test fails. |
46 | 49 |
|
47 | | -> **CI note:** In CI, `fail_if_new` is `true` by default — new screenshots without a committed baseline will fail. Always commit your baselines before pushing. |
| 50 | +> **CI note:** `fail_if_new` is `true` by default in CI — new screenshots without a committed baseline will fail. Always commit baselines before pushing. |
48 | 51 |
|
49 | 52 | For RSpec, Cucumber, or non-Rails setup, see [Framework Setup](docs/framework-setup.md). |
50 | 53 |
|
51 | | -## What You Get |
| 54 | +## What Happens When a Screenshot Changes |
52 | 55 |
|
53 | | -When a screenshot differs, the test fails with a clear message: |
| 56 | +The test fails with a clear message and generates diff files: |
54 | 57 |
|
55 | 58 | ```text |
56 | 59 | Screenshot does not match for 'homepage': |
57 | 60 | ({"area_size":1250,"region":[0,19,199,83],"max_color_distance":42.5}) |
58 | 61 | ``` |
59 | 62 |
|
60 | | -And generates diff files for inspection: |
| 63 | +Open `doc/screenshots/homepage.diff.png` to see exactly what changed. If the change is intentional, delete the baseline and re-run to update it. |
61 | 64 |
|
62 | 65 | | File | Description | |
63 | 66 | |------|-------------| |
64 | 67 | | `homepage.png` | Committed baseline | |
65 | 68 | | `homepage.diff.png` | Visual diff with changes highlighted in red | |
66 | 69 | | `homepage.heatmap.diff.png` | Heatmap of pixel differences | |
67 | 70 |
|
68 | | -Enable the [HTML report](docs/reporters.md) for an interactive dashboard with side-by-side comparison, zoom, and annotation toggle. |
| 71 | +## Web UI for Reviewing Screenshot Changes |
| 72 | + |
| 73 | +Add one line to get an interactive dashboard for reviewing all screenshot differences: |
69 | 74 |
|
70 | | -**Compare any two images** without a browser — PDFs, generated images, CI artifacts: |
71 | 75 | ```ruby |
72 | | -Capybara::Screenshot::Diff.compare("baseline.png", "current.png") |
| 76 | +# test/test_helper.rb |
| 77 | +require 'capybara_screenshot_diff/reporters/html' |
73 | 78 | ``` |
74 | 79 |
|
75 | | -## Installation |
| 80 | +After tests run, open `doc/screenshots/snap_diff_report.html` — side-by-side comparison with 4 view modes (both/base/new/heatmap), per-image zoom, annotation toggle, keyboard navigation, and search. |
76 | 81 |
|
77 | | -```ruby |
78 | | -# Gemfile |
79 | | -gem 'capybara-screenshot-diff' |
| 82 | +**In GitHub Actions**, the report renders inline as a CI artifact — no download needed. Add a PR comment with a link to the report automatically: |
80 | 83 |
|
81 | | -# Optional: faster image processing (recommended) |
82 | | -gem 'ruby-vips' |
| 84 | +```yaml |
| 85 | +- name: Upload screenshot report |
| 86 | + if: failure() |
| 87 | + uses: snap-diff/snap_diff-capybara/.github/actions/upload-screenshots@master |
| 88 | + with: |
| 89 | + name: screenshots |
83 | 90 | ``` |
84 | 91 |
|
85 | | -Then run `bundle install`. |
| 92 | +See [CI Integration](docs/ci-integration.md) for the full GitHub Actions setup with PR commenting. |
86 | 93 |
|
87 | | -**Requirements:** Ruby 3.2+, Rails 7.1+. For the `:vips` driver: [libvips 8.9+](https://libvips.github.io/libvips/install.html). |
| 94 | +## Compare Any Two Images |
| 95 | +
|
| 96 | +Works without a browser — PDFs, generated images, CI artifacts: |
| 97 | +
|
| 98 | +```ruby |
| 99 | +result = Capybara::Screenshot::Diff.compare("baseline.png", "current.png") |
| 100 | +result.different? # => true if visually different |
| 101 | +result.quick_equal? # => true if byte-identical |
| 102 | +``` |
88 | 103 |
|
89 | 104 | ## Next Steps |
90 | 105 |
|
91 | 106 | - **Crop to element:** `screenshot "form", crop: "#main-form"` |
92 | 107 | - **Ignore regions:** `screenshot "dashboard", skip_area: [".timestamp"]` |
93 | | -- **Run in CI:** See [GitHub Actions setup](docs/ci-integration.md) |
94 | | -- **HTML report:** `require 'capybara_screenshot_diff/reporters/html'` — [details](docs/reporters.md) |
| 108 | +- **Disable animations:** `Capybara::Screenshot.disable_animations = true` |
| 109 | +- **Set window size:** `Capybara::Screenshot.window_size = [1280, 1024]` |
95 | 110 |
|
96 | | -## Tuning Flaky Tests |
| 111 | +## Handling Flaky Tests |
97 | 112 |
|
98 | | -**Defaults work for most Rails apps.** `blur_active_element`, `hide_caret`, and `fail_if_new` (in CI) are enabled automatically. |
| 113 | +Defaults work for most Rails apps — `blur_active_element`, `hide_caret`, and `fail_if_new` (in CI) are enabled automatically. |
99 | 114 |
|
100 | | -If you see inconsistent results, choose a color comparison method: |
| 115 | +If screenshots differ between CI and local, set a comparison threshold: |
101 | 116 |
|
102 | 117 | ```ruby |
103 | | -# Option 1: Perceptual (recommended, VIPS only) |
104 | | -Capybara::Screenshot::Diff.perceptual_threshold = 2.0 |
105 | | - |
106 | | -# Option 2: Tolerance-based comparison (legacy) |
107 | | -Capybara::Screenshot::Diff.tolerance = 0.0005 |
108 | | - |
109 | | -# Always set window_size for consistent dimensions |
110 | 118 | Capybara::Screenshot::Diff.configure do |screenshot, diff| |
111 | 119 | screenshot.window_size = [1280, 1024] |
| 120 | + diff.perceptual_threshold = 2.0 # Recommended for VIPS — ignores anti-aliasing |
| 121 | + # or: diff.tolerance = 0.001 # Default for VIPS, percentage-based |
112 | 122 | end |
113 | 123 | ``` |
114 | 124 |
|
115 | | -| Use Case | VIPS `perceptual_threshold` | VIPS `tolerance` | ChunkyPNG `color_distance_limit` | |
116 | | -|----------|---------------------------|-----------------|--------------------------------| |
117 | | -| Cross-OS/browser testing | 2.0 (recommended) | — | — | |
118 | | -| Standard Rails apps | — | 0.001 (default) | 15 | |
119 | | -| Animated/complex pages | — | 0.01 | 30 | |
120 | | -| Pixel-perfect design | — | 0.0001 | 5 | |
121 | | - |
122 | | -**⚠️ Color methods are exclusive:** Use `perceptual_threshold` OR `color_distance_limit`, not both. But `tolerance` works with either — it's applied by default for VIPS (0.001). See [Choosing the Right Method](docs/configuration.md#choosing-the-right-color-comparison-method). |
| 125 | +See [Choosing the Right Method](docs/configuration.md#choosing-the-right-color-comparison-method) for detailed comparison options. |
123 | 126 |
|
124 | | -## Troubleshooting |
| 127 | +## Common Questions |
125 | 128 |
|
126 | | -**"No existing screenshot found"** — First run saves baselines. Run `bundle exec rake test` twice, then commit `doc/screenshots/`. |
| 129 | +**Why did my test pass on the first run?** First run always passes and saves baselines. Run again to compare. |
127 | 130 |
|
128 | | -**Screenshots differ between CI and local** — Use `tolerance: 0.001` or `perceptual_threshold: 2.0`. Set `window_size` for consistent dimensions. |
| 131 | +**How do I update baselines?** Delete the baseline file and re-run tests. Or delete all: `rm -rf doc/screenshots/ && bundle exec rake test`. |
129 | 132 |
|
130 | | -**Animations cause flaky diffs** — `Capybara::Screenshot.disable_animations = true` disables CSS animations/transitions before each screenshot. Or use `stability_time_limit: 1` to wait for animations to finish. |
| 133 | +**Animations make screenshots flaky** — `Capybara::Screenshot.disable_animations = true` freezes CSS animations/transitions before each capture. |
131 | 134 |
|
132 | | -**Dynamic content always differs** — `screenshot "page", skip_area: [".timestamp", "#ad-banner"]` |
| 135 | +**CI screenshots differ from local** — Set `window_size` for consistent dimensions and use `perceptual_threshold: 2.0` to ignore rendering differences. |
133 | 136 |
|
134 | 137 | **Debug mode** — `DEBUG=1 bundle exec rake test` keeps `.diff.png` files for inspection. |
135 | 138 |
|
| 139 | +## Installation |
| 140 | + |
| 141 | +**Requirements:** Ruby 3.2+, Rails 7.1+. For the `:vips` driver: [libvips 8.9+](https://libvips.github.io/libvips/install.html). |
| 142 | + |
136 | 143 | ## Advanced Topics |
137 | 144 |
|
138 | 145 | - [Framework Setup](docs/framework-setup.md) — Minitest, RSpec, Cucumber |
139 | 146 | - [Image Processing Drivers](docs/drivers.md) — VIPS, ChunkyPNG, perceptual threshold |
140 | 147 | - [Screenshot Organization](docs/organization.md) — groups, sections, cropping, multi-browser |
141 | 148 | - [Configuration Reference](docs/configuration.md) — all options explained |
142 | | -- [Reporters](docs/reporters.md) — HTML report, custom reporters |
| 149 | +- [Web UI & Custom Reporters](docs/reporters.md) — interactive report, custom reporters |
143 | 150 | - [CI & Non-Rails Integration](docs/ci-integration.md) — GitHub Actions, reusable action, baseline updates |
144 | 151 | - [Docker Testing](docs/docker-testing.md) — bin/dtest, recording baselines |
145 | 152 |
|
|
0 commit comments