diff --git a/doc/rule-descriptions.md b/doc/rule-descriptions.md index 0132bfb687..1f636c4c5f 100644 --- a/doc/rule-descriptions.md +++ b/doc/rule-descriptions.md @@ -42,7 +42,7 @@ | html-lang-valid | Ensures the lang attribute of the <html> element has a valid value | Serious | cat.language, wcag2a, wcag311 | true | | html-xml-lang-mismatch | Ensure that HTML elements with both valid lang and xml:lang attributes agree on the base language of the page | Moderate | cat.language, wcag2a, wcag311 | true | | image-alt | Ensures <img> elements have alternate text or a role of none or presentation | Critical | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a | true | -| image-redundant-alt | Ensure button and link text is not repeated as image alternative | Minor | cat.text-alternatives, best-practice | true | +| image-redundant-alt | Ensure image alternative is not repeated as text | Minor | cat.text-alternatives, best-practice | true | | input-button-name | Ensures input buttons have discernible text | Critical | cat.name-role-value, wcag2a, wcag412, section508, section508.22.a | true | | input-image-alt | Ensures <input type="image"> elements have alternate text | Critical | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a | true | | label-content-name-mismatch | Ensures that elements labelled through their content must have their visible text as part of their accessible name | Serious | wcag21a, wcag253, experimental | true | diff --git a/lib/checks/label/duplicate-img-label.js b/lib/checks/label/duplicate-img-label.js index 25bc32d124..f97b64a38f 100644 --- a/lib/checks/label/duplicate-img-label.js +++ b/lib/checks/label/duplicate-img-label.js @@ -1,19 +1,17 @@ -const text = axe.commons.text.visibleVirtual(virtualNode, true).toLowerCase(); -if (text === '') { +const { aria, text, dom } = axe.commons; + +if (['none', 'presentation'].includes(aria.getRole(node))) { return false; } -// Get all visible images in the composed tree of the current node -const images = axe.utils - .querySelectorAll(virtualNode, 'img') - // Ignore hidden or role=none/presentation images - .filter( - ({ actualNode }) => - axe.commons.dom.isVisible(actualNode) && - !['none', 'presentation'].includes(actualNode.getAttribute('role')) - ); - -// See if any of the images duplicate the node's text -return images.some( - img => text === axe.commons.text.accessibleTextVirtual(img).toLowerCase() +const parent = dom.findUpVirtual( + virtualNode, + 'button, [role="button"], a[href], p, li, td, th' ); +const parentVNode = axe.utils.getNodeFromTree(parent); +const visibleText = text.visibleVirtual(parentVNode, true).toLowerCase(); +if (visibleText === '') { + return false; +} + +return visibleText === text.accessibleTextVirtual(virtualNode).toLowerCase(); diff --git a/lib/rules/img-redundant-alt.json b/lib/rules/img-redundant-alt.json index 6bed7292c2..e2e92f10de 100644 --- a/lib/rules/img-redundant-alt.json +++ b/lib/rules/img-redundant-alt.json @@ -1,10 +1,10 @@ { "id": "image-redundant-alt", - "selector": "button, [role=\"button\"], a[href], p, li, td, th", + "selector": "img", "tags": ["cat.text-alternatives", "best-practice"], "metadata": { - "description": "Ensure button and link text is not repeated as image alternative", - "help": "Text of buttons and links should not be repeated in the image alternative" + "description": "Ensure image alternative is not repeated as text", + "help": "Alternative text of images should not be repeated as text" }, "all": [], "any": [], diff --git a/test/checks/label/duplicate-img-label.js b/test/checks/label/duplicate-img-label.js index bd15675702..e7d3f6c71e 100644 --- a/test/checks/label/duplicate-img-label.js +++ b/test/checks/label/duplicate-img-label.js @@ -10,21 +10,8 @@ describe('duplicate-img-label', function() { axe._tree = undefined; }); - it('should return false if no img is present', function() { - fixture.innerHTML = ''; - var node = fixture.querySelector('#target'); - axe.testUtils.flatTreeSetup(fixture); - assert.isFalse( - checks['duplicate-img-label'].evaluate( - node, - undefined, - axe.utils.getNodeFromTree(node) - ) - ); - }); - it('should return false if no text is present', function() { - fixture.innerHTML = ''; + fixture.innerHTML = ''; var node = fixture.querySelector('#target'); axe.testUtils.flatTreeSetup(fixture); var result = checks['duplicate-img-label'].evaluate( @@ -37,7 +24,7 @@ describe('duplicate-img-label', function() { it('should return false if aria-label duplicates img alt', function() { fixture.innerHTML = - ''; + ''; var node = fixture.querySelector('#target'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse( @@ -51,7 +38,7 @@ describe('duplicate-img-label', function() { it('should return false if img and text have different text', function() { fixture.innerHTML = - ''; + ''; var node = fixture.querySelector('#target'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse( @@ -65,7 +52,7 @@ describe('duplicate-img-label', function() { it('should return true if img and text have the same text', function() { fixture.innerHTML = - ''; + ''; var node = fixture.querySelector('#target'); axe.testUtils.flatTreeSetup(fixture); assert.isTrue( @@ -79,7 +66,7 @@ describe('duplicate-img-label', function() { it('should return true if img has ARIA label with the same text', function() { fixture.innerHTML = - ''; + ''; var node = fixture.querySelector('#target'); axe.testUtils.flatTreeSetup(fixture); assert.isTrue( @@ -92,7 +79,7 @@ describe('duplicate-img-label', function() { }); it('should return false if img and text are both blank', function() { - fixture.innerHTML = ''; + fixture.innerHTML = ''; var node = fixture.querySelector('#target'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse( @@ -106,7 +93,7 @@ describe('duplicate-img-label', function() { it('should return false if img and text have superset/subset text', function() { fixture.innerHTML = - ''; + ''; var node = fixture.querySelector('#target'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse( @@ -125,11 +112,16 @@ describe('duplicate-img-label', function() { button.setAttribute('role', 'button'); button.innerHTML = 'My button'; var shadow = button.attachShadow({ mode: 'open' }); - shadow.innerHTML = 'My button'; - var checkArgs = checkSetup(button); - + shadow.innerHTML = 'My button'; + fixture.appendChild(button); + axe.testUtils.flatTreeSetup(fixture); + var node = shadow.querySelector('#target'); assert.isTrue( - checks['duplicate-img-label'].evaluate.apply(null, checkArgs) + checks['duplicate-img-label'].evaluate( + node, + undefined, + axe.utils.getNodeFromTree(node) + ) ); } ); @@ -139,13 +131,19 @@ describe('duplicate-img-label', function() { function() { var button = document.createElement('div'); button.setAttribute('role', 'button'); - button.innerHTML = 'My button'; + button.innerHTML = 'My button'; var shadow = button.attachShadow({ mode: 'open' }); shadow.innerHTML = 'My button '; - var checkArgs = checkSetup(button); + fixture.appendChild(button); + axe.testUtils.flatTreeSetup(fixture); + var node = button.querySelector('#target'); assert.isTrue( - checks['duplicate-img-label'].evaluate.apply(null, checkArgs) + checks['duplicate-img-label'].evaluate( + node, + undefined, + axe.utils.getNodeFromTree(node) + ) ); } ); diff --git a/test/integration/rules/image-redundant-alt/image-redundant-alt.html b/test/integration/rules/image-redundant-alt/image-redundant-alt.html index dfd2687b83..dce9aca2e2 100644 --- a/test/integration/rules/image-redundant-alt/image-redundant-alt.html +++ b/test/integration/rules/image-redundant-alt/image-redundant-alt.html @@ -1,18 +1,20 @@ - -Img alt textLink text -Link textLink text -Link text + +Img alt textLink text +Link textLink text - -Link textLink text -

paragraph textparagraph text

+ +Link textLink text +

paragraph textparagraph text

- - + +
header cell textheader cell textdata cell textdata cell textheader cell textheader cell textdata cell textdata cell text
+ + +Link text diff --git a/test/integration/rules/image-redundant-alt/image-redundant-alt.json b/test/integration/rules/image-redundant-alt/image-redundant-alt.json index b8a244b349..0e938b549f 100644 --- a/test/integration/rules/image-redundant-alt/image-redundant-alt.json +++ b/test/integration/rules/image-redundant-alt/image-redundant-alt.json @@ -9,5 +9,5 @@ ["#fail5"], ["#fail6"] ], - "passes": [["#pass1"], ["#pass2"], ["#pass3"], ["#pass4"]] + "passes": [["#pass1"], ["#pass2"], ["#pass3"]] }