fix(role): make sure to ignore style/script/noscript/template (#32231)
Even when these are a part of a hidden `aria-labelledby` traversal, all browsers ignore them anyway.
This commit is contained in:
parent
b599335404
commit
b4a9b247b4
|
|
@ -261,12 +261,16 @@ function getAriaBoolean(attr: string | null) {
|
|||
return attr === null ? undefined : attr.toLowerCase() === 'true';
|
||||
}
|
||||
|
||||
function isElementIgnoredForAria(element: Element) {
|
||||
return ['STYLE', 'SCRIPT', 'NOSCRIPT', 'TEMPLATE'].includes(elementSafeTagName(element));
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/wai-aria-1.2/#tree_exclusion, but including "none" and "presentation" roles
|
||||
// Not implemented:
|
||||
// `Any descendants of elements that have the characteristic "Children Presentational: True"`
|
||||
// https://www.w3.org/TR/wai-aria-1.2/#aria-hidden
|
||||
export function isElementHiddenForAria(element: Element): boolean {
|
||||
if (['STYLE', 'SCRIPT', 'NOSCRIPT', 'TEMPLATE'].includes(elementSafeTagName(element)))
|
||||
if (isElementIgnoredForAria(element))
|
||||
return true;
|
||||
const style = getElementComputedStyle(element);
|
||||
const isSlot = element.nodeName === 'SLOT';
|
||||
|
|
@ -496,14 +500,17 @@ function getTextAlternativeInternal(element: Element, options: AccessibleNameOpt
|
|||
// step 2a. Hidden Not Referenced: If the current node is hidden and is:
|
||||
// Not part of an aria-labelledby or aria-describedby traversal, where the node directly referenced by that relation was hidden.
|
||||
// Nor part of a native host language text alternative element (e.g. label in HTML) or attribute traversal, where the root of that traversal was hidden.
|
||||
if (!options.includeHidden &&
|
||||
!options.embeddedInLabelledBy?.hidden &&
|
||||
!options.embeddedInDescribedBy?.hidden &&
|
||||
!options?.embeddedInNativeTextAlternative?.hidden &&
|
||||
!options?.embeddedInLabel?.hidden &&
|
||||
isElementHiddenForAria(element)) {
|
||||
options.visitedElements.add(element);
|
||||
return '';
|
||||
if (!options.includeHidden) {
|
||||
const isEmbeddedInHiddenReferenceTraversal =
|
||||
!!options.embeddedInLabelledBy?.hidden ||
|
||||
!!options.embeddedInDescribedBy?.hidden ||
|
||||
!!options.embeddedInNativeTextAlternative?.hidden ||
|
||||
!!options.embeddedInLabel?.hidden;
|
||||
if (isElementIgnoredForAria(element) ||
|
||||
(!isEmbeddedInHiddenReferenceTraversal && isElementHiddenForAria(element))) {
|
||||
options.visitedElements.add(element);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
const labelledBy = getAriaLabelledByElements(element);
|
||||
|
|
|
|||
|
|
@ -462,6 +462,19 @@ test('should work with form and tricky input names', async ({ page }) => {
|
|||
expect.soft(await getNameAndRole(page, 'form')).toEqual({ role: 'form', name: 'my form' });
|
||||
});
|
||||
|
||||
test('should ignore stylesheet from hidden aria-labelledby subtree', async ({ page }) => {
|
||||
await page.setContent(`
|
||||
<div id=mylabel style="display:none">
|
||||
<template shadowrootmode=open>
|
||||
<style>span { color: red; }</style>
|
||||
<span>hello</span>
|
||||
</template>
|
||||
</div>
|
||||
<input aria-labelledby=mylabel type=text>
|
||||
`);
|
||||
expect.soft(await getNameAndRole(page, 'input')).toEqual({ role: 'textbox', name: 'hello' });
|
||||
});
|
||||
|
||||
function toArray(x: any): any[] {
|
||||
return Array.isArray(x) ? x : [x];
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue