diff --git a/docs/src/api/class-locator.md b/docs/src/api/class-locator.md index ba6dc91353..e665423550 100644 --- a/docs/src/api/class-locator.md +++ b/docs/src/api/class-locator.md @@ -154,7 +154,8 @@ Additional locator to match. * since: v1.49 - returns: <[string]> -Captures the aria snapshot of the given element. See [`method: LocatorAssertions.toMatchAriaSnapshot`] for the corresponding assertion. +Captures the aria snapshot of the given element. +Read more about [accessibility snapshots](../aria-snapshot.md) and [`method: LocatorAssertions.toMatchAriaSnapshot`] for the corresponding assertion. **Usage** diff --git a/docs/src/api/class-locatorassertions.md b/docs/src/api/class-locatorassertions.md index b48b3fce7e..f858e299a2 100644 --- a/docs/src/api/class-locatorassertions.md +++ b/docs/src/api/class-locatorassertions.md @@ -2109,7 +2109,7 @@ Expected options currently selected. * langs: - alias-java: matchesAriaSnapshot -Asserts that the target element matches the given accessibility snapshot. +Asserts that the target element matches the given [accessibility snapshot](../aria-snapshot.md). **Usage** diff --git a/docs/src/aria-snapshot.md b/docs/src/aria-snapshot.md new file mode 100644 index 0000000000..15f75ab84a --- /dev/null +++ b/docs/src/aria-snapshot.md @@ -0,0 +1,470 @@ +--- +id: aria-snapshot +title: "Accessibility snapshots" +--- + +## Overview + +Accessibility snapshots in Playwright are a YAML representation of elements on the page. +These snapshots can be stored and later compared to check if the page structure remains consistent or meets specified +expectations. + +The YAML format for accessibility trees is used to describe the hierarchical structure of the elements on a web page, +including their roles, attributes, values and text content. The YAML structure follows a tree-like syntax where each node +represents an accessible element, and indentation reflects nesting within the hierarchy. + +## Matching snapshots + +The [`method: LocatorAssertions.toMatchAriaSnapshot`] assertion is a method used in Playwright to match the accessible +structure of a page against a defined accessibility snapshot template. This helps in verifying that the page's state +meets testing expectations. + +**Example**: Match a heading element + +```js +await page.setContent(`

title

`); +await expect(page.locator('body')).toMatchAriaSnapshot(` + - heading "title" +`); +``` + +```python sync +page.set_content("

title

") +page.locator("body").to_match_aria_snapshot(""" + - heading "title" +""") +``` + +```python async +await page.set_content("

title

") +await page.locator("body").to_match_aria_snapshot(""" + - heading "title" +""") +``` + +```java +page.setContent("

title

"); +page.locator("body").expect().toMatchAriaSnapshot(""" + - heading "title" +"""); +``` + +```csharp +await page.SetContentAsync("

title

"); +await Expect(page.Locator("body")).ToMatchAriaSnapshotAsync(@" + - heading ""title"" +"); +``` + +**Example**: Match list + +Lists can be matched partially. + +```js +await page.setContent(` + +`); +await expect(page.locator('body')).toMatchAriaSnapshot(` + - list "my list": + - listitem: one + - listitem: three + - listitem: five +`); +``` + +```python sync +page.set_content(""" + +""") +page.locator("body").to_match_aria_snapshot(""" + - list "my list": + - listitem: one + - listitem: two +""") +``` + +```python async +await page.set_content(""" + +""") +await page.locator("body").to_match_aria_snapshot(""" + - list "my list": + - listitem: one + - listitem: three + - listitem: five +""") +``` + +```java +page.setContent(""" + +"""); +page.locator("body").expect().toMatchAriaSnapshot(""" + - list "my list": + - listitem: one + - listitem: three + - listitem: five +"""); +``` + +```csharp +await page.SetContentAsync(@" + +"); +await Expect(page.Locator("body")).ToMatchAriaSnapshotAsync(@" + - list ""my list"": + - listitem: one + - listitem: three + - listitem: five +"); +``` + +**Example**: Matching Elements with Attributes + +Test elements with ARIA attributes, such as `checked`, `disabled`, `expanded`, `level`, `pressed` and `selected`, by specifying the attribute within square brackets. + +```js +await page.setContent(` + +`); + +await expect(page.locator('body')).toMatchAriaSnapshot(` + - checkbox [checked=true] +`); +``` + +```python sync +page.set_content("") +page.locator("body").to_match_aria_snapshot(""" + - checkbox [checked=true] +""") +``` + +```python async +await page.set_content("") +await page.locator("body").to_match_aria_snapshot(""" + - checkbox [checked=true] +""") +``` + +```java +page.setContent(""); +page.locator("body").expect().toMatchAriaSnapshot(""" + - checkbox [checked=true] +"""); +``` + +```csharp +await page.SetContentAsync(""); +await Expect(page.Locator("body")).ToMatchAriaSnapshotAsync(@" + - checkbox [checked=true] +"); +``` + +**Example**: Matching with Regular Expressions + +Use regular expressions to match elements with dynamic or varying text content. + +```js +await page.setContent(`

