1"use strict";(self.webpackChunkplaywright_dev=self.webpackChunkplaywright_dev||[]).push([["5044"],{96283(e,t,s){s.r(t),s.d(t,{metadata:()=>n,default:()=>p,frontMatter:()=>l,contentTitle:()=>c,toc:()=>h,assets:()=>o});var n=JSON.parse('{"id":"aria-snapshots","title":"Snapshot testing","description":"Overview","source":"@site/docs/aria-snapshots.mdx","sourceDirName":".","slug":"/aria-snapshots","permalink":"/docs/next/aria-snapshots","draft":false,"unlisted":false,"tags":[],"version":"current","frontMatter":{"id":"aria-snapshots","title":"Snapshot testing"},"sidebar":"docs","previous":{"title":"Service Workers","permalink":"/docs/next/service-workers"},"next":{"title":"Test generator","permalink":"/docs/next/codegen"}}'),a=s(74848),i=s(28453);s(13554),s(41647),s(83137);var r=s(21588);let l={id:"aria-snapshots",title:"Snapshot testing"},c,o={},h=[{value:"Overview",id:"overview",level:2},{value:"Assertion testing vs Snapshot testing",id:"assertion-testing-vs-snapshot-testing",level:2},{value:"Assertion testing",id:"assertion-testing",level:3},{value:"Snapshot testing",id:"snapshot-testing",level:3},{value:"When to use",id:"when-to-use",level:3},{value:"Aria snapshots",id:"aria-snapshots",level:2},{value:"Snapshot matching",id:"snapshot-matching",level:2},{value:"Partial matching",id:"partial-matching",level:3},{value:"Strict matching",id:"strict-matching",level:3},{value:"Setting <code>children</code> mode globally",id:"setting-children-mode-globally",level:4},{value:"Matching with regular expressions",id:"matching-with-regular-expressions",level:3},{value:"Generating snapshots",id:"generating-snapshots",level:2},{value:"Generating snapshots with the Playwright code generator",id:"generating-snapshots-with-the-playwright-code-generator",level:3},{value:"Updating snapshots with <code>@playwright/test</code> and the <code>--update-snapshots</code> flag",id:"updating-snapshots-with-playwrighttest-and-the---update-snapshots-flag",level:3},{value:"Empty template for snapshot generation",id:"empty-template-for-snapshot-generation",level:4},{value:"Snapshot patch files",id:"snapshot-patch-files",level:4},{value:"Snapshots as separate files",id:"snapshots-as-separate-files",level:4},{value:"Using page.ariaSnapshot() and locator.ariaSnapshot()",id:"using-pageariasnapshot-and-locatorariasnapshot",level:3},{value:"Accessibility tree examples",id:"accessibility-tree-examples",level:2},{value:"Headings with level attributes",id:"headings-with-level-attributes",level:3},{value:"Text nodes",id:"text-nodes",level:3},{value:"Inline multiline text",id:"inline-multiline-text",level:3},{value:"Links",id:"links",level:3},{value:"Text boxes",id:"text-boxes",level:3},{value:"Lists with items",id:"lists-with-items",level:3},{value:"Grouped elements",id:"grouped-elements",level:3},{value:"Attributes and states",id:"attributes-and-states",level:3},{value:"Checkbox with <code>checked</code> attribute",id:"checkbox-with-checked-attribute",level:4},{value:"Button with <code>pressed</code> attribute",id:"button-with-pressed-attribute",level:4},{value:"Input with <code>aria-invalid</code> attribute",id:"input-with-aria-invalid-attribute",level:4}];function d(e){let t={a:"a",code:"code",h2:"h2",h3:"h3",h4:"h4",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,i.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(t.h2,{id:"overview",children:"Overview"}),"\n",(0,a.jsx)(t.p,{children:"With Playwright's Snapshot testing you can assert the accessibility tree of a page against a predefined snapshot template."}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-js",children:'await page.goto(\'https://playwright.dev/\');\nawait expect(page).toMatchAriaSnapshot(`\n - banner:\n - heading /Playwright enables reliable end-to-end/ [level=1]\n - link "Get started":\n - /url: /docs/intro\n - link "Star microsoft/playwright on GitHub":\n - /url: https://github.com/microsoft/playwright\n - link /[\\\\d]+k\\\\+ stargazers on GitHub/\n`);\n'})}),"\n",(0,a.jsx)(r.A,{id:"P4R6hnsE0UY",title:"Getting started with ARIA Snapshots"}),"\n",(0,a.jsx)(t.h2,{id:"assertion-testing-vs-snapshot-testing",children:"Assertion testing vs Snapshot testing"}),"\n",(0,a.jsx)(t.p,{children:"Snapshot testing and assertion testing serve different purposes in test automation:"}),"\n",(0,a.jsx)(t.h3,{id:"assertion-testing",children:"Assertion testing"}),"\n",(0,a.jsxs)(t.p,{children:["Assertion testing is a targeted approach where you assert specific values or conditions about elements or components. For instance, with Playwright, ",(0,a.jsx)(t.a,{href:"/docs/next/api/class-locatorassertions#locator-assertions-to-have-text",children:"expect(locator).toHaveText()"})," verifies that an element contains the expected text, and ",(0,a.jsx)(t.a,{href:"/docs/next/api/class-locatorassertions#locator-assertions-to-have-value",children:"expect(locator).toHaveValue()"})," confirms that an input field has the expected value. Assertion tests are specific and generally check the current state of an element or property against an expected, predefined state. They w
1ork well for predictable, single-value checks but are limited in scope when testing the broader structure or variations."]}),"\n",(0,a.jsx)(t.p,{children:(0,a.jsx)(t.strong,{children:"Advantages"})}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"Clarity"}),": The intent of the test is explicit and easy to understand."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"Specificity"}),": Tests focus on particular aspects of functionality, making them more robust against unrelated changes."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"Debugging"}),": Failures provide targeted feedback, pointing directly to the problematic aspect."]}),"\n"]}),"\n",(0,a.jsx)(t.p,{children:(0,a.jsx)(t.strong,{children:"Disadvantages"})}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"Verbose for complex outputs"}),": Writing assertions for complex data structures or large outputs can be cumbersome and error-prone."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"Maintenance overhead"}),": As code evolves, manually updating assertions can be time-consuming."]}),"\n"]}),"\n",(0,a.jsx)(t.h3,{id:"snapshot-testing",children:"Snapshot testing"}),"\n",(0,a.jsx)(t.p,{children:"Snapshot testing captures a \u201Csnapshot\u201D or representation of the entire state of an element, component, or data at a given moment, which is then saved for future comparisons. When re-running tests, the current state is compared to the snapshot, and if there are differences, the test fails. This approach is especially useful for complex or dynamic structures, where manually asserting each detail would be too time-consuming. Snapshot testing is broader and more holistic than assertion testing, allowing you to track more complex changes over time."}),"\n",(0,a.jsx)(t.p,{children:(0,a.jsx)(t.strong,{children:"Advantages"})}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"Simplifies complex outputs"}),": For example, testing a UI component's rendered output can be tedious with traditional assertions. Snapshots capture the entire output for easy comparison."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"Quick Feedback loop"}),": Developers can easily spot unintended changes in the output."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"Encourages consistency"}),": Helps maintain consistent output as code evolves."]}),"\n"]}),"\n",(0,a.jsx)(t.p,{children:(0,a.jsx)(t.strong,{children:"Disadvantages"})}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"Over-Reliance"}),": It can be tempting to accept changes to snapshots without fully understanding them, potentially hiding bugs."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"Granularity"}),": Large snapshots may be hard to interpret when differences arise, especially if minor changes affect large portions of the output."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"Suitability"}),": Not ideal for highly dynamic content where outputs change frequently or unpredictably."]}),"\n"]}),"\n",(0,a.jsx)(t.h3,{id:"when-to-use",children:"When to use"}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"Snapshot testing"}
1)," is ideal for:","\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsx)(t.li,{children:"UI testing of whole pages and components."}),"\n",(0,a.jsx)(t.li,{children:"Broad structural checks for complex UI components."}),"\n",(0,a.jsx)(t.li,{children:"Regression testing for outputs that rarely change structure."}),"\n"]}),"\n"]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"Assertion testing"})," is ideal for:","\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsx)(t.li,{children:"Core logic validation."}),"\n",(0,a.jsx)(t.li,{children:"Computed value testing."}),"\n",(0,a.jsx)(t.li,{children:"Fine-grained tests requiring precise conditions."}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,a.jsx)(t.p,{children:"By combining snapshot testing for broad, structural checks and assertion testing for specific functionality, you can achieve a well-rounded testing strategy."}),"\n",(0,a.jsx)(t.h2,{id:"aria-snapshots",children:"Aria snapshots"}),"\n",(0,a.jsx)(t.p,{children:"In Playwright, aria snapshots provide a YAML representation of the accessibility tree of a page. These snapshots can be stored and compared later to verify if the page structure remains consistent or meets defined expectations. A template is a constraint, not necessarily a complete serialization of the accessibility tree."}),"\n",(0,a.jsxs)(t.p,{children:["The YAML format describes the hierarchical structure of accessible elements on the page, detailing ",(0,a.jsx)(t.strong,{children:"roles"}),", ",(0,a.jsx)(t.strong,{children:"attributes"}),", ",(0,a.jsx)(t.strong,{children:"values"}),", and ",(0,a.jsx)(t.strong,{children:"text content"}),". The structure follows a tree-like syntax, where each node represents an accessible element, and indentation indicates nested elements."]}),"\n",(0,a.jsx)(t.p,{children:"Each accessible element in the tree is represented as a YAML node:"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-yaml",children:'- role "name" [attribute=value]\n'})}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"role"}),": Specifies the ARIA or HTML role of the element (e.g., ",(0,a.jsx)(t.code,{children:"heading"}),", ",(0,a.jsx)(t.code,{children:"list"}),", ",(0,a.jsx)(t.code,{children:"listitem"}),", ",(0,a.jsx)(t.code,{children:"button"}),")."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:'"name"'}),": Accessible name of the element. Quoted strings indicate exact values, ",(0,a.jsx)(t.code,{children:"/patterns/"})," are used for regular expression."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"[attribute=value]"}),": Attributes and values, in square brackets, represent specific ARIA attributes, such as ",(0,a.jsx)(t.code,{children:"checked"}),", ",(0,a.jsx)(t.code,{children:"disabled"}),", ",(0,a.jsx)(t.code,{children:"expanded"}),", ",(0,a.jsx)(t.code,{children:"invalid"}),", ",(0,a.jsx)(t.code,{children:"level"}),", ",(0,a.jsx)(t.code,{children:"pressed"}),", or ",(0,a.jsx)(t.code,{children:"selected"}),". Attributes can constrain a specific value, such as ",(0,a.jsx)(t.code,{children:"[pressed=mixed]"}),"."]}),"\n"]}),"\n",(0,a.jsxs)(t.p,{children:["These values are derived from ARIA attributes or calculated based on HTML semantics. To inspect the accessibility tree structure of a page, use the ",(0,a.jsx)(t.a,{href:"https://developer.chrome.com/docs/devtools/accessibility/reference#tab",children:"Chrome DevTools Accessibility Tab"}),"."]}),"\n",(0,a.jsx)(t.h2,{id:"snapshot-matching",children:"Snapshot matching"}),"\n",(0,a.jsxs)(t.p,{children:["The ",(0,a.jsx)(t.a,{href:"/docs/next/api/class-pageassertions#page-assertions-to-match-aria-snapshot",children:"expect(page).toMatchAriaSnapshot()"})," assertion method in Playwright compares the accessible structure of the page with a predefined aria snapshot template, helping validate the page's state against testing requirements. You can also use ",(0,a.jsx)(t.a,{href:"/docs/next/api/class-locatorassertions#locator-assertions-to-match-aria-snapshot",children:"expect(locator).toMatchAriaSnapshot()"})," to match a specific part of the page."]}),"\n",(0,a.jsx)(t.p,{children:"For the following DOM:"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-html",children:"<h1>title</h1>\n"})}),"\n",(0,a.jsx)(t.p,{children:"You can match it using the following snapshot template:"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-js",children:'await expect(page).toMatchAriaSnapsh
1ot(`\n - heading "title"\n`);\n'})}),"\n",(0,a.jsx)(t.p,{children:"When matching, the snapshot template is compared to the current accessibility tree of the page:"}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsx)(t.li,{children:"If the tree structure matches the template, the test passes; otherwise, it fails, indicating a mismatch between expected and actual accessibility states."}),"\n",(0,a.jsx)(t.li,{children:"The comparison is case-sensitive and normalizes whitespace within names and text values. YAML indentation determines nesting."}),"\n",(0,a.jsx)(t.li,{children:"The comparison is order-sensitive, meaning the order of elements in the snapshot template must match the order in the page's accessibility tree."}),"\n",(0,a.jsx)(t.li,{children:"A single-node template can match at any depth within the selected page or locator. Multiple top-level nodes must match under the same parent, in order."}),"\n"]}),"\n",(0,a.jsx)(t.h3,{id:"partial-matching",children:"Partial matching"}),"\n",(0,a.jsx)(t.p,{children:"You can perform partial matches on nodes by omitting attributes or accessible names, enabling verification of specific parts of the accessibility tree without requiring exact matches. This flexibility is helpful for dynamic or irrelevant attributes."}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-html",children:"<button>Submit</button>\n"})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-yaml",metastring:'title="aria snapshot"',children:"- button\n"})}),"\n",(0,a.jsx)(t.p,{children:'In this example, the button role is matched, but the accessible name ("Submit") is not specified, allowing the test to pass regardless of the button\'s label.'}),"\n",(0,a.jsx)("hr",{}),"\n",(0,a.jsxs)(t.p,{children:["For elements with ARIA attributes like ",(0,a.jsx)(t.code,{children:"checked"})," or ",(0,a.jsx)(t.code,{children:"disabled"}),", omitting these attributes allows partial matching, focusing solely on role and hierarchy."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-html",children:'<input type="checkbox" checked>\n'})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-yaml",metastring:'title="aria snapshot (partial match)"',children:"- checkbox\n"})}),"\n",(0,a.jsxs)(t.p,{children:["In this partial match, the ",(0,a.jsx)(t.code,{children:"checked"})," attribute is ignored, so the test will pass regardless of the checkbox state."]}),"\n",(0,a.jsx)("hr",{}),"\n",(0,a.jsx)(t.p,{children:"Similarly, you can partially match children in lists or groups by omitting specific list items or nested elements."}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-html",children:"<ul>\n <li>Feature A</li>\n <li>Feature B</li>\n <li>Feature C</li>\n</ul>\n"})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-yaml",metastring:'title="aria snapshot (partial match)"',children:"- list:\n - listitem: Feature B\n"})}),"\n",(0,a.jsx)(t.p,{children:"Partial matches let you create flexible snapshot tests that verify essential page structure without enforcing specific content or attributes."}),"\n",(0,a.jsx)(t.h3,{id:"strict-matching",children:"Strict matching"}),"\n",(0,a.jsx)(t.p,{children:"By default, a template containing the subset of children will be matched:"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-html",children:"<ul>\n <li>Feature A</li>\n <li>Feature B</li>\n <li>Feature C</li>\n</ul>\n"})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-yaml",metastring:'title="aria snapshot (partial match)"',children:"- list:\n - listitem: Feature B\n"})}),"\n",(0,a.jsxs)(t.p,{children:["The ",(0,a.jsx)(t.code,{children:"/children"})," property controls children for the node where it appears:"]}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"contain"})," (default): Matches if all specified children are present in order."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"equal"}),": Matches if direct children exactly match the specified list in order."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"deep-equal"}),": Matches if children and nested children exactly match the specified list in order."]}),"\n"]}),"\n",(0,a.jsxs)(t.p,{children:["With no expected child entries, ",(0,a.jsx)(t.code,{children:"contain"})," allows any children, while ",(0,a.jsx)(t.code,{children:"equal"})," and ",(0,a.jsx)(t.code,{children:"deep-equal"})," require none. Add ",(0,a.jsx)(t.code,{children:"/children: contain"})," to a nested node to override inherited ",(0,a.jsx)(t.code,{children:"deep-equal"})," matching and allow extra children there."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-html",children:"<ul>\n <li>Feature A</li>\n <li>Feature B</li>\n <li>Feature C</li>\n</ul>\n"})}),"\n",(0,a.jsx)(t.p,{children:"Following snapshot will fail due to Feature C not being in the template:"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-yaml",metastring:'title="aria snapshot"',children:"- list:\n - /children: equal\n - listitem: Feature A\n - listitem: Feature B\n"})}),"\n",(0,a.jsxs)(t.h4,{id:"setting-children-mode-globally",children:["Setting ",(0,a.jsx)(t.code,{children:"children"})," mode globally"]}),"\n",(0,a.jsxs)(t.p,{children:["Instead of adding a ",(0,a.jsx)(t.code,{children:"/children"})," property to every snapshot, you can set the default children matching mode for all ",(0,a.jsx)(t.code,{children:"toMatchAriaSnapsh
1ot"})," calls in the configuration file:"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-js",metastring:'title="playwright.config.ts"',children:"import { defineConfig } from '@playwright/test';\n\nexport default defineConfig({\n expect: {\n toMatchAriaSnapshot: {\n children: 'equal',\n },\n },\n});\n"})}),"\n",(0,a.jsxs)(t.p,{children:["Individual snapshots can still override the global setting by including an explicit ",(0,a.jsx)(t.code,{children:"/children"})," property in the template."]}),"\n",(0,a.jsx)(t.h3,{id:"matching-with-regular-expressions",children:"Matching with regular expressions"}),"\n",(0,a.jsx)(t.p,{children:"Regular expressions allow flexible matching for elements with dynamic or variable text. Accessible names and text can support regex patterns."}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-html",children:"<h1>Issues 12</h1>\n"})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-yaml",metastring:'title="aria snapshot"',children:"- heading /Issues \\d+/\n"})}),"\n",(0,a.jsx)(t.h2,{id:"generating-snapshots",children:"Generating snapshots"}),"\n",(0,a.jsx)(t.p,{children:"Creating aria snapshots in Playwright helps ensure and maintain your application's structure. You can generate snapshots in various ways depending on your testing setup and workflow."}),"\n",(0,a.jsx)(t.h3,{id:"generating-snapshots-with-the-playwright-code-generator",children:"Generating snapshots with the Playwright code generator"}),"\n",(0,a.jsxs)(t.p,{children:["If you're using Playwright's ",(0,a.jsx)(t.a,{href:"/docs/next/codegen",children:"Code Generator"}),", generating aria snapshots is streamlined with its interactive interface:"]}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:'"Assert snapshot" Action'}),': In the code generator, you can use the "Assert snapshot" action to automatically create a snapshot assertion for the selected elements. This is a quick way to capture the aria snapshot as part of your recorded test flow.']}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:'"Aria snapshot" Tab'}),': The "Aria snapshot" tab within the code generator interface visually represents the aria snapshot for a selected locator, letting you explore, inspect, and verify element roles, attributes, and accessible names to aid snapshot creation and review.']}),"\n"]}),"\n",(0,a.jsxs)(t.h3,{id:"updating-snapshots-with-playwrighttest-and-the---update-snapshots-flag",children:["Updating snapshots with ",(0,a.jsx)(t.code,{children:"@playwright/test"})," and the ",(0,a.jsx)(t.code,{children:"--update-snapshots"})," flag"]}),"\n",(0,a.jsxs)(t.p,{children:["When using the Playwright test runner (",(0,a.jsx)(t.code,{children:"@playwright/test"}),"), you can automatically update snapshots with the ",(0,a.jsx)(t.code,{children:"--update-snapshots"})," flag, ",(0,a.jsx)(t.code,{children:"-u"})," for short."]}),"\n",(0,a.jsxs)(t.p,{children:["Running without the flag uses ",(0,a.jsx)(t.code,{children:"default"})," mode: absent snapshots are generated, but the tests that generate them fail, so that a run with new snapshots does not silently pass. Use ",(0,a.jsx)(t.code,{children:"missing"})," to generate absent snapshots and keep those tests passing. Supplying ",(0,a.jsx)(t.code,{children:"-u"})," uses ",(0,a.jsx)(t.code,{children:"changed"})," mode and updates snapshots that do not match. Use ",(0,a.jsx)(t.code,{children:"all"})," to regenerate every snapshot, including matching ones, or ",(0,a.jsx)(t.code,{children:"none"})," to prevent snapshot updates."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-bash",children:"npx playwright test --update-snapshots\n"})}),"\n",(0,a.jsxs)(t.p,{children:["Updating snapshots is useful when application structure changes require new snapshots as a baseline. Playwright retries the assertion until its expect timeout expires. Adjust ",(0,a.jsx)(t.code,{children:"--timeout"})," if snapshot generation takes longer than the test timeout."]}
1),"\n",(0,a.jsx)(t.h4,{id:"empty-template-for-snapshot-generation",children:"Empty template for snapshot generation"}),"\n",(0,a.jsx)(t.p,{children:"Passing an empty string as the template in an assertion generates a snapshot on-the-fly:"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-js",children:"await expect(locator).toMatchAriaSnapshot('');\n"})}),"\n",(0,a.jsxs)(t.p,{children:["This works without ",(0,a.jsx)(t.code,{children:"-u"})," because the default mode generates missing snapshots."]}),"\n",(0,a.jsx)(t.h4,{id:"snapshot-patch-files",children:"Snapshot patch files"}),"\n",(0,a.jsxs)(t.p,{children:["For inline snapshot templates, Playwright creates patch files that capture differences. These patch files can be reviewed and applied. Separate ",(0,a.jsx)(t.code,{children:".aria.yml"})," snapshots are written directly to their configured snapshot path."]}),"\n",(0,a.jsxs)(t.p,{children:["The way source code is updated can be changed using the ",(0,a.jsx)(t.code,{children:"--update-source-method"})," flag. There are several options available:"]}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:'"patch"'})," (default): Generates a unified diff file that can be applied to the source code using ",(0,a.jsx)(t.code,{children:"git apply"}),"."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:'"3way"'}),": Generates merge conflict markers in your source code, allowing you to choose whether to accept changes."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:'"overwrite"'}),": Overwrites the source code with the new snapshot values."]}),"\n"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-bash",children:"npx playwright test --update-snapshots --update-source-method=3way\n"})}),"\n",(0,a.jsx)(t.h4,{id:"snapshots-as-separate-files",children:"Snapshots as separate files"}),"\n",(0,a.jsxs)(t.p,{children:["To store your snapshots in a separate file, use the ",(0,a.jsx)(t.code,{children:"toMatchAriaSnapshot"})," method with the ",(0,a.jsx)(t.code,{children:"name"})," option, specifying a ",(0,a.jsx)(t.code,{children:".aria.yml"})," file extension."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-js",children:"await expect(page.getByRole('main')).toMatchAriaSnapshot({ name: 'main.aria.yml' });\n"})}),"\n",(0,a.jsxs)(t.p,{children:["By default, snapshots from a test file ",(0,a.jsx)(t.code,{children:"example.spec.ts"})," are placed in the ",(0,a.jsx)(t.code,{children:"example.spec.ts-snapshots"})," directory. As snapshots should be the same across browsers, only one snapshot is saved even if testing with multiple browsers. Should you wish, you can customize the ",(0,a.jsx)(t.a,{href:"./api/class-testconfig#test-config-snapshot-path-template",children:"snapshot path template"})," using the following configuration:"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-js",children:"export default defineConfig({\n expect: {\n toMatchAriaSnapshot: {\n pathTemplate: '__snapshots__/{testFilePath}/{arg}{ext}',\n },\n },\n});\n"})}),"\n",(0,a.jsxs)(t.h3,{id:"using-pageariasnapshot-and-locatorariasnapshot",children:["Using ",(0,a.jsx)(t.a,{href:"/docs/next/api/class-page#page-aria-snapshot",children:"page.ariaSnapshot()"})," and ",(0,a.jsx)(t.a,{href:"/docs/next/api/class-locator#locator-aria-snapshot",children:"locator.ariaSnapshot()"})]}),"\n",(0,a.jsxs)(t.p,{children:["Methods ",(0,a.jsx)(t.a,{href:"/docs/next/api/class-page#page-aria-snapshot",children:"page.ariaSnapshot()"})," and ",(0,a.jsx)(t.a,{href:"/docs/next/api/class-locator#locator-aria-snapshot",children:"locator.ariaSnapshot()"})," allow you to programmatically create a YAML representation of accessible elements within a locator's scope, especially helpful for generating snapshots dynamically during test execution."]}),"\n",(0,a.jsxs)(t.p,{children:[(0,a.jsx)(t.strong,{children:"Example"}),":"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-js",children:"const snapshot = await page.ariaSnapsh
1ot();\nconsole.log(snapshot);\n"})}),"\n",(0,a.jsx)(t.p,{children:"This command outputs the aria snapshot within the specified locator's scope in YAML format, which you can validate or store as needed."}),"\n",(0,a.jsx)(t.h2,{id:"accessibility-tree-examples",children:"Accessibility tree examples"}),"\n",(0,a.jsx)(t.h3,{id:"headings-with-level-attributes",children:"Headings with level attributes"}),"\n",(0,a.jsxs)(t.p,{children:["Headings can include a ",(0,a.jsx)(t.code,{children:"level"})," attribute indicating their heading level."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-html",children:"<h1>Title</h1>\n<h2>Subtitle</h2>\n"})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-yaml",metastring:'title="aria snapshot"',children:'- heading "Title" [level=1]\n- heading "Subtitle" [level=2]\n'})}),"\n",(0,a.jsx)(t.h3,{id:"text-nodes",children:"Text nodes"}),"\n",(0,a.jsx)(t.p,{children:"Standalone or descriptive text elements appear as text nodes."}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-html",children:"<div>Sample accessible name</div>\n"})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-yaml",metastring:'title="aria snapshot"',children:"- text: Sample accessible name\n"})}),"\n",(0,a.jsx)(t.h3,{id:"inline-multiline-text",children:"Inline multiline text"}),"\n",(0,a.jsx)(t.p,{children:"Multiline text, such as paragraphs, is normalized in the aria snapshot."}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-html",children:"<p>Line 1<br>Line 2</p>\n"})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-yaml",metastring:'title="aria snapshot"',children:"- paragraph: Line 1 Line 2\n"})}),"\n",(0,a.jsx)(t.h3,{id:"links",children:"Links"}),"\n",(0,a.jsxs)(t.p,{children:["Links display their text or composed content from pseudo-elements. The link\u2019s destination may be matched using the ",(0,a.jsx)(t.code,{children:"/url"})," property."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-html",children:'<a href="#more-info">Read more about Accessibility</a>\n'})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-yaml",metastring:'title="aria snapshot"',children:'- link "Read more about Accessibility":\n - /url: "#more-info"\n'})}),"\n",(0,a.jsxs)(t.p,{children:["The value of ",(0,a.jsx)(t.code,{children:"/url"})," may also be a regular expression:"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-html",children:'<a href="https://www.youtube.com/channel/UC46Zj8pDH5tDosqm1gd7WTg">YouTube channel</a>\n'})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-yaml",metastring:'title="aria snapshot"',children:"- link:\n - /url: /https://www.youtube.com/channel/.*/\n"})}),"\n",(0,a.jsx)(t.h3,{id:"text-boxes",children:"Text boxes"}),"\n",(0,a.jsxs)(t.p,{children:["Input elements of type ",(0,a.jsx)(t.code,{children:"text"})," show their ",(0,a.jsx)(t.code,{children:"value"})," attribute content."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-html",children:'<input type="text" value="Enter your name">\n'})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-yaml",metastring:'title="aria snapshot"',children:"- textbox: Enter your name\n"})}),"\n",(0,a.jsx)(t.h3,{id:"lists-with-items",children:"Lists with items"}),"\n",(0,a.jsx)(t.p,{children:"Ordered and unordered lists include their list items."}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-html",children:'<ul aria-label="Main Features">\n <li>Feature 1</li>\n <li>Feature 2</li>\n</ul>\n'})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-yaml",metastring:'title="aria snapshot"',children:'- list "Main Features":\n - listitem: Feature 1\n - listitem: Feature 2\n'})}),"\n",(0,a.jsx)(t.h3,{id:"grouped-elements",children:"Grouped elements"}),"\n",(0,a.jsxs)(t.p,{children:["Groups capture nested elements, such as ",(0,a.jsx)(t.code,{children:"<details>"})," elements with summary content."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-html",children:"<details>\n <summary>Summary</summary>\n <p>Detail content here</p>\n</details>\n"})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-yaml",metastring:'title="aria snapshot"',children:"- group: Summary\n"})}),"\n",(0,a.jsx)(t.h3,{id:"attributes-and-states",children:"Attributes and states"}),"\n",(0,a.jsxs)(t.p,{children:["Commonly used ARIA attributes, like ",(0,a.jsx)(t.code,{children:"checked"}),", ",(0,a.jsx)(t.code,{children:"disabled"}),", ",(0,a.jsx)(t.code,{children:"expanded"}),", ",(0,a.jsx)(t.code,{children:"invalid"}),", ",(0,a.jsx)(t.code,{children:"level"}),", ",(0,a.jsx)(t.code,{children:"pressed"}),", and ",(0,a.jsx)(t.code,{children:"selected"}),", represent control states."]}),"\n",(0,a.jsxs)(t.h4,{id:"checkbox-with-checked-attribute",children:["Checkbox with ",(0,a.jsx)(t.code,{children:"checked"})," attribute"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-html",children:'<input type="checkbox" checked>\n'})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-yaml",metastring:'title="aria snapshot"',children:"- checkbox [checked]\n"})}),"\n",(0,a.jsxs)(t.h4,{id:"button-with-pressed-attribute",children:["Button with ",(0,a.jsx)(t.code,{children:"pressed"})," attribute"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-html",children:'<button aria-pressed="true">Toggle</button>\n'})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-yaml",metastring:'title="aria snapshot"',children:'- button "Toggle" [pressed=true]\n'})}),"\n",(0,a.jsxs)(t.h4,{id:"input-with-aria-invalid-attribute",children:["Input with ",(0,a.jsx)(t.code,{children:"aria-invalid"})," attribute"]}),"\n",(0,a.jsxs)(t.p,{children:["The ",(0,a.jsx)(t.code,{children:"aria-invalid"})," value is surfaced directly. A value of ",(0,a.jsx)(t.code,{children:"true"})," renders as ",(0,a.jsx)(t.code,{children:"[invalid]"}),", while ",(0,a.jsx)(t.code,{children:"grammar"})," and ",(0,a.jsx)(t.code,{children:"spelling"})," render as ",(0,a.jsx)(t.code,{children:"[invalid=grammar]"})," and ",(0,a.jsx)(t.code,{children:"[invalid=spelling]"}),". A ",(0,a.jsx)(t.code,{children:"false"})," value is omitted."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-html",children:'<input type="text" aria-label="Email" aria-invalid="true" value="not-an-email">\n'})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-yaml",metastring:'title="aria snapshot"',children:'- textbox "Email" [invalid]: not-an-email\n'})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-html",children:'<input type="text" aria-label="Bio" aria-invalid="spelling">\n'})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-yaml",metastring:'title="aria snapshot"',children:'- textbox "Bio" [invalid=spelling]\n'})})]})}function p(e={}){let{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,a.jsx)(t,{...e,children:(0,a.jsx)(d,{...e})}):d(e)}},21588(e,t,s){s.d(t,{A:()=>l});var n=s(74848),a=s(96540),i=function(){return(i=Object.assign||function(e){for(var t,s=1,n=arguments.length;s<n;s++)for(var a in t=arguments[s])Object.prototype.hasOwnProperty.call(t,a)&&(e[a]=t[a]);return e}).apply(this,arguments)},r=a.forwardRef(function(e,t){var s=a.useState(!1),n=s[0],r=s[1],l=a.useState(!1),c=l[0],o=l[1],h=encodeURIComponent(e.id),d="string"==typeof e.playlistCoverId?encodeURIComponent(e.playlistCoverId):null,p=e.title,u=e.poster||"hqdefault",g="&".concat(e.params)||"",x=e.muted?"&mute=1":"",m=e.announce||"Watch",j=e.webp?"webp":"jpg",f=e.webp?"vi_webp":"vi",y=e.thumbnail||(e.playlist?"https://i.ytimg.com/".concat(f,"/").concat(d,"/").concat(u,".").concat(j):"https://i.ytimg.com/".concat(f,"/").concat(h,"/").concat(u,".").concat(j)),b=e.noCookie?"https://www.youtube-nocookie.com":"https://www.youtube.com";b=e.cookie?"https://www.youtube.com":"https://www.youtube-nocookie.com";var v=e.playlist?"".concat(b,"/embed/videoseries?autoplay=1").concat(x,"&list=").concat(h).concat(g):"".concat(b,"/embed/").concat(h,"?autoplay=1&state=1").concat(x).concat(g),w=e.activatedClass||"lyt-activated",k=e.adNetwork||!1,A=e.aspectHeight||9,S=e.aspectWidth||16,N=e.iframeClass||"",T=e.playerClass||"lty-playbtn",F=e.wrapperClass||"yt-lite",M=e.onIframeAdded||function(){},I=e.rel?"prefetch":"preload",C=e.containerElement||"article";return a.useEffect(function(){c&&M()},[c]),a.createElement(a.Fragment,null,a.createElement("link",{rel:I,href:y,as:"image"}),a.createElement(a.Fragment,null,n&&a.createElement(a.Fragment,null,a.createElement("link",{rel:"prec
1onnect",href:b}),a.createElement("link",{rel:"preconnect",href:"https://www.google.com"}),k&&a.createElement(a.Fragment,null,a.createElement("link",{rel:"preconnect",href:"https://static.doubleclick.net"}),a.createElement("link",{rel:"preconnect",href:"https://googleads.g.doubleclick.net"})))),a.createElement(C,{onPointerOver:function(){n||r(!0)},onClick:function(){c||o(!0)},className:"".concat(F," ").concat(c?w:""),"data-title":p,style:i({backgroundImage:"url(".concat(y,")")},{"--aspect-ratio":"".concat(A/S*100,"%")})},a.createElement("button",{type:"button",className:T,"aria-label":"".concat(m," ").concat(p)}),c&&a.createElement("iframe",{ref:t,className:N,title:p,width:"560",height:"315",frameBorder:"0",allow:"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture",allowFullScreen:!0,src:v})))});let l=function(e){let{id:t,title:s,thumbnail:a}=e;return(0,n.jsx)("div",{className:"videoContainer_NvH5",children:(0,n.jsx)(r,{thumbnail:a,id:t,params:"autoplay=1&autohide=1&showinfo=0&rel=0",title:s,poster:"hqdefault",webp:!0})})}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.