Skip to content

Commit

Permalink
feat: ARIA supported checks (#1254)
Browse files Browse the repository at this point in the history
This branch adds a new check to report unsupported ARIA attributes to the user. We have to make a decision on how to modify the rule to support it, which you can find discussed in #918.

Closes issue: #918

## Reviewer checks

**Required fields, to be filled out by PR reviewer(s)**
- [x] Follows the commit message policy, appropriate for next version
- [x] Has documentation updated, a DU ticket, or requires no documentation change
- [x] Includes new tests, or was unnecessary
- [x] Code is reviewed for security by: @WilcoFiers
  • Loading branch information
marcysutton authored and WilcoFiers committed Dec 14, 2018
1 parent 09a08c2 commit 51a18a8
Show file tree
Hide file tree
Showing 15 changed files with 292 additions and 186 deletions.
2 changes: 1 addition & 1 deletion doc/aria-supported.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ For a detailed description about how accessibility support is decided, see [How
| -------------------- | ---------------- |
| aria-describedat | No |
| aria-details | No |
| aria-roledescription | No |
| aria-roledescription | No |
154 changes: 77 additions & 77 deletions doc/rule-descriptions.md

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions lib/checks/aria/unsupportedattr.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
let unsupported = Array.from(node.attributes)
.filter(candidate => {
// filter out unsupported attributes
return axe.commons.aria.validateAttr(candidate.name, {
flagUnsupported: true
});
})
.map(candidate => {
return candidate.name.toString();
});

if (unsupported.length) {
this.data(unsupported);
return true;
}
return false;
11 changes: 11 additions & 0 deletions lib/checks/aria/unsupportedattr.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"id": "aria-unsupported-attr",
"evaluate": "unsupportedattr.js",
"metadata": {
"impact": "critical",
"messages": {
"pass": "ARIA attribute is supported",
"fail": "ARIA attribute is not widely supported in screen readers and assistive technologies: {{~it.data:value}} {{=value}}{{~}}"
}
}
}
2 changes: 1 addition & 1 deletion lib/checks/aria/unsupportedrole.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"impact": "critical",
"messages": {
"pass": "ARIA role is supported",
"fail": "The role used is not widely supported in assistive technologies"
"fail": "The role used is not widely supported in screen readers and assistive technologies: {{~it.data:value}} {{=value}}{{~}}"
}
}
}
12 changes: 7 additions & 5 deletions lib/commons/aria/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
* @return {Array}
*/
aria.requiredAttr = function(role) {
'use strict';
var roles = aria.lookupTable.role[role],
attr = roles && roles.attributes && roles.attributes.required;
return attr || [];
Expand All @@ -24,7 +23,6 @@ aria.requiredAttr = function(role) {
* @return {Array}
*/
aria.allowedAttr = function(role) {
'use strict';
var roles = aria.lookupTable.role[role],
attr = (roles && roles.attributes && roles.attributes.allowed) || [],
requiredAttr =
Expand All @@ -39,9 +37,13 @@ aria.allowedAttr = function(role) {
* @memberof axe.commons.aria
* @instance
* @param {String} att The attribute name
* @param {Object} options Use `flagUnsupported: true` to report unsupported attributes
* @return {Boolean}
*/
aria.validateAttr = function(att) {
'use strict';
return !!aria.lookupTable.attributes[att];
aria.validateAttr = function(att, { flagUnsupported = false } = {}) {
const attrDefinition = aria.lookupTable.attributes[att];
if (flagUnsupported && attrDefinition) {
return !!attrDefinition.unsupported;
}
return !!attrDefinition;
};
148 changes: 102 additions & 46 deletions lib/commons/aria/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,177 +10,233 @@ var aria = (commons.aria = {}),
lookupTable.attributes = {
'aria-activedescendant': {
type: 'idref',
allowEmpty: true
allowEmpty: true,
unsupported: false
},
'aria-atomic': {
type: 'boolean',
values: ['true', 'false']
values: ['true', 'false'],
unsupported: false
},
'aria-autocomplete': {
type: 'nmtoken',
values: ['inline', 'list', 'both', 'none']
values: ['inline', 'list', 'both', 'none'],
unsupported: false
},
'aria-busy': {
type: 'boolean',
values: ['true', 'false']
values: ['true', 'false'],
unsupported: false
},
'aria-checked': {
type: 'nmtoken',
values: ['true', 'false', 'mixed', 'undefined']
values: ['true', 'false', 'mixed', 'undefined'],
unsupported: false
},
'aria-colcount': {
type: 'int'
type: 'int',
unsupported: false
},
'aria-colindex': {
type: 'int'
type: 'int',
unsupported: false
},
'aria-colspan': {
type: 'int'
type: 'int',
unsupported: false
},
'aria-controls': {
type: 'idrefs',
allowEmpty: true
allowEmpty: true,
unsupported: false
},
'aria-current': {
type: 'nmtoken',
allowEmpty: true,
values: ['page', 'step', 'location', 'date', 'time', 'true', 'false']
values: ['page', 'step', 'location', 'date', 'time', 'true', 'false'],
unsupported: false
},
'aria-describedby': {
type: 'idrefs',
allowEmpty: true
allowEmpty: true,
unsupported: false
},
'aria-describedat': {
unsupported: true,
unstandardized: true
},
'aria-details': {
unsupported: true
},
'aria-disabled': {
type: 'boolean',
values: ['true', 'false']
values: ['true', 'false'],
unsupported: false
},
'aria-dropeffect': {
type: 'nmtokens',
values: ['copy', 'move', 'reference', 'execute', 'popup', 'none']
values: ['copy', 'move', 'reference', 'execute', 'popup', 'none'],
unsupported: false
},
'aria-errormessage': {
type: 'idref',
allowEmpty: true
allowEmpty: true,
unsupported: false
},
'aria-expanded': {
type: 'nmtoken',
values: ['true', 'false', 'undefined']
values: ['true', 'false', 'undefined'],
unsupported: false
},
'aria-flowto': {
type: 'idrefs',
allowEmpty: true
allowEmpty: true,
unsupported: false
},
'aria-grabbed': {
type: 'nmtoken',
values: ['true', 'false', 'undefined']
values: ['true', 'false', 'undefined'],
unsupported: false
},
'aria-haspopup': {
type: 'nmtoken',
allowEmpty: true,
values: ['true', 'false', 'menu', 'listbox', 'tree', 'grid', 'dialog']
values: ['true', 'false', 'menu', 'listbox', 'tree', 'grid', 'dialog'],
unsupported: false
},
'aria-hidden': {
type: 'boolean',
values: ['true', 'false']
values: ['true', 'false'],
unsupported: false
},
'aria-invalid': {
type: 'nmtoken',
allowEmpty: true,
values: ['true', 'false', 'spelling', 'grammar']
values: ['true', 'false', 'spelling', 'grammar'],
unsupported: false
},
'aria-keyshortcuts': {
type: 'string',
allowEmpty: true
allowEmpty: true,
unsupported: false
},
'aria-label': {
type: 'string',
allowEmpty: true
allowEmpty: true,
unsupported: false
},
'aria-labelledby': {
type: 'idrefs',
allowEmpty: true
allowEmpty: true,
unsupported: false
},
'aria-level': {
type: 'int'
type: 'int',
unsupported: false
},
'aria-live': {
type: 'nmtoken',
values: ['off', 'polite', 'assertive']
values: ['off', 'polite', 'assertive'],
unsupported: false
},
'aria-modal': {
type: 'boolean',
values: ['true', 'false']
values: ['true', 'false'],
unsupported: false
},
'aria-multiline': {
type: 'boolean',
values: ['true', 'false']
values: ['true', 'false'],
unsupported: false
},
'aria-multiselectable': {
type: 'boolean',
values: ['true', 'false']
values: ['true', 'false'],
unsupported: false
},
'aria-orientation': {
type: 'nmtoken',
values: ['horizontal', 'vertical']
values: ['horizontal', 'vertical'],
unsupported: false
},
'aria-owns': {
type: 'idrefs',
allowEmpty: true
allowEmpty: true,
unsupported: false
},
'aria-placeholder': {
type: 'string',
allowEmpty: true
allowEmpty: true,
unsupported: false
},
'aria-posinset': {
type: 'int'
type: 'int',
unsupported: false
},
'aria-pressed': {
type: 'nmtoken',
values: ['true', 'false', 'mixed', 'undefined']
values: ['true', 'false', 'mixed', 'undefined'],
unsupported: false
},
'aria-readonly': {
type: 'boolean',
values: ['true', 'false']
values: ['true', 'false'],
unsupported: false
},
'aria-relevant': {
type: 'nmtokens',
values: ['additions', 'removals', 'text', 'all']
values: ['additions', 'removals', 'text', 'all'],
unsupported: false
},
'aria-required': {
type: 'boolean',
values: ['true', 'false']
values: ['true', 'false'],
unsupported: false
},
'aria-roledescription': {
unsupported: true
},
'aria-rowcount': {
type: 'int'
type: 'int',
unsupported: false
},
'aria-rowindex': {
type: 'int'
type: 'int',
unsupported: false
},
'aria-rowspan': {
type: 'int'
type: 'int',
unsupported: false
},
'aria-selected': {
type: 'nmtoken',
values: ['true', 'false', 'undefined']
values: ['true', 'false', 'undefined'],
unsupported: false
},
'aria-setsize': {
type: 'int'
type: 'int',
unsupported: false
},
'aria-sort': {
type: 'nmtoken',
values: ['ascending', 'descending', 'other', 'none']
values: ['ascending', 'descending', 'other', 'none'],
unsupported: false
},
'aria-valuemax': {
type: 'decimal'
type: 'decimal',
unsupported: false
},
'aria-valuemin': {
type: 'decimal'
type: 'decimal',
unsupported: false
},
'aria-valuenow': {
type: 'decimal'
type: 'decimal',
unsupported: false
},
'aria-valuetext': {
type: 'string'
type: 'string',
unsupported: false
}
};

Expand Down
19 changes: 6 additions & 13 deletions lib/rules/aria-allowed-attr-matches.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
var role = node.getAttribute('role');
if (!role) {
role = axe.commons.aria.implicitRole(node);
}
var allowed = axe.commons.aria.allowedAttr(role);
if (role && allowed) {
var aria = /^aria-/;
if (node.hasAttributes()) {
var attrs = node.attributes;
for (var i = 0, l = attrs.length; i < l; i++) {
if (aria.test(attrs[i].name)) {
return true;
}
const aria = /^aria-/;
if (node.hasAttributes()) {
let attrs = node.attributes;
for (let i = 0, l = attrs.length; i < l; i++) {
if (aria.test(attrs[i].name)) {
return true;
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/aria-allowed-attr.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
},
"all": [],
"any": ["aria-allowed-attr"],
"none": []
"none": ["aria-unsupported-attr"]
}
Loading

0 comments on commit 51a18a8

Please sign in to comment.