Issues 12

`); +await expect(page.locator('body')).toMatchAriaSnapshot(` + - heading /Issues \\d+/ +`); +``` + +```python sync +page.set_content("

Issues 12

") +page.locator("body").to_match_aria_snapshot(""" + - heading /Issues \\d+/ +""") +``` + +```python async +await page.set_content("

Issues 12

") +await page.locator("body").to_match_aria_snapshot(""" + - heading /Issues \\d+/ +""") +``` + +```java +page.setContent("

Issues 12

"); +page.locator("body").expect().toMatchAriaSnapshot(""" + - heading /Issues \\d+/ +"""); +``` + +```csharp +await page.SetContentAsync("

Issues 12

"); +await Expect(page.Locator("body")).ToMatchAriaSnapshotAsync(@" + - heading /Issues \\d+/ +"); +``` + +## Accessibility Tree + +### Syntax Overview + +Each accessible element in the accessibility tree is represented as a YAML node with the following structure: + +```yaml +- role "name" [attribute=value] +``` + +- **role**: Specifies the ARIA or HTML role of the element, such as `heading`, `list`, `listitem`, `button`, etc. +- **"name"** (optional): Accessible name of the element. Quoted strings represent exact value, while regex patterns (e.g., `/pattern/`) match values dynamically. +- **[attribute=value]** (optional): Attributes and their values, enclosed in square brackets. Attributes include `checked`, `disabled`, `expanded`, `level`, `pressed` and `selected`, as specified by ARIA or HTML semantics. + +When capturing the accessibility tree, these values are either extracted from the ARIA attributes, or are computed from the HTML semantics. + +You can use [Chrome DevTools Accessibility Pane](https://developer.chrome.com/docs/devtools/accessibility/reference#pane) to inspect the +accessibility tree of a page and identify the roles, name, attributes, and text content of accessible elements. + +**Example**: Headings with `level` attributes indicate heading levels + +```html +

Title

+

Subtitle

+``` + +*accessibility tree* + +```yaml +- heading "Title" [level=1] +- heading "Subtitle" [level=2] +``` + +**Example**: Text Nodes capture standalone or descriptive text elements + +```html +
Sample accessible name
+``` + +*accessibility tree* + +```yaml +- text: Sample accessible name +``` + +**Example**: Flattening of the multiline text + +```html +

Line 1
Line 2

