Skip to content

Commit 16682fd

Browse files
authored
feat(rule): aria-roledescription (#1745)
* feat(rule): aria-roledescription * change supportedRoles to options * update meta and tests
1 parent 42158ac commit 16682fd

File tree

11 files changed

+185
-32
lines changed

11 files changed

+185
-32
lines changed

doc/aria-supported.md

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,7 @@ For a detailed description about how accessibility support is decided, see [How
88

99
## Attributes
1010

11-
| aria-attribute | axe-core support |
12-
| -------------------- | ---------------- |
13-
| aria-describedat | No |
14-
| aria-details | No |
15-
| aria-roledescription | Mixed[^1] |
16-
17-
[^1]: Supported on elements: `<button>`, `<input type="button" | "checkbox" | "image" | "radio" | "reset" | "submit">`, `<img>`, `<select>`, `<summary>`
11+
| aria-attribute | axe-core support |
12+
| ---------------- | ---------------- |
13+
| aria-describedat | No |
14+
| aria-details | No |

doc/rule-descriptions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
| aria-required-attr | Ensures elements with ARIA roles have all required ARIA attributes | Critical | cat.aria, wcag2a, wcag412 | true |
1212
| aria-required-children | Ensures elements with an ARIA role that require child roles contain them | Critical | cat.aria, wcag2a, wcag131 | true |
1313
| aria-required-parent | Ensures elements with an ARIA role that require parent roles are contained by them | Critical | cat.aria, wcag2a, wcag131 | true |
14+
| aria-roledescription | Ensure aria-roledescription is only used on elements with an implicit or explicit role | Serious | cat.aria, wcag2a, wcag412 | true |
1415
| aria-roles | Ensures all elements with a role attribute use a valid value | Serious, Critical | cat.aria, wcag2a, wcag412 | true |
1516
| aria-toggle-field-name | Ensures every ARIA toggle field has an accessible name | Moderate, Serious | wcag2a, wcag412 | true |
1617
| aria-valid-attr-value | Ensures all ARIA attributes have valid values | Critical | cat.aria, wcag2a, wcag412 | true |
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
options = options || {};
2+
3+
const role = axe.commons.aria.getRole(node);
4+
const supportedRoles = options.supportedRoles || [];
5+
6+
if (supportedRoles.includes(role)) {
7+
return true;
8+
}
9+
10+
if (role && role !== 'presentation' && role !== 'none') {
11+
return undefined;
12+
}
13+
14+
return false;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"id": "aria-roledescription",
3+
"evaluate": "aria-roledescription.js",
4+
"options": {
5+
"supportedRoles": [
6+
"button",
7+
"img",
8+
"checkbox",
9+
"radio",
10+
"combobox",
11+
"menuitemcheckbox",
12+
"menuitemradio"
13+
]
14+
},
15+
"metadata": {
16+
"impact": "serious",
17+
"messages": {
18+
"pass": "aria-roledescription used on a supported semantic role",
19+
"incomplete": "Check that the aria-roledescription is announced by supported screen readers",
20+
"fail": "Give the element a role that supports aria-roledescription"
21+
}
22+
}
23+
}

lib/commons/aria/index.js

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -198,20 +198,7 @@ lookupTable.attributes = {
198198
'aria-roledescription': {
199199
type: 'string',
200200
allowEmpty: true,
201-
unsupported: {
202-
exceptions: [
203-
'button',
204-
{
205-
nodeName: 'input',
206-
properties: {
207-
type: ['button', 'checkbox', 'image', 'radio', 'reset', 'submit']
208-
}
209-
},
210-
'img',
211-
'select',
212-
'summary'
213-
]
214-
}
201+
unsupported: false
215202
},
216203
'aria-rowcount': {
217204
type: 'int',

lib/rules/aria-roledescription.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"id": "aria-roledescription",
3+
"selector": "[aria-roledescription]",
4+
"tags": ["cat.aria", "wcag2a", "wcag412"],
5+
"metadata": {
6+
"description": "Ensure aria-roledescription is only used on elements with an implicit or explicit role",
7+
"help": "Use aria-roledescription on elements with a semantic role"
8+
},
9+
"all": [],
10+
"any": ["aria-roledescription"],
11+
"none": []
12+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
describe('aria-roledescription', function() {
2+
'use strict';
3+
4+
var fixture = document.getElementById('fixture');
5+
var checkContext = axe.testUtils.MockCheckContext();
6+
7+
afterEach(function() {
8+
fixture.innerHTML = '';
9+
checkContext.reset();
10+
});
11+
12+
it('returns true for elements with an implicit supported role', function() {
13+
fixture.innerHTML =
14+
'<button aria-roledescription="Awesome Button">Click</button>';
15+
var actual = checks['aria-roledescription'].evaluate.call(
16+
checkContext,
17+
fixture.firstChild,
18+
{
19+
supportedRoles: ['button']
20+
}
21+
);
22+
assert.equal(actual, true);
23+
assert.isNull(checkContext._data, null);
24+
});
25+
26+
it('returns true for elements with an explicit supported role', function() {
27+
fixture.innerHTML =
28+
'<div role="radio" aria-roledescription="Awesome Radio">Click</div>';
29+
var actual = checks['aria-roledescription'].evaluate.call(
30+
checkContext,
31+
fixture.firstChild,
32+
{
33+
supportedRoles: ['radio']
34+
}
35+
);
36+
assert.equal(actual, true);
37+
assert.isNull(checkContext._data, null);
38+
});
39+
40+
it('returns undefined for elements with an unsupported role', function() {
41+
fixture.innerHTML =
42+
'<div role="main" aria-roledescription="Awesome Main">The main element</div>';
43+
var actual = checks['aria-roledescription'].evaluate.call(
44+
checkContext,
45+
fixture.firstChild
46+
);
47+
assert.equal(actual, undefined);
48+
assert.isNull(checkContext._data, null);
49+
});
50+
51+
it('returns false for elements without role', function() {
52+
fixture.innerHTML =
53+
'<div aria-roledescription="Awesome Main">The main element</div>';
54+
var actual = checks['aria-roledescription'].evaluate.call(
55+
checkContext,
56+
fixture.firstChild
57+
);
58+
assert.equal(actual, false);
59+
assert.isNull(checkContext._data, null);
60+
});
61+
62+
it('returns false for elements with role=presentation', function() {
63+
fixture.innerHTML =
64+
'<div role="presentation" aria-roledescription="Awesome Main">The main element</div>';
65+
var actual = checks['aria-roledescription'].evaluate.call(
66+
checkContext,
67+
fixture.firstChild
68+
);
69+
assert.equal(actual, false);
70+
assert.isNull(checkContext._data, null);
71+
});
72+
73+
it('returns false for elements with role=none', function() {
74+
fixture.innerHTML =
75+
'<div role="none" aria-roledescription="Awesome Main">The main element</div>';
76+
var actual = checks['aria-roledescription'].evaluate.call(
77+
checkContext,
78+
fixture.firstChild
79+
);
80+
assert.equal(actual, false);
81+
assert.isNull(checkContext._data, null);
82+
});
83+
});

test/integration/rules/aria-allowed-attr/failures.html

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,3 @@
66
<!-- unsupported attributes -->
77
<div aria-describedat="#fail4" id="fail5">fail</div>
88
<div aria-details="fail5" id="fail6">fail</div>
9-
<div aria-roledescription="Slide" id="fail7">fail</div>
10-
<p id="fail8" aria-roledescription="status">
11-
warning: things are a wee bit bit slow
12-
</p>
13-
<input id="fail9" type="text" aria-roledescription="input" />
14-
<textarea id="fail10" type="text" aria-roledescription="comments"></textarea>

test/integration/rules/aria-allowed-attr/failures.json

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,6 @@
77
["#fail3"],
88
["#fail4"],
99
["#fail5"],
10-
["#fail6"],
11-
["#fail7"],
12-
["#fail8"],
13-
["#fail9"],
14-
["#fail10"]
10+
["#fail6"]
1511
]
1612
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<button aria-roledescription="my button" id="pass1">button</button>
2+
<img aria-roledescription="my img" src="foo.png" id="pass2" />
3+
<div role="checkbox" aria-roledescription="my checkbox" id="pass3"></div>
4+
<div role="radio" aria-roledescription="my radio" id="pass4"></div>
5+
<div role="combobox" aria-roledescription="my combobox" id="pass5"></div>
6+
<div
7+
role="menuitemcheckbox"
8+
aria-roledescription="my menuitemcheckbox"
9+
id="pass6"
10+
></div>
11+
<div
12+
role="menuitemradio"
13+
aria-roledescription="my menuitemradio"
14+
id="pass7"
15+
></div>
16+
<input type="checkbox" aria-roledescription="my checkbox" id="pass8" />
17+
<input type="radio" aria-roledescription="my radio" id="pass9" />
18+
19+
<h1 aria-roledescription="my heading" id="incomplete1">heading</h1>
20+
<div role="rowgroup" aria-roledescription="my row" id="incomplete2"></div>
21+
22+
<p aria-roledescription="my paragraph" id="fail1">paragraph</p>
23+
<div aria-roledescription="my div" id="fail2">div</div>
24+
<div
25+
role="presentation"
26+
aria-roledescription="my presentation"
27+
id="fail3"
28+
></div>
29+
<div role="none" aria-roledescription="my none" id="fail4"></div>

0 commit comments

Comments
 (0)