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

feat(new-rule): ARIA links, buttons, menuitems have an accessible name #2571

Merged
merged 3 commits into from
Oct 23, 2020
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
4 changes: 3 additions & 1 deletion build/tasks/validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,9 @@ function createSchemas() {
items: {
type: 'string'
},
conform: function hasCategoryTag(tags) { return tags.some(tag => tag.includes('cat.')) },
conform: function hasCategoryTag(tags) {
return tags.some(tag => tag.includes('cat.'));
},
Comment on lines -202 to +204
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, not sure how that didn't make it in last PR. Shouldn't matter.

messages: {
conform: 'must include a category tag'
}
Expand Down
1 change: 1 addition & 0 deletions doc/rule-descriptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
| :------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------ | :---------------- | :------------------------------------------------------------------------------------ | :------------------------- |
| [area-alt](https://dequeuniversity.com/rules/axe/4.0/area-alt?application=RuleDescription) | Ensures <area> elements of image maps have alternate text | Critical | cat.text-alternatives, wcag2a, wcag111, wcag244, wcag412, section508, section508.22.a | failure, needs review |
| [aria-allowed-attr](https://dequeuniversity.com/rules/axe/4.0/aria-allowed-attr?application=RuleDescription) | Ensures ARIA attributes are allowed for an element's role | Critical | cat.aria, wcag2a, wcag412 | failure |
| [aria-command-name](https://dequeuniversity.com/rules/axe/4.0/aria-command-name?application=RuleDescription) | Ensures every ARIA button, link and menuitem has an accessible name | Serious | wcag2a, wcag412 | failure, needs review |
| [aria-hidden-body](https://dequeuniversity.com/rules/axe/4.0/aria-hidden-body?application=RuleDescription) | Ensures aria-hidden='true' is not present on the document body. | Critical | cat.aria, wcag2a, wcag412 | failure |
| [aria-hidden-focus](https://dequeuniversity.com/rules/axe/4.0/aria-hidden-focus?application=RuleDescription) | Ensures aria-hidden elements do not contain focusable elements | Serious | cat.name-role-value, wcag2a, wcag412, wcag131 | failure, needs review |
| [aria-input-field-name](https://dequeuniversity.com/rules/axe/4.0/aria-input-field-name?application=RuleDescription) | Ensures every ARIA input field has an accessible name | Moderate, Serious | cat.aria, wcag2a, wcag412 | failure, needs review |
Expand Down
18 changes: 18 additions & 0 deletions lib/rules/aria-command-name.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"id": "aria-command-name",
"selector": "[role=\"link\"], [role=\"button\"], [role=\"menuitem\"]",
"matches": "no-naming-method-matches",
"tags": ["wcag2a", "wcag412"],
"metadata": {
"description": "Ensures every ARIA button, link and menuitem has an accessible name",
"help": "ARIA commands must have an accessible name"
},
"all": [],
"any": [
"aria-label",
"aria-labelledby",
"non-empty-title",
"has-visible-text"
],
"none": []
}
2 changes: 1 addition & 1 deletion lib/rules/aria-tooltip-name.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"tags": ["cat.aria", "wcag2a", "wcag412"],
"metadata": {
"description": "Ensures every ARIA tooltip node has an accessible name",
"help": "ARIA tooltip ndoes must have an accessible name"
"help": "ARIA tooltip nodes must have an accessible name"
},
"all": [],
"any": [
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/button-name.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"id": "button-name",
"selector": "button, [role=\"button\"]:not(input)",
"selector": "button",
"tags": [
"cat.name-role-value",
"wcag2a",
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/link-name.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"id": "link-name",
"selector": "a[href]:not([role=button]), [role=link]",
"selector": "a[href]",
"tags": [
"cat.name-role-value",
"wcag2a",
Expand Down
53 changes: 53 additions & 0 deletions test/integration/rules/aria-command-name/aria-command-name.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<!-- PASS -->
<div id="pass1" role="link">Home</div>
<div id="pass2" role="link" title="About"></div>
<div id="pass3" role="link" aria-label="Products"></div>
<div id="pass4" role="link" aria-labelledby="contact"></div>
<div id="contact">Contact us</div>

<div id="pass5" role="button">Submit</div>
<div id="pass6" role="button" title="Upload"></div>
<div id="pass7" role="button" aria-label="Download"></div>
<div id="pass8" role="button" aria-labelledby="print"></div>

<div role="menu">
<div id="pass9" role="menuitem">New</div>
<div id="pass10" role="menuitem" title="Open"></div>
<div id="pass11" role="menuitem" aria-label="Save"></div>
<div id="pass12" role="menuitem" aria-labelledby="print"></div>
</div>

<div id="print">print file</div>

<!-- FAIL -->
<div id="fail1" role="link"></div>
<div id="fail2" role="link" aria-labelledby="non-existant"></div>
<div id="fail3" role="link" aria-labelledby="div-empty"></div>

<div id="fail4" role="button"></div>
<div id="fail5" role="button" aria-labelledby="non-existant"></div>
<div id="fail6" role="button" aria-labelledby="div-empty"></div>

<div role="menu">
<div id="fail7" role="menuitem"></div>
<div id="fail8" role="menuitem" aria-labelledby="non-existant"></div>
<div id="fail9" role="menuitem" aria-labelledby="div-empty"></div>
</div>

<div id="div-empty"></div>

<!-- INAPPLICABLE -->
<a href="/" role="link">Home</a>
<button role="button">Save</button>
<img role="button" alt="Send" id="inapplicable1" />
<div role="menu">
<input role="menuitem" title="Label" id="inapplicable2" />
<button role="menuitem" title="Label" id="inapplicable3"></button>
<a href="#" role="menuitem" title="Label" id="inapplicable4"></a>
<select role="menuitem" title="Label" id="inapplicable5">
<option value="volvo">Volvo</option>
<option value="saab">Saab</option>
<option value="opel">Opel</option>
</select>
<textarea role="menuitem" id="inapplicable6" title="Label"></textarea>
</div>
29 changes: 29 additions & 0 deletions test/integration/rules/aria-command-name/aria-command-name.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"description": "aria-command-name test",
"rule": "aria-command-name",
"passes": [
["#pass1"],
["#pass2"],
["#pass3"],
["#pass4"],
["#pass5"],
["#pass6"],
["#pass7"],
["#pass8"],
["#pass9"],
["#pass10"],
["#pass11"],
["#pass12"]
],
"violations": [
["#fail1"],
["#fail2"],
["#fail3"],
["#fail4"],
["#fail5"],
["#fail6"],
["#fail7"],
["#fail8"],
["#fail9"]
]
}
5 changes: 3 additions & 2 deletions test/integration/rules/button-name/button-name.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@
<button id="buttonTitle" title="Title"></button>
<button id="buttonvalue" value="foo" tabindex="-1"></button>

<input type="submit" value="submit" role="button" id="ignored" />

<button id="fail1" role="presentation"></button>
<button id="fail2" role="none"></button>

<button id="pass1" role="presentation" disabled></button>
<button id="pass2" role="none" disabled></button>

<span id="inapplicable1" role="button">Does not apply</span>
<input type="submit" value="submit" role="button" id="inapplicable2" />
51 changes: 11 additions & 40 deletions test/integration/rules/link-name/link-name.html
Original file line number Diff line number Diff line change
@@ -1,45 +1,16 @@
<a href="#" id="violation1"></a>
<a href="#" id="pass1">This link has text</a>
<a href="#" id="pass3" aria-label="link text"></a>
<a href="#" id="pass4" aria-labelledby="linklabel"></a>
<a href="#" id="violation2" aria-labelledby="nonexistent"></a>
<a href="#" id="violation3" aria-labelledby="badlabel"></a>
<a href="#" id="pass2" aria-label="link text"></a>
<a href="#" id="pass3" aria-labelledby="linklabel"></a>
<a href="#" id="pass4" title="title text"></a>

<div id="linklabel">Text</div>
<div id="badlabel"></div>
<span role="link" href="#" tabindex="0" id="violation4"></span>
<span
role="link"
href="#"
tabindex="0"
id="pass6"
aria-labelledby="linklabel"
></span>
<span
role="link"
href="#"
tabindex="0"
id="pass7"
aria-label="Link text"
></span>
<span
role="link"
href="#"
tabindex="0"
id="violation5"
aria-labelledby="badlabel"
></span>
<span
role="link"
href="#"
tabindex="0"
id="violation6"
aria-labelledby="nonexistent"
></span>

<a href="#" id="pass8" title="title text"></a>
<span role="link" href="#" tabindex="0" id="pass9" title="title text"></span>
<a href="#" id="violation1"></a>
<a href="#" id="violation2" aria-labelledby="nonexistent"></a>
<a href="#" id="violation3" aria-labelledby="empty-label"></a>
<a href="#" id="violation4" role="none"></a>
<a href="#" id="violation5" role="presentation"></a>

<a href="#" role="button">Does not apply</a>
<div id="empty-label"></div>

<a href="#" id="violation7" role="none"></a>
<a href="#" id="violation8" role="presentation"></a>
<span id="inapplicable1" role="link">Does not apply</span>
15 changes: 2 additions & 13 deletions test/integration/rules/link-name/link-name.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,7 @@
["#violation2"],
["#violation3"],
["#violation4"],
["#violation5"],
["#violation6"],
["#violation7"],
["#violation8"]
["#violation5"]
],
"passes": [
["#pass1"],
["#pass3"],
["#pass4"],
["#pass6"],
["#pass7"],
["#pass8"],
["#pass9"]
]
"passes": [["#pass1"], ["#pass2"], ["#pass3"], ["#pass4"]]
}
13 changes: 0 additions & 13 deletions test/integration/rules/role-button-name/role-button-name.html

This file was deleted.

This file was deleted.

89 changes: 89 additions & 0 deletions test/integration/virtual-rules/aria-command-name.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
describe('aria-command-name', function() {
it('should pass for aria-label', function() {
var node = new axe.SerialVirtualNode({
nodeName: 'div',
attributes: {
role: 'link',
'aria-label': 'foobar'
}
});
node.parent = null;

var results = axe.runVirtualRule('aria-command-name', node);

assert.lengthOf(results.passes, 1);
assert.lengthOf(results.violations, 0);
assert.lengthOf(results.incomplete, 0);
});

it('should incomplete for aria-labelledby', function() {
var node = new axe.SerialVirtualNode({
nodeName: 'div',
attributes: {
role: 'button',
'aria-labelledby': 'foobar'
}
});
node.parent = null;

var results = axe.runVirtualRule('aria-command-name', node);

assert.lengthOf(results.passes, 0);
assert.lengthOf(results.violations, 0);
assert.lengthOf(results.incomplete, 1);
});

it('should pass for title', function() {
var node = new axe.SerialVirtualNode({
nodeName: 'div',
attributes: {
role: 'menuitem',
title: 'foobar'
}
});
// children are required since titleText comes after subtree text
// in accessible name calculation
node.children = [];
node.parent = null;

var results = axe.runVirtualRule('aria-command-name', node);

assert.lengthOf(results.passes, 1);
assert.lengthOf(results.violations, 0);
assert.lengthOf(results.incomplete, 0);
});

it('should fail when aria-label contains only whitespace', function() {
var node = new axe.SerialVirtualNode({
nodeName: 'div',
attributes: {
role: 'link',
'aria-label': ' \t \n '
}
});
node.children = [];

var results = axe.runVirtualRule('aria-command-name', node);

assert.lengthOf(results.passes, 0);
assert.lengthOf(results.violations, 1);
assert.lengthOf(results.incomplete, 0);
});

it('should fail when title is empty', function() {
var node = new axe.SerialVirtualNode({
nodeName: 'div',
attributes: {
role: 'button',
title: ''
}
});
node.children = [];

var results = axe.runVirtualRule('aria-command-name', node);

assert.lengthOf(results.passes, 0);
assert.lengthOf(results.violations, 1);
assert.lengthOf(results.incomplete, 0);
});
});
21 changes: 12 additions & 9 deletions test/integration/virtual-rules/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,24 @@
</head>
<body>
<div id="mocha"></div>
<script src="area-alt.js"></script>
<script src="aria-command-name.js"></script>
<script src="aria-input-field-name.js"></script>
<script src="aria-progressbar-name.js"></script>
<script src="aria-toggle-field-name.js"></script>
<script src="aria-tooltip-name.js"></script>
<script src="autocomplete-valid.js"></script>
<script src="image-alt.js"></script>
<script src="button-name.js"></script>
<script src="frame-title.js"></script>
<script src="image-alt.js"></script>
<script src="input-button-name.js"></script>
<script src="input-image-alt.js"></script>
<script src="object-alt.js"></script>
<script src="label.js"></script>
<script src="button-name.js"></script>
<script src="input-button-name.js"></script>
<script src="aria-toggle-field-name.js"></script>
<script src="aria-input-field-name.js"></script>
<script src="area-alt.js"></script>
<script src="svg-img-alt.js"></script>
<script src="role-img-alt.js"></script>
<script src="link-name.js"></script>
<script src="object-alt.js"></script>
<script src="role-img-alt.js"></script>
<script src="select-name.js"></script>
<script src="svg-img-alt.js"></script>
<script src="/test/integration/adapter.js"></script>
</body>
</html>
Loading