capybara-storyboard 0.3.0 → 0.4.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 +8 -0
- data/README.md +11 -0
- data/docs/visual-regression.md +4 -1
- data/lib/capybara/storyboard/session.rb +52 -0
- data/lib/capybara/storyboard/test_helper.rb +1 -1
- data/lib/capybara/storyboard/version.rb +1 -1
- data/skills/visual-regression-test/SKILL.md +3 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3bf6a851426d1aa00542d1d81071115072cd603519243887686156f178c62d57
|
|
4
|
+
data.tar.gz: 145f880b26d5d6ae6b8042f2434b398bb018f7d0b646cc5fc0922cd9ed25d509
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b73fed754aafe430f72452947b62f3ebb50480b3deeeea2c3dff00f6296d17297eaa96004c94d12908838dedbde58ac5ff966db331003e628fc3b639d9312129
|
|
7
|
+
data.tar.gz: 6f61ca195317e9c69f7cd476e158d55b48f86fc1d072a60829a93a780527176d94d0a5c1bf44cb5137e8ddbd6739cd7f4081d12f84c850e9991bcd39b6ac4a6f
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.4.0] - 2026-08-12
|
|
4
|
+
|
|
5
|
+
- Replace wholly-numeric path segments in `visit` paths with `N` in screenshot filenames
|
|
6
|
+
(e.g. `visit '/observations/20/edit'` now produces `visit_observations_N_edit.png`), so
|
|
7
|
+
varying record IDs no longer break visual-regression pairing between runs. Migration note:
|
|
8
|
+
filenames change for numeric-ID visits, so the first run after upgrading shows one round of
|
|
9
|
+
added/deleted images when compared against an older baseline.
|
|
10
|
+
|
|
3
11
|
## [0.3.0] - 2026-07-23
|
|
4
12
|
|
|
5
13
|
- Fix `NoMethodError` / spurious "skipped after error" warnings when a page navigation happens between setup and a stability poll, by treating non-finite poll results (nil/NaN/Infinity) as "measurement lost" and re-arming the observer
|
data/README.md
CHANGED
|
@@ -171,6 +171,17 @@ order in which actions occurred. For example:
|
|
|
171
171
|
Non-ASCII descriptions and labels (e.g. Japanese) are preserved as-is in file and directory
|
|
172
172
|
names; only symbols and whitespace are replaced with underscores.
|
|
173
173
|
|
|
174
|
+
For `visit`, wholly-numeric path segments are additionally replaced with `N` before
|
|
175
|
+
sanitization, e.g. `visit '/observations/20/edit'` produces `001_visit_observations_N_edit.png`
|
|
176
|
+
rather than embedding the `20`. Record IDs vary between test runs and between branches, and a
|
|
177
|
+
filename that varies with them stops a visual-regression tool from pairing the same screen
|
|
178
|
+
across two runs, which reports it as added + deleted instead of comparing it. This only
|
|
179
|
+
replaces path segments that are *entirely* digits (`user42` and `h2` are left as-is), only
|
|
180
|
+
applies to `visit`, and only touches the path — the query string and fragment are untouched
|
|
181
|
+
(`/search?id=20` stays `search_id_20`). Locators passed to `click_on`, `fill_in`, and friends
|
|
182
|
+
keep their digits. If you want a specific ID to appear in a filename anyway, use
|
|
183
|
+
`storyboard_screenshot(label)` to build the label yourself.
|
|
184
|
+
|
|
174
185
|
The default output root is `<Rails.root>/tmp/screenshots` (overridable, see
|
|
175
186
|
[Configuration](#configuration)).
|
|
176
187
|
|
data/docs/visual-regression.md
CHANGED
|
@@ -96,7 +96,10 @@ The compare job uploads two artifacts:
|
|
|
96
96
|
output and would cause over-selection.
|
|
97
97
|
- A large batch of "added"/"deleted" images clustered under one example usually means a
|
|
98
98
|
Capybara step was inserted or removed in that example, shifting every later step's `NNN`
|
|
99
|
-
sequence number — not many independent regressions.
|
|
99
|
+
sequence number — not many independent regressions. Numeric `visit` path segments are
|
|
100
|
+
already normalized to `N` by capybara-storyboard, so a differing record ID there is not a
|
|
101
|
+
cause — a shifted `NNN` is usually the remaining explanation. (An ID in a query string, as
|
|
102
|
+
in `/search?user_id=42`, is not normalized and can still shift a filename.)
|
|
100
103
|
- Diff images are linked via artifact URLs rather than embedded in the PR comment, because
|
|
101
104
|
GitHub's Markdown image embedding requires a URL its camo proxy can fetch unauthenticated,
|
|
102
105
|
and artifact URLs require authentication.
|
|
@@ -12,6 +12,9 @@ module Capybara
|
|
|
12
12
|
# of Capybara and RSpec hooks: a Session can be built with a plain example
|
|
13
13
|
# double and an injected +output_root+.
|
|
14
14
|
class Session
|
|
15
|
+
PATH_ID_PLACEHOLDER = 'N'
|
|
16
|
+
private_constant :PATH_ID_PLACEHOLDER
|
|
17
|
+
|
|
15
18
|
def initialize(example:, enabled:, output_root: nil)
|
|
16
19
|
@example = example
|
|
17
20
|
@enabled = enabled
|
|
@@ -34,6 +37,31 @@ module Capybara
|
|
|
34
37
|
capture_with_label(page, label)
|
|
35
38
|
end
|
|
36
39
|
|
|
40
|
+
# Automatic screenshot for a path-shaped DSL action (currently only
|
|
41
|
+
# #visit). Same as #auto except wholly-numeric path segments in the detail
|
|
42
|
+
# are collapsed to N first, so /observations/20/edit and
|
|
43
|
+
# /observations/33/edit yield one stable filename. Record ids vary between
|
|
44
|
+
# runs and between branches; a varying filename stops a visual-regression
|
|
45
|
+
# tool from pairing the two sides by path, which reports the same screen
|
|
46
|
+
# as added + deleted instead of comparing it.
|
|
47
|
+
#
|
|
48
|
+
# Deliberately a separate entry point rather than a branch inside #auto:
|
|
49
|
+
# Session stays ignorant of which action names are path-shaped, and the
|
|
50
|
+
# caller declares it by choosing the method (as with #auto vs #manual).
|
|
51
|
+
# Locators passed to click_link/fill_in/... are human-written fixed
|
|
52
|
+
# strings, so they keep their digits and keep using #auto.
|
|
53
|
+
#
|
|
54
|
+
# The enabled/suppressed guards are repeated here rather than left to
|
|
55
|
+
# #auto because Ruby evaluates arguments before the call: without them,
|
|
56
|
+
# every visit in a disabled suite would normalize a path only for #auto to
|
|
57
|
+
# discard it, breaking the "disabled -> zero overhead" contract.
|
|
58
|
+
def auto_path(page, action, path)
|
|
59
|
+
return unless @enabled
|
|
60
|
+
return if suppressed?
|
|
61
|
+
|
|
62
|
+
auto(page, action, normalize_path_ids(path))
|
|
63
|
+
end
|
|
64
|
+
|
|
37
65
|
# Manual screenshot hook. Like #auto, captured only when enabled. For an
|
|
38
66
|
# unconditional screenshot, use Capybara's own save_screenshot. The page
|
|
39
67
|
# is passed explicitly rather than held as state.
|
|
@@ -144,6 +172,30 @@ module Capybara
|
|
|
144
172
|
def sanitize(text)
|
|
145
173
|
text.to_s.gsub(/[^\p{Word}-]/, '_').gsub(/_+/, '_').gsub(/\A_|_\z/, '')
|
|
146
174
|
end
|
|
175
|
+
|
|
176
|
+
# Replaces every wholly-numeric path segment with N (/observations/20/edit
|
|
177
|
+
# -> /observations/N/edit). Segment-based on purpose: only a segment that
|
|
178
|
+
# is *nothing but* digits is a record id, so user42, h2 and v2 are left
|
|
179
|
+
# alone.
|
|
180
|
+
#
|
|
181
|
+
# The query/fragment is split off and left untouched — an id there sits in
|
|
182
|
+
# a value (?id=20), not a segment, and rewriting it would need parameter
|
|
183
|
+
# parsing for no gain. Splitting on / with -1 keeps empty segments, so a
|
|
184
|
+
# trailing slash and a full URL's // both survive round-tripping (the host
|
|
185
|
+
# segment of http://example.com/x/20 is non-numeric, so a full URL needs
|
|
186
|
+
# no special case).
|
|
187
|
+
#
|
|
188
|
+
# Runs BEFORE #sanitize, which would otherwise collapse / into _ and make
|
|
189
|
+
# segment boundaries unrecoverable. \A\d+\z is ASCII-only by design: URL
|
|
190
|
+
# path ids are ASCII digits, and preserving Unicode is #sanitize's job.
|
|
191
|
+
def normalize_path_ids(path)
|
|
192
|
+
head, separator, tail = path.to_s.partition(/[?#]/)
|
|
193
|
+
normalized =
|
|
194
|
+
head.split('/', -1).map do |segment|
|
|
195
|
+
segment.match?(/\A\d+\z/) ? PATH_ID_PLACEHOLDER : segment
|
|
196
|
+
end
|
|
197
|
+
"#{normalized.join('/')}#{separator}#{tail}"
|
|
198
|
+
end
|
|
147
199
|
end
|
|
148
200
|
end
|
|
149
201
|
end
|
|
@@ -233,7 +233,9 @@ npx reg-cli tmp/vrt/after tmp/vrt/before tmp/vrt/diff \
|
|
|
233
233
|
directory). `1` means "there's a diff, go verify it," not failure.
|
|
234
234
|
- Since both sets ran the same spec, filenames match across the two sets and reg-cli pairs them
|
|
235
235
|
automatically by path. Images present on only one side are reported as added/deleted — this
|
|
236
|
-
happens when the diff changed the spec's own steps
|
|
236
|
+
happens when the diff changed the spec's own steps (record IDs in `visit` **path segments** are
|
|
237
|
+
already normalized to `N` by the gem, so a differing ID there is not a cause — but an ID in a
|
|
238
|
+
query string, as in `/search?user_id=42`, is not normalized and can still shift a filename).
|
|
237
239
|
|
|
238
240
|
### 5. Verify the detected diffs
|
|
239
241
|
|