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 = '
paragraph text
+ +Link text +paragraph text
header cell text | -data cell text | +header cell text | +data cell text |
---|