chore(snapshot): support aria-owns (#33404)
This commit is contained in:
parent
3cd753f6bb
commit
1d4650cea2
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
`);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue