From 551ba24efa4108c18fe1a81ae9107d694fa9a5aa Mon Sep 17 00:00:00 2001 From: Ava Gaiety W Date: Fri, 19 Apr 2024 09:26:13 -0500 Subject: [PATCH 1/2] fix(aria-valid-attr-value): aria-controls & aria-haspopup incomplete if an element has both aria-controls and aria-haspopup mark it incomplete as we are unsure if the DOM element will be added dynamically later Refs: #4363 --- lib/checks/aria/aria-valid-attr-value-evaluate.js | 15 +++++++++++++-- lib/checks/aria/aria-valid-attr-value.json | 3 ++- locales/_template.json | 3 ++- test/checks/aria/valid-attr-value.js | 9 +++++++++ 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/lib/checks/aria/aria-valid-attr-value-evaluate.js b/lib/checks/aria/aria-valid-attr-value-evaluate.js index 36e824afc8..79ea53fefb 100644 --- a/lib/checks/aria/aria-valid-attr-value-evaluate.js +++ b/lib/checks/aria/aria-valid-attr-value-evaluate.js @@ -36,12 +36,23 @@ export default function ariaValidAttrValueEvaluate(node, options, virtualNode) { const preChecks = { // aria-controls should only check if element exists if the element - // doesn't have aria-expanded=false or aria-selected=false (tabs) + // doesn't have aria-expanded=false, aria-selected=false (tabs), + // or aria-haspopup (may load later) // @see https://github.com/dequelabs/axe-core/issues/1463 + // @see https://github.com/dequelabs/axe-core/issues/4363 'aria-controls': () => { + const hasPopup = + ['false', null].includes(virtualNode.attr('aria-haspopup')) === false; + + if (hasPopup) { + needsReview = `aria-controls="${virtualNode.attr('aria-controls')}"`; + messageKey = 'controlsWithinPopup'; + } + return ( virtualNode.attr('aria-expanded') !== 'false' && - virtualNode.attr('aria-selected') !== 'false' + virtualNode.attr('aria-selected') !== 'false' && + hasPopup === false ); }, // aria-current should mark as needs review if any value is used that is diff --git a/lib/checks/aria/aria-valid-attr-value.json b/lib/checks/aria/aria-valid-attr-value.json index d533ad667e..df7f2be6d7 100644 --- a/lib/checks/aria/aria-valid-attr-value.json +++ b/lib/checks/aria/aria-valid-attr-value.json @@ -15,7 +15,8 @@ "noIdShadow": "ARIA attribute element ID does not exist on the page or is a descendant of a different shadow DOM tree: ${data.needsReview}", "ariaCurrent": "ARIA attribute value is invalid and will be treated as \"aria-current=true\": ${data.needsReview}", "idrefs": "Unable to determine if ARIA attribute element ID exists on the page: ${data.needsReview}", - "empty": "ARIA attribute value is ignored while empty: ${data.needsReview}" + "empty": "ARIA attribute value is ignored while empty: ${data.needsReview}", + "controlsWithinPopup": "Unable to determine if aria-controls referenced ID exists on the page while using aria-haspopup: ${data.needsReview}" } } } diff --git a/locales/_template.json b/locales/_template.json index a911c60144..0029d133a3 100644 --- a/locales/_template.json +++ b/locales/_template.json @@ -538,7 +538,8 @@ "noIdShadow": "ARIA attribute element ID does not exist on the page or is a descendant of a different shadow DOM tree: ${data.needsReview}", "ariaCurrent": "ARIA attribute value is invalid and will be treated as \"aria-current=true\": ${data.needsReview}", "idrefs": "Unable to determine if ARIA attribute element ID exists on the page: ${data.needsReview}", - "empty": "ARIA attribute value is ignored while empty: ${data.needsReview}" + "empty": "ARIA attribute value is ignored while empty: ${data.needsReview}", + "controlsWithinPopup": "Unable to determine if aria-controls referenced ID exists on the page while using aria-haspopup: ${data.needsReview}" } }, "aria-valid-attr": { diff --git a/test/checks/aria/valid-attr-value.js b/test/checks/aria/valid-attr-value.js index a9e3a3afcc..e2605ecd8b 100644 --- a/test/checks/aria/valid-attr-value.js +++ b/test/checks/aria/valid-attr-value.js @@ -110,6 +110,15 @@ describe('aria-valid-attr-value', function () { assert.isFalse(validAttrValueCheck.call(checkContext, null, null, vNode)); }); + it('should return undefined on aria-controls with aria-haspopup as we cannot determine if it is in the DOM later', function () { + var vNode = queryFixture( + '' + ); + assert.isUndefined( + validAttrValueCheck.call(checkContext, null, null, vNode) + ); + }); + it('should pass on aria-owns and aria-expanded=false when the element is not in the DOM', function () { var vNode = queryFixture( '' From a82371226d202899325ac661106519e70008cefe Mon Sep 17 00:00:00 2001 From: Ava Gaiety W Date: Tue, 23 Apr 2024 08:56:45 -0500 Subject: [PATCH 2/2] fix(aria-valid-attr-value): more thorough test coverage - messageKey added to unit test - integration test Refs: #4363 --- test/checks/aria/valid-attr-value.js | 4 ++++ .../rules/aria-valid-attr-value/aria-valid-attr-value.html | 3 +++ .../rules/aria-valid-attr-value/aria-valid-attr-value.json | 3 ++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/test/checks/aria/valid-attr-value.js b/test/checks/aria/valid-attr-value.js index e2605ecd8b..956c3b496b 100644 --- a/test/checks/aria/valid-attr-value.js +++ b/test/checks/aria/valid-attr-value.js @@ -117,6 +117,10 @@ describe('aria-valid-attr-value', function () { assert.isUndefined( validAttrValueCheck.call(checkContext, null, null, vNode) ); + assert.deepEqual(checkContext._data, { + messageKey: 'controlsWithinPopup', + needsReview: 'aria-controls="test"' + }); }); it('should pass on aria-owns and aria-expanded=false when the element is not in the DOM', function () { diff --git a/test/integration/rules/aria-valid-attr-value/aria-valid-attr-value.html b/test/integration/rules/aria-valid-attr-value/aria-valid-attr-value.html index 42e60bae4c..1542a403b9 100644 --- a/test/integration/rules/aria-valid-attr-value/aria-valid-attr-value.html +++ b/test/integration/rules/aria-valid-attr-value/aria-valid-attr-value.html @@ -360,4 +360,7 @@

Possible False Positives

I'm actually valid
I'm not really gone
+
+ May have injected html to control dynamically later, who knows! +
diff --git a/test/integration/rules/aria-valid-attr-value/aria-valid-attr-value.json b/test/integration/rules/aria-valid-attr-value/aria-valid-attr-value.json index 8fb15e1190..f0b46c6fc4 100644 --- a/test/integration/rules/aria-valid-attr-value/aria-valid-attr-value.json +++ b/test/integration/rules/aria-valid-attr-value/aria-valid-attr-value.json @@ -236,6 +236,7 @@ ["#incomplete5"], ["#incomplete6"], ["#incomplete7"], - ["#incomplete8"] + ["#incomplete8"], + ["#incomplete9"] ] }