fix: merge .percy.yml config options with snapshot options for serializeDOM#430
fix: merge .percy.yml config options with snapshot options for serializeDOM#430rishigupta1599 wants to merge 7 commits into
Conversation
…izeDOM Config options from .percy.yml (like widths, minHeight, enableJavaScript, etc.) were not being passed to PercyDOM.serialize(). Only per-snapshot options were used. Now merges both, with per-snapshot options taking priority. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
This PR is stale because it has been open for more than 14 days with no activity. Remove stale label or comment or this will be closed in 14 days. |
|
This PR was closed because it has been stalled for 28 days with no activity. |
…-config-with-serialize-dom
rishigupta1599
left a comment
There was a problem hiding this comment.
Claude Code Review (automated) — 2 inline finding(s). Full report in the PR comment below. Verdict: Failed - see PR comment.
| } | ||
| } | ||
| } | ||
| catch (Exception) { } |
There was a problem hiding this comment.
[Low] Empty catch swallows config-merge errors
catch (Exception) { } discards every error during config extraction with no log, so a malformed cliConfig silently contributes nothing and the user gets no signal.
Suggestion: Log at debug, matching the existing pattern: Log($"Error reading snapshot config: {e.Message}", "debug");
Reviewer: stack:code-review
Claude Code PR ReviewPR: #430 • Head: a6fd4fa • Reviewers: stack:code-review SummaryAdds Review Table
Findings
Verdict: FAIL — config-supplied |
…id InvalidCastException Ref: PER-8053
rishigupta1599
left a comment
There was a problem hiding this comment.
Claude Code Review (automated) — 2 inline finding(s). Full report in the PR comment below. Verdict: Passed.
| private static object ConvertJsonArray(JsonElement array) | ||
| { | ||
| var items = array.EnumerateArray().ToList(); | ||
| if (items.Count > 0 && items.All(item => item.ValueKind == JsonValueKind.Number && item.TryGetInt32(out _))) |
There was a problem hiding this comment.
[Low] Empty config widths: [] re-triggers the InvalidCastException
ConvertJsonArray only returns List<int> when items.Count > 0. An empty config array falls through to the second branch returning an empty List<object>. Since MergeSnapshotOptions still adds the widths key, CaptureResponsiveDom (line 774, ContainsKey("widths") true) then runs (List<int>)options["widths"] on a List<object> and throws — the same failure this PR fixes, for the empty-widths edge case.
Suggestion: Return List<int> for empty numeric arrays too, e.g. if (items.Count == 0 || items.All(item => item.ValueKind == JsonValueKind.Number && item.TryGetInt32(out _))), or make line 774 defensive.
Reviewer: stack:code-review
| return domSnapshots; | ||
| } | ||
|
|
||
| private static Dictionary<string, object> MergeSnapshotOptions(Dictionary<string, object>? options) |
There was a problem hiding this comment.
[Medium] No tests for the new merge/array-typing logic
MergeSnapshotOptions and ConvertJsonArray (including the widths-typing fix that was the prior FAIL) ship with no unit tests, though the repo has a Percy.Test project. Regressions in array typing or merge precedence would go uncaught.
Suggestion: Add tests covering: config widths array converting to List<int> consumable by CaptureResponsiveDom; per-call options overriding config; empty and mixed-type arrays; and absent/non-object snapshot config falling back cleanly.
Reviewer: stack:code-review
Claude Code PR ReviewPR: #430 • Head: 6dabd1f • Reviewers: stack:code-review SummaryAdds Review Table
Findings
Verdict: PASS — the widths conversion fix is correct and resolves the prior cast FAIL; remaining items (missing tests, empty-array edge case) are non-blocking Medium/Low. |
rishigupta1599
left a comment
There was a problem hiding this comment.
Claude Code Review (automated) — 2 inline finding(s). Full report in the PR comment below. Verdict: Passed.
| } | ||
| } | ||
| } | ||
| catch (Exception) { } |
There was a problem hiding this comment.
[Low] Silently swallowed merge error
catch (Exception) { } discards any failure while reading cliConfig.snapshot, so a misconfigured .percy.yml silently drops all config-seeded options with no diagnostic.
Suggestion: Log at debug level inside the catch (the file already has a Log(..., "debug") helper) so misconfiguration is diagnosable while still degrading gracefully.
Reviewer: stack:code-review
| return merged; | ||
| } | ||
|
|
||
| private static object ConvertJsonArray(JsonElement array) |
There was a problem hiding this comment.
[Low] ConvertJsonArray is untested
The added test only covers scalar (bool/string) merge precedence; the widths-style array conversion path has no direct coverage.
Suggestion: Add a case where cliConfig.snapshot.widths is a JSON number array and assert it converts to a typed List<int> and survives the merge.
Reviewer: stack:code-review
Claude Code PR ReviewPR: #430 • Head: 4f2e554 • Reviewers: stack:code-review SummaryMerges Review Table
Findings
Verdict: PASS — small, focused fix with correct precedence semantics, a deterministic test, and only Low-severity polish nits. |
rishigupta1599
left a comment
There was a problem hiding this comment.
Claude Code Review (automated) — 1 inline finding(s). Full report in the PR comment below. Verdict: Failed - see PR comment.
| if (isResponsiveSnapshotCapture(options)) { | ||
| domSnapshot = CaptureResponsiveDom(driver, cookies, options); | ||
| if (isResponsiveSnapshotCapture(mergedOptions)) { | ||
| domSnapshot = CaptureResponsiveDom(driver, cookies, mergedOptions); |
There was a problem hiding this comment.
[High] Config-seeded widths crashes responsive capture
This now passes mergedOptions into CaptureResponsiveDom. When widths comes from .percy.yml, MergeSnapshotOptions/JsonElementToObjectDeep convert it to List<object>, but CaptureResponsiveDom (line 774) hard-casts options["widths"] to List<int> and throws InvalidCastException. It's swallowed by Snapshot's outer catch, so a config-driven responsive snapshot that previously fell back to default widths now produces no snapshot at all.
Suggestion: Coerce widths at the consumption site regardless of element type:
List<int> widths = new List<int>();
if (options != null && options.TryGetValue("widths", out var raw)) {
if (raw is List<int> ints) widths = ints;
else if (raw is List<object> objs) widths = objs.Select(Convert.ToInt32).ToList();
}or route array conversion through the (currently unused) ConvertJsonArray, which already yields List<int> for homogeneous int arrays.
Reviewer: stack:code-review
Claude Code PR ReviewPR: #430 • Head: 17070dd • Reviewers: stack:code-review SummaryReplaces the prior per-call-wins-wholesale merge of Review Table
Findings
Verdict: FAIL — the deep-merge core is correct, but routing config-seeded options into the responsive path introduces a config-triggerable |
…rge conversion JsonElementToObjectDeep converted JSON arrays to List<object>, which broke responsive widths (selenium-dotnet hard-casts to List<int>; playwright-dotnet's IEnumerable<int> check missed List<object>). Convert all-integer arrays to List<int> so config-sourced widths flow through responsive capture. Ref: PER-8053
rishigupta1599
left a comment
There was a problem hiding this comment.
Claude Code Review (automated) — 1 inline finding(s). Full report in the PR comment below. Verdict: Passed.
| return result; | ||
| } | ||
|
|
||
| private static object ConvertJsonArray(JsonElement array) |
There was a problem hiding this comment.
[Low] Dead code: ConvertJsonArray is never called
ConvertJsonArray is a private static method with no call site. JsonElementToObjectDeep (used by MergeSnapshotOptions) already implements the all-integer→List<int> logic, so this method is unused and may trigger unused-member analyzer warnings.
Suggestion: Delete ConvertJsonArray, or route the array branch of JsonElementToObjectDeep through it to remove the duplication.
Reviewer: stack:code-review
Claude Code PR ReviewPR: #430 • Head: 042d9c8 • Reviewers: stack:code-review SummaryAdds Review Table
Findings
Adjudication applied: "merged options not in POST body" is intended (the CLI merges server-side); the test project targeting net10 runs in CI rather than locally; pre-existing patterns and test gaps are non-blocking. The prior FAIL is verified fixed — config Verdict: PASS |
…-config-with-serialize-dom # Conflicts: # Percy/Percy.cs
Summary
.percy.ymlwere not being passed toPercyDOM.serialize()MergeSnapshotOptions()helper that extractscliConfig.snapshotproperties and merges with user options, with per-snapshot options taking priorityTest plan
.percy.ymlconfig options are applied during DOM serialization🤖 Generated with Claude Code