diff --git a/lib/commons/text/subtree-text.js b/lib/commons/text/subtree-text.js index 971ef51365..2708b6f3f2 100644 --- a/lib/commons/text/subtree-text.js +++ b/lib/commons/text/subtree-text.js @@ -13,14 +13,32 @@ import getOwnedVirtual from '../aria/get-owned-virtual'; function subtreeText(virtualNode, context = {}) { const { alreadyProcessed } = accessibleTextVirtual; context.startNode = context.startNode || virtualNode; - const { strict } = context; + const { strict, inControlContext, inLabelledByContext } = context; if ( alreadyProcessed(virtualNode, context) || - !namedFromContents(virtualNode, { strict }) + virtualNode.props.nodeType !== 1 ) { return ''; } + if ( + !namedFromContents(virtualNode, { strict }) && + !context.subtreeDescendant + ) { + return ''; + } + + /** + * Note: Strictly speaking if a child isn't named from content and it has no accessible name + * accName says to ignore it. Browsers do this fairly consistently, but screen readers have + * chosen to ignore this, but only for direct content, not for labels / aria-labelledby. + * That way in `a[href] > article > #text` the text is used for the accessible name, + * See: https://github.com/dequelabs/axe-core/issues/1461 + */ + if (!strict) { + const subtreeDescendant = !inControlContext && !inLabelledByContext; + context = { subtreeDescendant, ...context }; + } return getOwnedVirtual(virtualNode).reduce((contentText, child) => { return appendAccessibleText(contentText, child, context); }, ''); diff --git a/test/commons/text/accessible-text.js b/test/commons/text/accessible-text.js index fb76a851d3..9b42b79b9f 100644 --- a/test/commons/text/accessible-text.js +++ b/test/commons/text/accessible-text.js @@ -257,12 +257,12 @@ describe('text.accessibleTextVirtual', function() { axe.testUtils.flatTreeSetup(fixture); var target = axe.utils.querySelectorAll(axe._tree, '#t2label')[0]; - // Chrome 72: This is This is a label of - // Firefox 62: This is ARIA Label - // Safari 12.0: This is This is a label of + // Chrome 86: This is This is a label of + // Firefox 82: This is ARIA Label everything + // Safari 14.0: This is This is a label of everything assert.equal( axe.commons.text.accessibleTextVirtual(target), - 'This is This is a label of' + 'This is This is a label of everything' ); }); diff --git a/test/integration/rules/link-name/link-name.html b/test/integration/rules/link-name/link-name.html index fd70c3e4b8..797402245d 100644 --- a/test/integration/rules/link-name/link-name.html +++ b/test/integration/rules/link-name/link-name.html @@ -2,6 +2,9 @@ + +
Some sectioning content
+
Text
diff --git a/test/integration/rules/link-name/link-name.json b/test/integration/rules/link-name/link-name.json index 88cfd6dbfe..c0c9c3259e 100644 --- a/test/integration/rules/link-name/link-name.json +++ b/test/integration/rules/link-name/link-name.json @@ -8,5 +8,5 @@ ["#violation4"], ["#violation5"] ], - "passes": [["#pass1"], ["#pass2"], ["#pass3"], ["#pass4"]] + "passes": [["#pass1"], ["#pass2"], ["#pass3"], ["#pass4"], ["#pass5"]] }