+``` + +*accessibility tree* + +```yaml +- paragraph: Line 1 Line 2 +``` + +**Example**: Links represent hyperlinks with text or composed text from pseudo-elements + +```html +Read more about Accessibility +``` + +*accessibility tree* + +```yaml +- link "Read more about Accessibility" +``` + + +**Example**: Buttons represent interactive button elements, supporting states like `pressed` or `disabled` + +```html + +``` + +*accessibility tree* + +```yaml +- button "Submit" [disabled=true] +``` + +**Example**: Textboxes capture input elements, with the `value` attribute reflecting the content + +```html + +``` + +*accessibility tree* + +```yaml +- textbox: Enter your name +``` + +### Composite Structures + +Accessibility tree follows DOM hierarchy. It does not include **presentation** and **none** roles and inlines text content +from the generic nodes. + +**Example**: Lists capture ordered and unordered lists with list items + +```html + +``` + +*accessibility tree* + +```yaml +- list "Main Features": + - listitem: Feature 1 + - listitem: Feature 2 +``` + +**Example**: Groups capture grouped elements, such as `details` elements with `summary` text. + +```html +
+ Summary +

Detail content here

+
+``` + +*accessibility tree* + +```yaml +- group: Summary +``` + +### Attributes and States + +Attributes such as `checked`, `disabled`, `expanded`, `level`, `pressed`, and `selected` represent control states. + +**Example**: Checkbox with `checked` attribute + +```html + +``` + +*accessibility tree* + +```yaml +- checkbox [checked=true] +``` + +or + +```yaml +- checkbox [checked] +``` + +**Example**: Button with `pressed` attribute + +```html + +``` + +```yaml +- button "Toggle" [pressed=true] +``` + +or + +```yaml +- button "Toggle" [pressed] +``` + +### Full Document Examples + +**Example**: Heading and Paragraph + +```html +

Welcome

+

This is a sample paragraph

+``` + +*accessibility tree* + +```yaml +- heading "Welcome" [level=1] +- paragraph: This is a sample paragraph +``` + +**Example**: Interactive List with Nested Elements + +```html +

Features

+ +``` + +*accessibility tree* + + +```yaml +- heading "Features" [level=2] +- list "Main Features": + - listitem: + - link "Feature 1" + - listitem: + - link "Feature 2" +``` + +**Example**: Complex Document with Pseudo-Elements and Attributes + +```html + +

Title

+

Introductory text

+Read more +``` + +*accessibility tree* + +```yaml +- heading "Title" [level=1] +- text: hello Introductory text +- link "Read more" +``` + +**Example**: Button with State Attributes + +```html + +``` + +*accessibility tree* + + +```yaml +- button "Toggle" [expanded=true] +``` diff --git a/packages/playwright-core/types/types.d.ts b/packages/playwright-core/types/types.d.ts index 2d4ecc2b7c..d963203643 100644 --- a/packages/playwright-core/types/types.d.ts +++ b/packages/playwright-core/types/types.d.ts @@ -12425,7 +12425,7 @@ export interface Locator { and(locator: Locator): Locator; /** - * Captures the aria snapshot of the given element. See + * Captures the aria snapshot of the given element. Read more about [accessibility snapshots](https://playwright.dev/docs/aria-snapshot) and * [expect(locator).toMatchAriaSnapshot(expected[, options])](https://playwright.dev/docs/api/class-locatorassertions#locator-assertions-to-match-aria-snapshot) * for the corresponding assertion. * diff --git a/packages/playwright/types/test.d.ts b/packages/playwright/types/test.d.ts index 706d567dcb..f17fba3502 100644 --- a/packages/playwright/types/test.d.ts +++ b/packages/playwright/types/test.d.ts @@ -8414,7 +8414,7 @@ interface LocatorAssertions { }): Promise; /** - * Asserts that the target element matches the given accessibility snapshot. + * Asserts that the target element matches the given [accessibility snapshot](https://playwright.dev/docs/aria-snapshot). * * **Usage** * diff --git a/tests/page/to-match-aria-snapshot.spec.ts b/tests/page/to-match-aria-snapshot.spec.ts index 8c8b11525e..daeecd69c1 100644 --- a/tests/page/to-match-aria-snapshot.spec.ts +++ b/tests/page/to-match-aria-snapshot.spec.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { stripAnsi } from 'tests/config/utils'; +import { stripAnsi } from '../config/utils'; import { test, expect } from './pageTest'; test('should match', async ({ page }) => {