diff --git a/lib/commons/text/accessible-text.js b/lib/commons/text/accessible-text.js index ad378d2e65..ffde54e06d 100644 --- a/lib/commons/text/accessible-text.js +++ b/lib/commons/text/accessible-text.js @@ -21,9 +21,10 @@ var phrasingElements = ['A', 'EM', 'STRONG', 'SMALL', 'MARK', 'ABBR', 'DFN', 'I' */ function findLabel({ actualNode }) { let label; - const id = axe.utils.escapeSelector(actualNode.id); - if (id) { - label = document.querySelector('label[for="' + id + '"]'); + if (actualNode.id) { + label = dom.findElmsInContext({ + elm: 'label', attr: 'for', value: actualNode.id, context: actualNode + })[0]; } else { label = dom.findUp(actualNode, 'label'); } @@ -214,24 +215,29 @@ text.accessibleText = function(element, inLabelledByContext) { } function checkARIA (element, inLabelledByContext, inControlContext) { + let returnText = ''; const { actualNode } = element; if (!inLabelledByContext && actualNode.hasAttribute('aria-labelledby')) { - return text.sanitize(dom.idrefs(actualNode, 'aria-labelledby').map(label => { - if (actualNode === label) { - encounteredNodes.pop(); - } //let element be encountered twice - - const vLabel = axe.utils.getNodeFromTree(axe._tree[0], label); - return accessibleNameComputation(vLabel, true, actualNode !== label); + // Store the return text, if it's empty, fall back to aria-label + returnText = text.sanitize(dom.idrefs(actualNode, 'aria-labelledby').map(label => { + if (label !== null) {// handle unfound elements by dom.idref + if (actualNode === label) { + encounteredNodes.pop(); + } //let element be encountered twice + const vLabel = axe.utils.getNodeFromTree(axe._tree[0], label); + return accessibleNameComputation(vLabel, true, actualNode !== label); + } else { + return ''; + } }).join(' ')); } - if (!(inControlContext && isEmbeddedControl(element)) && + if (!returnText && !(inControlContext && isEmbeddedControl(element)) && actualNode.hasAttribute('aria-label')) { return text.sanitize(actualNode.getAttribute('aria-label')); } - return ''; + return returnText; } /** @@ -244,19 +250,15 @@ text.accessibleText = function(element, inLabelledByContext) { * @return {string} */ accessibleNameComputation = function (element, inLabelledByContext, inControlContext) { - // TODO: Make sure I don't have to do this let returnText; - if (element.actualNode instanceof Node !== true) { - /* global console */ - var e = new Error('Invalid argument. Virtual Node must be provided'); - console.error(e); - throw e; - } - // If the node was already checked or is null, skip if (!element || encounteredNodes.includes(element)) { return ''; + // if the node is invalid, throw + } else if (element !== null && element.actualNode instanceof Node !== true) { + throw new Error('Invalid argument. Virtual Node must be provided'); + //Step 2a: Skip if the element is hidden, unless part of labelledby } else if(!inLabelledByContext && !dom.isVisible(element.actualNode, true)) { return ''; diff --git a/test/commons/text/accessible-text.js b/test/commons/text/accessible-text.js index 3484a9721b..10e5c04f3a 100644 --- a/test/commons/text/accessible-text.js +++ b/test/commons/text/accessible-text.js @@ -2,6 +2,7 @@ describe('text.accessibleText', function() { 'use strict'; var fixture = document.getElementById('fixture'); + var shadowSupport = axe.testUtils.shadowSupport; afterEach(function() { fixture.innerHTML = ''; @@ -397,9 +398,24 @@ describe('text.accessibleText', function() { assert.equal(axe.commons.text.accessibleText(target), ''); }); + (shadowSupport.v1 ? it : xit)('should only find aria-labelledby element in the same context ', function() { + fixture.innerHTML = '