Playwright accessibility snapshot and axe-core attribute reporting mismatch
0 reputation · 10 Oct 2021, 15:51 UTC
0 reputation · 10 Oct 2021, 15:51 UTC
Goal: Verify that Playwright's page.accessibility.snapshot() reports the same ARIA attributes that axe‑core evaluates when auditing a page, specifically attributes like aria-describedby and aria-details that are currently omitted from the snapshot.
Constraint: The snapshot API is experimental and deliberately excludes certain ARIA relations, while axe‑core reads the DOM directly, causing divergent results and making cross‑browser accessibility assertions unreliable without additional normalization.
Unresolved: Whether Playwright should extend the snapshot to include omitted attributes and provide a unified, browser‑normalized accessibility tree, or leave this work to user‑land libraries.
Should Playwright augment accessibility.snapshot() to include omitted ARIA attributes? Should it supply a normalization layer for cross‑browser differences? Or should users handle discrepancies with external tools?
35275 reputation · 11 Oct 2021, 01:16 UTC
Playwright should not extend accessibility.snapshot() to include omitted ARIA attributes such as aria-describedby or aria-details. The snapshot is intended to reflect the browser's accessibility tree (name, role, state, value, description). Adding raw DOM attributes would blur that purpose and introduce browser‑specific inconsistencies. For attribute‑level audits, use axe‑core directly; combine the two tools when you need both tree‑level and rule‑based validation.
accessibility.snapshot() returns a JSON representation of the computed accessibility tree (name, role, value, description, etc.) and deliberately excludes raw ARIA attributes that are not mapped to accessibility properties.The mismatch arises because the two tools operate at different layers: snapshot = accessibility‑tree layer; axe‑core = DOM‑attribute layer. Extending the snapshot to include omitted attributes would require Playwright to duplicate axe‑core’s attribute inspection, which is outside its scope and would increase maintenance burden without providing a normalized cross‑browser tree.
\n<img src='x' aria-describedby='desc'> where the described element is hidden or not part of the tree.const snapshot = await page.accessibility.snapshot();\nCapture the JSON output.\naxe-cli or import { axe } from '@axe-core/playwright'):\nconst results = await axe.run(page);\nattributes (if any) with the violations reported by axe. You will see that the snapshot lacks the aria-describedby entry while axe may flag a missing or misused attribute.If you are testing inside a shadow DOM or an iframe, please confirm whether you are scoping the accessibility snapshot to that boundary (e.g., passing root option) because the recommendation may change if the snapshot omits elements that axe‑core can see.
Use comments to ask for clarification. Post a solution as an answer.
35,275 reputation · 10 Oct 2021, 20:55 UTC
To clarify the technical gap: page.accessibility.snapshot() captures the computed accessibility tree, which is the browser's internal interpretation of what a screen reader actually perceives. In contrast, axe-core audits the DOM and CSSOM to ensure the source code follows W3C specifications.
A critical distinction occurs when an attribute like aria-describedby points to an ID that does not exist or is hidden from the tree. In this scenario:
For verification, users can compare the Playwright snapshot output against the Accessibility tab in Chrome DevTools. If an attribute appears in the DOM but not in the DevTools accessibility properties, it will not appear in the Playwright snapshot regardless of whether axe-core flags it.