test(regression): 100% E2E coverage for CLI configs (PER-8250)#2312
Conversation
Covers every non-excluded CLI config option (percy/snapshot/discovery/ project + cli-snapshot static/sitemap + per-snapshot capture options) via `percy snapshot --dry-run`, asserting the CLI loads & validates each with no "Invalid config:" output. Runs token-free and discovery-free, so it can gate every PR in CI. Includes a negative self-test fixture proving the validator detector fires. PER-8250
…s (Track V) New pages + snapshots.yml entries exercise scope/scopeOptions, per-snapshot percyCSS override, execute + additionalSnapshots, domTransformation, discovery.scrollToBottom, disableShadowDOM, forceShadowAsLightDOM, and responsiveSnapshotCapture. Visual diffs are reviewed via Percy's dashboard on token-gated runs; the suite skips cleanly without PERCY_TOKEN. Bumped Track C expected snapshot count 16 -> 25 to match. PER-8250
Adds gated server routes that record the headers/auth/cookies/user-agent Percy sends during discovery plus a cross-origin disallowed-hostname probe. functional.test.js runs one real snapshot and asserts on those server observations (robust to log-format changes) for discovery.requestHeaders, authorization, cookies, userAgent, captureSrcset and disallowedHostnames. Token-gated; skips cleanly without PERCY_TOKEN. Server-route behavior is verified token-free; the end-to-end Percy assertions run when a token is set. PER-8250
…cks in CI Adds COVERAGE.md (per-option E2E coverage matrix with explicit onlyAutomate exclusions), rewrites the regression README around the three tracks, and adds config-validation (token-free) + functional (token-gated) steps to the regression job in test.yml. PER-8250
- lib/percy-cli.js: justify spawn shell:true with a nosemgrep comment (static, test-controlled args — no injection surface; mirrors regression.test.js). - functional-discovery.html: load the cross-origin disallowed-host probe via @import instead of a <link> so it needs no Subresource Integrity hash (meaningless for a dynamic localhost test resource); discovery still attempts the request. PER-8250
…p OSS alert The nosemgrep comment suppressed spawn-shell-true for the workflow exit code, but GitHub code-scanning (Semgrep OSS) still surfaced the suppressed finding as an alert and failed the check. Eliminate it instead: npx resolves via PATH without a shell (this suite is Linux-only) and args are passed as an array, so shell:true was unnecessary and there is no command-injection surface. PER-8250
Claude Code PR ReviewPR: #2312 • Head: fb9ffce • Reviewers: stack:code-reviewer SummaryTest-only PR extending the Review Table
Findings
Schema & behavioral claims were cross-checked against Verdict: PASS — No High/Critical issues. Two Medium findings (adopt the shared |
Coverage audit: ~3% of reachable options not yet exercisedVerified the fixtures against the schema source of truth ( 1. 2. 3. Server mode ( Items 1–2 are two-line additions that make the literal-100% claim accurate; item 3 is optional. Great PR overall — the Track C |
…free) Reviewer feedback: the regression project's builds showed only 1 snapshot and read as baseline-only. Root cause: the functional track was a second `percy snapshot` invocation that uploaded its own 1-snapshot build on the same commit, superseding the 25-snapshot visual build. Fix: run the functional track with `--debug` (skipUploads). Discovery still runs — the browser fetches every gated resource so the servers verify the headers/auth/cookies/user-agent/srcset/disallowed-host behavior — but no Percy build is created. This makes the track token-free (now runs on every PR like the config track) and leaves the visual track as the sole build creator, so the PR's single build carries all visual snapshots and compares against the master baseline as a proper head build. Also tightened the captureSrcset assertion to the discriminating 2x candidate. PER-8250
…ayout, serve) Addresses reviewer's coverage audit: 1. regions[].elementSelector.elementXpath — add a region using the xpath selector form (all-config.yml); previously only elementCSS + boundingBox. 2. algorithm: layout — the same new region uses the layout enum value, which no fixture/region exercised before. 3. server mode (serve) — add a static-site/ fixture covered by a new Track C case (percy snapshot <dir> --dry-run --clean-urls). The /snapshot/server 'port' option is not reachable via the CLI (no --port flag; not set for directories), so it's documented as a non-goal in COVERAGE.md. Track C now 5 cases; all-config.yml stays at 25 snapshots. PR-2312 review follow-up. PER-8250
|
@pranavz28 thanks for the careful audit — all three gaps are now closed in
|
Claude Code PR ReviewPR: #2312 • Head: b04f42f • Reviewers: stack:code-reviewer SummaryRe-review of the test-only PR adding three regression tracks (config-validation, visual, functional discovery) to Review Table
FindingsPrior findings — all verified resolved:
Remaining (all Low / nits, none blocking):
Verdict: PASS — Clean, well-engineered test-only PR; all prior findings genuinely resolved (verified against core source), only Low/nit items remain, none blocking merge. |
Verification — the suite was mutation-tested (it catches regressions, not just passes)To prove the specs actually fail when an option changes (and only the affected spec moves), each track was mutation-tested. The real Track C (config-validation, token-free): set Track F (functional, token-free): each mutation fails its own server-observation assertion → ✅
Track V (visual): baseline build on
The methodology is documented in |
Summary
Adds 100% E2E coverage for the
percy snapshotCLI config surface(PER-8250). The existing
test/regression/harness covered only a subset of asset-discovery options;this extends it to every non-excluded option across the
percy,snapshot,discovery, andprojectnamespaces plus the cli-snapshotstatic/sitemapand per-snapshot capture options.
Three complementary tracks (full per-option matrix in
test/regression/COVERAGE.md):config-validation.test.js) — token-freepercy snapshot --dry-runthat loads fixtures setting every option andasserts the CLI accepts them all (no
Invalid config:). This is theliteral-100% backbone and gates every PR (including forks) without a token.
Includes a negative self-test proving the validator actually fires.
regression.test.js, newpages/config-*.html) — render-affectingoptions reviewed as visual diffs: scope/scopeOptions, per-snapshot percyCSS
override, execute + additionalSnapshots, domTransformation,
discovery.scrollToBottom, disableShadowDOM, forceShadowAsLightDOM,
responsiveSnapshotCapture.
functional.test.js, gatedserver.jsroutes) — discoveryoptions asserted on what the test servers observed (robust to log-format
changes): requestHeaders, authorization, cookies, userAgent, captureSrcset,
disallowedHostnames.
CI: the
regressionjob intest.ymlnow runs config validation token-freealways, plus visual + functional with
PERCY_REGRESSION_TOKEN.Scope — what "100% coverage" means here
"100%" = every CLI config option reachable via
percy snapshotis exercisedend-to-end through the real CLI and validated — ~54 options across the
percy/snapshot/discovery/projectnamespaces plus the cli-snapshotstatic/sitemapand per-snapshot capture options. Coverage is layered:asserts the CLI accepts each with no
Invalid config:).assertions (Track F).
Non-visual options (e.g.
concurrency,retry,sync,deferUploads,project.*,readiness.*sub-options) are covered at the config-validitylevel — the CLI accepts and loads them — not with bespoke runtime-behavior
tests, by design.
Explicitly excluded: the 6
onlyAutomatesnapshot options —fullPage,freezeAnimation,freezeAnimatedImage,freezeAnimatedImageOptions,ignoreRegions,considerRegions— are unreachable via thepercy snapshotweb flow and belong to the SDK/Automate path (PER-8249), so they are not
covered here. CLI flags (
--allowed-hostname,--disable-cache, …) are 1:1wrappers over these config values and are covered at the value level.
Test-only changes; no production code touched.
Test plan
yarn test:regression:config— passes locally, token-free (12 assertionsincl. negative self-test; 25 + 8 snapshots enumerated, no
Invalid config:)recorded; auth route 401s without creds)
eslint test/regression/cleanPERCY_REGRESSION_TOKEN)🤖 Generated with Claude Code