Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(image-redundant-alt): prevent redundant issues of image tree #1616

Merged
merged 3 commits into from
Jun 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/rule-descriptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down
28 changes: 13 additions & 15 deletions lib/checks/label/duplicate-img-label.js
Original file line number Diff line number Diff line change
@@ -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();
6 changes: 3 additions & 3 deletions lib/rules/img-redundant-alt.json
Original file line number Diff line number Diff line change
@@ -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": [],
Expand Down
52 changes: 25 additions & 27 deletions test/checks/label/duplicate-img-label.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,8 @@ describe('duplicate-img-label', function() {
axe._tree = undefined;
});

it('should return false if no img is present', function() {
fixture.innerHTML = '<button id="target">Plain text</button>';
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 = '<button id="target"><img alt="Plain text"></button>';
fixture.innerHTML = '<button><img id="target" alt="Plain text"></button>';
var node = fixture.querySelector('#target');
axe.testUtils.flatTreeSetup(fixture);
var result = checks['duplicate-img-label'].evaluate(
Expand All @@ -37,7 +24,7 @@ describe('duplicate-img-label', function() {

it('should return false if aria-label duplicates img alt', function() {
fixture.innerHTML =
'<button id="target" aria-label="Plain text"><img alt="Plain text"></button>';
'<button aria-label="Plain text"><img id="target" alt="Plain text"></button>';
var node = fixture.querySelector('#target');
axe.testUtils.flatTreeSetup(fixture);
assert.isFalse(
Expand All @@ -51,7 +38,7 @@ describe('duplicate-img-label', function() {

it('should return false if img and text have different text', function() {
fixture.innerHTML =
'<button id="target"><img alt="Alt text">Plain text</button>';
'<button><img id="target" alt="Alt text">Plain text</button>';
var node = fixture.querySelector('#target');
axe.testUtils.flatTreeSetup(fixture);
assert.isFalse(
Expand All @@ -65,7 +52,7 @@ describe('duplicate-img-label', function() {

it('should return true if img and text have the same text', function() {
fixture.innerHTML =
'<button id="target"><img alt="Plain text">Plain text</button>';
'<button><img id="target" alt="Plain text">Plain text</button>';
var node = fixture.querySelector('#target');
axe.testUtils.flatTreeSetup(fixture);
assert.isTrue(
Expand All @@ -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 =
'<button id="target"><img aria-label="Plain text">Plain text</button>';
'<button><img id="target" aria-label="Plain text">Plain text</button>';
var node = fixture.querySelector('#target');
axe.testUtils.flatTreeSetup(fixture);
assert.isTrue(
Expand All @@ -92,7 +79,7 @@ describe('duplicate-img-label', function() {
});

it('should return false if img and text are both blank', function() {
fixture.innerHTML = '<button id="target"><img alt=""></button>';
fixture.innerHTML = '<button><img id="target" alt=""></button>';
var node = fixture.querySelector('#target');
axe.testUtils.flatTreeSetup(fixture);
assert.isFalse(
Expand All @@ -106,7 +93,7 @@ describe('duplicate-img-label', function() {

it('should return false if img and text have superset/subset text', function() {
fixture.innerHTML =
'<button id="target"><img alt="Plain text and more">Plain text</button>';
'<button><img id="target" alt="Plain text and more">Plain text</button>';
var node = fixture.querySelector('#target');
axe.testUtils.flatTreeSetup(fixture);
assert.isFalse(
Expand All @@ -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 = '<slot></slot><img alt="My button">';
var checkArgs = checkSetup(button);

shadow.innerHTML = '<slot></slot><img id="target" alt="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)
)
);
}
);
Expand All @@ -139,13 +131,19 @@ describe('duplicate-img-label', function() {
function() {
var button = document.createElement('div');
button.setAttribute('role', 'button');
button.innerHTML = '<img alt="My button">';
button.innerHTML = '<img id="target" alt="My button">';
var shadow = button.attachShadow({ mode: 'open' });
shadow.innerHTML = '<span>My button</span> <slot></slot>';
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)
)
);
}
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
<button id="pass1"><img alt="Img alt text" />Link text</button>
<a href="#" id="pass2"><img alt="Img alt text" />Link text</a>
<a href="#" id="pass3"><img alt="Link text" role="presentation" />Link text</a>
<a href="#" id="pass4"><img alt="Link text" aria-hidden="true" />Link text</a>
<button><img id="pass1" alt="Img alt text" />Link text</button>
<a href="#"><img id="pass2" alt="Img alt text" />Link text</a>
<a href="#"><img id="pass3" alt="Link text" role="presentation" />Link text</a>

<button id="fail1"><img alt="button text" />Button text</button>
<a href="#" id="fail2"><img alt="Link text" />Link text</a>
<p id="fail3"><img alt="paragraph text" />paragraph text</p>
<button><img id="fail1" alt="button text" />Button text</button>
<a href="#"><img id="fail2" alt="Link text" />Link text</a>
<p><img id="fail3" alt="paragraph text" />paragraph text</p>
<table>
<tr>
<th id="fail4"><img alt="header cell text" />header cell text</th>
<td id="fail5"><img alt="data cell text" />data cell text</td>
<th><img id="fail4" alt="header cell text" />header cell text</th>
<td><img id="fail5" alt="data cell text" />data cell text</td>
</tr>
</table>

<ul>
<li id="fail6"><img alt="list text" />list text</li>
<li><img id="fail6" alt="list text" />list text</li>
</ul>

<!-- ignore -->
<a href="#"><img alt="Link text" aria-hidden="true" />Link text</a>
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
["#fail5"],
["#fail6"]
],
"passes": [["#pass1"], ["#pass2"], ["#pass3"], ["#pass4"]]
"passes": [["#pass1"], ["#pass2"], ["#pass3"]]
}