chore(snapshot): support aria-owns (#33404)

This commit is contained in:
Pavel Feldman 2024-11-01 15:25:38 -07:00 committed by GitHub
parent 3cd753f6bb
commit 1d4650cea2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 58 additions and 2 deletions

View File

@ -50,7 +50,12 @@ export type AriaTemplateRoleNode = AriaProps & {
export type AriaTemplateNode = AriaTemplateRoleNode | AriaTemplateTextNode;
export function generateAriaTree(rootElement: Element): AriaNode {
const visited = new Set<Node>();
const visit = (ariaNode: AriaNode, node: Node) => {
if (visited.has(node))
return;
visited.add(node);
if (node.nodeType === Node.TEXT_NODE && node.nodeValue) {
const text = node.nodeValue;
if (text)
@ -65,13 +70,23 @@ export function generateAriaTree(rootElement: Element): AriaNode {
if (roleUtils.isElementHiddenForAria(element))
return;
const ariaChildren: Element[] = [];
if (element.hasAttribute('aria-owns')) {
const ids = element.getAttribute('aria-owns')!.split(/\s+/);
for (const id of ids) {
const ownedElement = rootElement.ownerDocument.getElementById(id);
if (ownedElement)
ariaChildren.push(ownedElement);
}
}
const childAriaNode = toAriaNode(element);
if (childAriaNode)
ariaNode.children.push(childAriaNode);
processChildNodes(childAriaNode || ariaNode, element);
processElement(childAriaNode || ariaNode, element, ariaChildren);
};
function processChildNodes(ariaNode: AriaNode, element: Element) {
function processElement(ariaNode: AriaNode, element: Element, ariaChildren: Element[] = []) {
// Surround every element with spaces for the sake of concatenated text nodes.
const display = getElementComputedStyle(element)?.display || 'inline';
const treatAsBlock = (display !== 'inline' || element.nodeName === 'BR') ? ' ' : '';
@ -94,6 +109,9 @@ export function generateAriaTree(rootElement: Element): AriaNode {
}
}
for (const child of ariaChildren)
visit(ariaNode, child);
ariaNode.children.push(roleUtils.getPseudoContent(element, '::after'));
if (treatAsBlock)

View File

@ -421,3 +421,41 @@ it('should treat input value as text in templates', async ({ page }) => {
- textbox: hello world
`);
});
it('should respect aria-owns', async ({ page }) => {
await page.setContent(`
<a href='about:blank' aria-owns='input p'>
<div role='region'>Link 1</div>
</a>
<a href='about:blank' aria-owns='input p'>
<div role='region'>Link 2</div>
</a>
<input id='input' value='Value'>
<p id='p'>Paragraph</p>
`);
// - 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":
- region: Link 1
- textbox: Value
- paragraph: Paragraph
- link "Link 2 Value Paragraph":
- region: Link 2
`);
});
it('should be ok with circular ownership', async ({ page }) => {
await page.setContent(`
<a href='about:blank' id='parent'>
<div role='region' aria-owns='parent'>Hello</div>
</a>
`);
await checkAndMatchSnapshot(page.locator('body'), `
- link "Hello":
- region: Hello
`);
});