mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-11 23:49:01 +02:00
`snapshot -a` exits 1 with "Selector matched multiple elements" on most real
pages, so /qa, /canary and /land-and-deploy silently produce reports whose
screenshots do not exist. Plain `screenshot <path>` is unaffected.
Refs are built as getByRole(role, {name}) and disambiguated with .nth() when
role+name repeats. That disambiguation cannot fire for a node with NO accessible
name: the locator degrades to getByRole(role) with no name filter, and the count
driving .nth() is taken from the FILTERED aria snapshot while getByRole matches
the unfiltered DOM. Measured on a live page: the tree surfaced 2 unnamed
paragraphs, the DOM had 9. Landmarks (banner/main/contentinfo) and paragraphs are
correctly unnamed per ARIA, so this is the common case rather than an edge case.
boundingBox() then hits Playwright strict mode, and the catch allowlisted only
timeout/closed/Target/Execution-context messages — so the strict-mode error was
re-thrown and aborted every remaining annotation.
Two changes:
- `.first()` before boundingBox(), so an ambiguous ref draws a box on its first
match instead of aborting. The heatmap path below has always tolerated this via
a bare `catch {}`; annotate was the only path that could be killed outright.
- the catch no longer re-throws on unrecognised messages. A box we cannot measure
is a box we do not draw, never a reason to lose the rest of the page. Set
BROWSE_DEBUG to see what was skipped.
Also: `-o` passed without `-a`/`-H` was silently ignored (exit 0, no file), which
reads as "screenshots are broken" rather than "you forgot a flag". It now warns
and points at `browse screenshot <path>`.
Verified by rebuilding both ways against the same page with 51 refs present:
before — "Selector matched multiple elements", no file written
after — exit 0, 229KB PNG
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
25 lines
733 B
HTML
25 lines
733 B
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head><title>Ambiguous refs fixture</title></head>
|
|
<body>
|
|
<!-- "Save" is a substring of "Save As": getByRole('button', { name: 'Save' })
|
|
matches BOTH buttons (Playwright name matching is substring by default),
|
|
so the "Save" ref trips strict mode without .first(). This is the
|
|
deterministic form of the field failure in PR #2601. -->
|
|
<header>
|
|
<h1>Ambiguity test page</h1>
|
|
</header>
|
|
<main>
|
|
<p>Paragraph one of plain content.</p>
|
|
<p>Paragraph two of plain content.</p>
|
|
<button>Save</button>
|
|
<button>Save As</button>
|
|
<button>Cancel</button>
|
|
<a href="#end">Jump to end</a>
|
|
</main>
|
|
<footer>
|
|
<p id="end">Footer content.</p>
|
|
</footer>
|
|
</body>
|
|
</html>
|