/** * Copyright (c) Microsoft Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import type { Locator } from '@playwright/test'; import { test as it, expect } from './pageTest'; function unshift(snapshot: string): string { const lines = snapshot.split('\n'); let whitespacePrefixLength = 100; for (const line of lines) { if (!line.trim()) continue; const match = line.match(/^(\s*)/); if (match && match[1].length < whitespacePrefixLength) whitespacePrefixLength = match[1].length; } return lines.filter(t => t.trim()).map(line => line.substring(whitespacePrefixLength)).join('\n'); } async function checkAndMatchSnapshot(locator: Locator, snapshot: string) { expect.soft(await locator.ariaSnapshot()).toBe(unshift(snapshot)); await expect.soft(locator).toMatchAriaSnapshot(snapshot); } it('should snapshot', async ({ page }) => { await page.setContent(`

title

`); await checkAndMatchSnapshot(page.locator('body'), ` - heading "title" [level=1] `); }); it('should snapshot list', async ({ page }) => { await page.setContent(`

title

title 2

`); await checkAndMatchSnapshot(page.locator('body'), ` - heading "title" [level=1] - heading "title 2" [level=1] `); }); it('should snapshot list with accessible name', async ({ page }) => { await page.setContent(` `); await checkAndMatchSnapshot(page.locator('body'), ` - list "my list": - listitem: one - listitem: two `); }); it('should snapshot complex', async ({ page }) => { await page.setContent(` `); await checkAndMatchSnapshot(page.locator('body'), ` - list: - listitem: - link "link": - /url: about:blank `); }); it('should allow text nodes', async ({ page }) => { await page.setContent(`

Microsoft

Open source projects and samples from Microsoft
`); await checkAndMatchSnapshot(page.locator('body'), ` - heading "Microsoft" [level=1] - text: Open source projects and samples from Microsoft `); }); it('should snapshot details visibility', async ({ page }) => { await page.setContent(`
Summary
Details
`); await checkAndMatchSnapshot(page.locator('body'), ` - group: Summary `); }); it('should snapshot integration', async ({ page }) => { await page.setContent(`

Microsoft

Open source projects and samples from Microsoft
`); await checkAndMatchSnapshot(page.locator('body'), ` - heading "Microsoft" [level=1] - text: Open source projects and samples from Microsoft - list: - listitem: - group: Verified - listitem: - link "Sponsor": - /url: about:blank `); }); it('should support multiline text', async ({ page }) => { await page.setContent(`

Line 1 Line 2 Line 3

`); await checkAndMatchSnapshot(page.locator('body'), ` - paragraph: Line 1 Line 2 Line 3 `); await expect(page.locator('body')).toMatchAriaSnapshot(` - paragraph: | Line 1 Line 2 Line 3 `); }); it('should concatenate span text', async ({ page }) => { await page.setContent(` One Two Three `); await checkAndMatchSnapshot(page.locator('body'), ` - text: One Two Three `); }); it('should concatenate span text 2', async ({ page }) => { await page.setContent(` One Two Three `); await checkAndMatchSnapshot(page.locator('body'), ` - text: One Two Three `); }); it('should concatenate div text with spaces', async ({ page }) => { await page.setContent(`
One
Two
Three
`); await checkAndMatchSnapshot(page.locator('body'), ` - text: One Two Three `); }); it('should include pseudo in text', async ({ page }) => { await page.setContent(` hello
hello
`); await checkAndMatchSnapshot(page.locator('body'), ` - link "worldhello hellobye": - /url: about:blank `); }); it('should not include hidden pseudo in text', async ({ page }) => { await page.setContent(` hello
hello
`); await checkAndMatchSnapshot(page.locator('body'), ` - link "hello hello": - /url: about:blank `); }); it('should include new line for block pseudo', async ({ page }) => { await page.setContent(` hello
hello
`); await checkAndMatchSnapshot(page.locator('body'), ` - link "world hello hello bye": - /url: about:blank `); }); it('should work with slots', async ({ page }) => { // Text "foo" is assigned to the slot, should not be used twice. await page.setContent(` `); await checkAndMatchSnapshot(page.locator('body'), ` - button "foo" `); // Text "foo" is assigned to the slot, should be used instead of slot content. await page.setContent(`
foo
`); await checkAndMatchSnapshot(page.locator('body'), ` - button "foo" `); // Nothing is assigned to the slot, should use slot content. await page.setContent(`
`); await checkAndMatchSnapshot(page.locator('body'), ` - button "pre" `); }); it('should snapshot inner text', async ({ page }) => { await page.setContent(`
a.test.ts
snapshot
30ms
`); await checkAndMatchSnapshot(page.locator('body'), ` - listitem: - text: a.test.ts - button "Run" - button "Show source" - button "Watch" - listitem: - text: snapshot 30ms - button "Run" - button "Show source" - button "Watch" `); }); it('should include pseudo codepoints', async ({ page, server }) => { await page.goto(server.EMPTY_PAGE); await page.setContent(`

hello

`); await checkAndMatchSnapshot(page.locator('body'), ` - paragraph: \ueab2hello `); }); it('check aria-hidden text', async ({ page }) => { await page.setContent(`

hello

`); await checkAndMatchSnapshot(page.locator('body'), ` - paragraph: hello `); }); it('should ignore presentation and none roles', async ({ page }) => { await page.setContent(` `); await checkAndMatchSnapshot(page.locator('body'), ` - list: hello world `); }); it('should treat input value as text in templates, but not for checkbox/radio/file', async ({ page }) => { await page.setContent(` `); await checkAndMatchSnapshot(page.locator('body'), ` - textbox: hello world - button "Choose File" - checkbox [checked] - radio [checked] `); }); it('should not use on as checkbox value', async ({ page }) => { await page.setContent(` `); await checkAndMatchSnapshot(page.locator('body'), ` - checkbox - radio `); }); it('should respect aria-owns', async ({ page }) => { await page.setContent(`
Link 1
Link 2

Paragraph

`); // - Different from Chrome DevTools which attributes ownership to the last element. // - CDT also does not include non-owned children in accessible name. // - Disregarding these as aria-owns can't suggest multiple parts by spec. await checkAndMatchSnapshot(page.locator('body'), ` - link "Link 1 Value Paragraph": - /url: about:blank - region: Link 1 - textbox: Value - paragraph: Paragraph - link "Link 2 Value Paragraph": - /url: about:blank - region: Link 2 `); }); it('should be ok with circular ownership', async ({ page }) => { await page.setContent(`
Hello
`); await checkAndMatchSnapshot(page.locator('body'), ` - link "Hello": - /url: about:blank - region: Hello `); }); it('should escape yaml text in text nodes', async ({ page }) => { await page.setContent(`
one: link1 "two link2 'three link3 \`four
[Select all]
`); await checkAndMatchSnapshot(page.locator('body'), ` - group: - text: "one:" - link "link1": - /url: "#" - text: "\\\"two" - link "link2": - /url: "#" - text: "'three" - link "link3": - /url: "#" - text: "\`four" - list: - link "one": - /url: "#" - text: "," - link "two": - /url: "#" - text: ( - link "three": - /url: "#" - text: ") {" - link "four": - /url: "#" - text: "} [" - link "five": - /url: "#" - text: "]" - text: "[Select all]" `); }); it('should normalize whitespace', async ({ page }) => { await page.setContent(`
one \n two link  \n 1
`); await checkAndMatchSnapshot(page.locator('body'), ` - group: - text: one two - link "link 1": - /url: "#" - textbox: hello world - button "helloworld" `); // Weird whitespace in the template should be normalized. await expect(page.locator('body')).toMatchAriaSnapshot(` - group: - text: | one two - link " link 1 ": - /url: "#" - textbox: hello world - button "he\u00adlloworld\u200b" `); }); it('should handle long strings', async ({ page }) => { const s = 'a'.repeat(10000); await page.setContent(`
${s}
`); await checkAndMatchSnapshot(page.locator('body'), ` - link: - /url: about:blank - region: ${s} `); }); it('should escape special yaml characters', async ({ page }) => { await page.setContent(` @hello@hello ]hello]hello hello\n hello\n\n hello\n hello #hello#hello `); await checkAndMatchSnapshot(page.locator('body'), ` - link "@hello": - /url: "#" - text: "@hello" - link "]hello": - /url: "#" - text: "]hello" - link "hello": - /url: "#" - text: hello - link "hello": - /url: "#" - text: hello - link "#hello": - /url: "#" - text: "#hello" `); }); it('should escape special yaml values', async ({ page }) => { await page.setContent(` trueFalse NOyes yN onOff nullNULL 123123 -1.2-1.2 -- `); await checkAndMatchSnapshot(page.locator('body'), ` - link "true": - /url: "#" - text: "False" - link "NO": - /url: "#" - text: "yes" - link "y": - /url: "#" - text: "N" - link "on": - /url: "#" - text: "Off" - link "null": - /url: "#" - text: "NULL" - link "123": - /url: "#" - text: "123" - link "-1.2": - /url: "#" - text: "-1.2" - link "-": - /url: "#" - text: "-" - textbox: "555" `); }); it('should not report textarea textContent', async ({ page }) => { await page.setContent(``); await checkAndMatchSnapshot(page.locator('body'), ` - textbox: Before `); await page.evaluate(() => { document.querySelector('textarea').value = 'After'; }); await checkAndMatchSnapshot(page.locator('body'), ` - textbox: After `); });