Skip to content

Commit

Permalink
feat(rule): aria-roledescription (#1745)
Browse files Browse the repository at this point in the history
* feat(rule): aria-roledescription

* change supportedRoles to options

* update meta and tests
  • Loading branch information
straker committed Aug 20, 2019
1 parent 42158ac commit 16682fd
Show file tree
Hide file tree
Showing 11 changed files with 185 additions and 32 deletions.
11 changes: 4 additions & 7 deletions doc/aria-supported.md
Expand Up @@ -8,10 +8,7 @@ For a detailed description about how accessibility support is decided, see [How

## Attributes

| aria-attribute | axe-core support |
| -------------------- | ---------------- |
| aria-describedat | No |
| aria-details | No |
| aria-roledescription | Mixed[^1] |

[^1]: Supported on elements: `<button>`, `<input type="button" | "checkbox" | "image" | "radio" | "reset" | "submit">`, `<img>`, `<select>`, `<summary>`
| aria-attribute | axe-core support |
| ---------------- | ---------------- |
| aria-describedat | No |
| aria-details | No |
1 change: 1 addition & 0 deletions doc/rule-descriptions.md
Expand Up @@ -11,6 +11,7 @@
| aria-required-attr | Ensures elements with ARIA roles have all required ARIA attributes | Critical | cat.aria, wcag2a, wcag412 | true |
| aria-required-children | Ensures elements with an ARIA role that require child roles contain them | Critical | cat.aria, wcag2a, wcag131 | true |
| aria-required-parent | Ensures elements with an ARIA role that require parent roles are contained by them | Critical | cat.aria, wcag2a, wcag131 | true |
| aria-roledescription | Ensure aria-roledescription is only used on elements with an implicit or explicit role | Serious | cat.aria, wcag2a, wcag412 | true |
| aria-roles | Ensures all elements with a role attribute use a valid value | Serious, Critical | cat.aria, wcag2a, wcag412 | true |
| aria-toggle-field-name | Ensures every ARIA toggle field has an accessible name | Moderate, Serious | wcag2a, wcag412 | true |
| aria-valid-attr-value | Ensures all ARIA attributes have valid values | Critical | cat.aria, wcag2a, wcag412 | true |
Expand Down
14 changes: 14 additions & 0 deletions lib/checks/aria/aria-roledescription.js
@@ -0,0 +1,14 @@
options = options || {};

const role = axe.commons.aria.getRole(node);
const supportedRoles = options.supportedRoles || [];

if (supportedRoles.includes(role)) {
return true;
}

if (role && role !== 'presentation' && role !== 'none') {
return undefined;
}

return false;
23 changes: 23 additions & 0 deletions lib/checks/aria/aria-roledescription.json
@@ -0,0 +1,23 @@
{
"id": "aria-roledescription",
"evaluate": "aria-roledescription.js",
"options": {
"supportedRoles": [
"button",
"img",
"checkbox",
"radio",
"combobox",
"menuitemcheckbox",
"menuitemradio"
]
},
"metadata": {
"impact": "serious",
"messages": {
"pass": "aria-roledescription used on a supported semantic role",
"incomplete": "Check that the aria-roledescription is announced by supported screen readers",
"fail": "Give the element a role that supports aria-roledescription"
}
}
}
15 changes: 1 addition & 14 deletions lib/commons/aria/index.js
Expand Up @@ -198,20 +198,7 @@ lookupTable.attributes = {
'aria-roledescription': {
type: 'string',
allowEmpty: true,
unsupported: {
exceptions: [
'button',
{
nodeName: 'input',
properties: {
type: ['button', 'checkbox', 'image', 'radio', 'reset', 'submit']
}
},
'img',
'select',
'summary'
]
}
unsupported: false
},
'aria-rowcount': {
type: 'int',
Expand Down
12 changes: 12 additions & 0 deletions lib/rules/aria-roledescription.json
@@ -0,0 +1,12 @@
{
"id": "aria-roledescription",
"selector": "[aria-roledescription]",
"tags": ["cat.aria", "wcag2a", "wcag412"],
"metadata": {
"description": "Ensure aria-roledescription is only used on elements with an implicit or explicit role",
"help": "Use aria-roledescription on elements with a semantic role"
},
"all": [],
"any": ["aria-roledescription"],
"none": []
}
83 changes: 83 additions & 0 deletions test/checks/aria/aria-roledescription.js
@@ -0,0 +1,83 @@
describe('aria-roledescription', function() {
'use strict';

var fixture = document.getElementById('fixture');
var checkContext = axe.testUtils.MockCheckContext();

afterEach(function() {
fixture.innerHTML = '';
checkContext.reset();
});

it('returns true for elements with an implicit supported role', function() {
fixture.innerHTML =
'<button aria-roledescription="Awesome Button">Click</button>';
var actual = checks['aria-roledescription'].evaluate.call(
checkContext,
fixture.firstChild,
{
supportedRoles: ['button']
}
);
assert.equal(actual, true);
assert.isNull(checkContext._data, null);
});

it('returns true for elements with an explicit supported role', function() {
fixture.innerHTML =
'<div role="radio" aria-roledescription="Awesome Radio">Click</div>';
var actual = checks['aria-roledescription'].evaluate.call(
checkContext,
fixture.firstChild,
{
supportedRoles: ['radio']
}
);
assert.equal(actual, true);
assert.isNull(checkContext._data, null);
});

it('returns undefined for elements with an unsupported role', function() {
fixture.innerHTML =
'<div role="main" aria-roledescription="Awesome Main">The main element</div>';
var actual = checks['aria-roledescription'].evaluate.call(
checkContext,
fixture.firstChild
);
assert.equal(actual, undefined);
assert.isNull(checkContext._data, null);
});

it('returns false for elements without role', function() {
fixture.innerHTML =
'<div aria-roledescription="Awesome Main">The main element</div>';
var actual = checks['aria-roledescription'].evaluate.call(
checkContext,
fixture.firstChild
);
assert.equal(actual, false);
assert.isNull(checkContext._data, null);
});

it('returns false for elements with role=presentation', function() {
fixture.innerHTML =
'<div role="presentation" aria-roledescription="Awesome Main">The main element</div>';
var actual = checks['aria-roledescription'].evaluate.call(
checkContext,
fixture.firstChild
);
assert.equal(actual, false);
assert.isNull(checkContext._data, null);
});

it('returns false for elements with role=none', function() {
fixture.innerHTML =
'<div role="none" aria-roledescription="Awesome Main">The main element</div>';
var actual = checks['aria-roledescription'].evaluate.call(
checkContext,
fixture.firstChild
);
assert.equal(actual, false);
assert.isNull(checkContext._data, null);
});
});
6 changes: 0 additions & 6 deletions test/integration/rules/aria-allowed-attr/failures.html
Expand Up @@ -6,9 +6,3 @@
<!-- unsupported attributes -->
<div aria-describedat="#fail4" id="fail5">fail</div>
<div aria-details="fail5" id="fail6">fail</div>
<div aria-roledescription="Slide" id="fail7">fail</div>
<p id="fail8" aria-roledescription="status">
warning: things are a wee bit bit slow
</p>
<input id="fail9" type="text" aria-roledescription="input" />
<textarea id="fail10" type="text" aria-roledescription="comments"></textarea>
6 changes: 1 addition & 5 deletions test/integration/rules/aria-allowed-attr/failures.json
Expand Up @@ -7,10 +7,6 @@
["#fail3"],
["#fail4"],
["#fail5"],
["#fail6"],
["#fail7"],
["#fail8"],
["#fail9"],
["#fail10"]
["#fail6"]
]
}
@@ -0,0 +1,29 @@
<button aria-roledescription="my button" id="pass1">button</button>
<img aria-roledescription="my img" src="foo.png" id="pass2" />
<div role="checkbox" aria-roledescription="my checkbox" id="pass3"></div>
<div role="radio" aria-roledescription="my radio" id="pass4"></div>
<div role="combobox" aria-roledescription="my combobox" id="pass5"></div>
<div
role="menuitemcheckbox"
aria-roledescription="my menuitemcheckbox"
id="pass6"
></div>
<div
role="menuitemradio"
aria-roledescription="my menuitemradio"
id="pass7"
></div>
<input type="checkbox" aria-roledescription="my checkbox" id="pass8" />
<input type="radio" aria-roledescription="my radio" id="pass9" />

<h1 aria-roledescription="my heading" id="incomplete1">heading</h1>
<div role="rowgroup" aria-roledescription="my row" id="incomplete2"></div>

<p aria-roledescription="my paragraph" id="fail1">paragraph</p>
<div aria-roledescription="my div" id="fail2">div</div>
<div
role="presentation"
aria-roledescription="my presentation"
id="fail3"
></div>
<div role="none" aria-roledescription="my none" id="fail4"></div>
@@ -0,0 +1,17 @@
{
"description": "aria-roledescription test",
"rule": "aria-roledescription",
"violations": [["#fail1"], ["#fail2"], ["#fail3"], ["#fail4"]],
"passes": [
["#pass1"],
["#pass2"],
["#pass3"],
["#pass4"],
["#pass5"],
["#pass6"],
["#pass7"],
["#pass8"],
["#pass9"]
],
"incomplete": [["#incomplete1"], ["#incomplete2"]]
}

0 comments on commit 16682fd

Please sign in to comment.