Skip to content

Commit

Permalink
fix(aria-errormessage): adds support for aria-errormessage (#517)
Browse files Browse the repository at this point in the history
* fix(aria-errormessage): adds support for aria-errormessage

* fix(aria-valid-attr-value): switches from `any` mode to `all`
  • Loading branch information
AutoSponge authored and marcysutton committed Oct 25, 2017
1 parent 6b81a50 commit c96f58c
Show file tree
Hide file tree
Showing 9 changed files with 110 additions and 10 deletions.
25 changes: 25 additions & 0 deletions lib/checks/aria/errormessage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
options = Array.isArray(options) ? options : [];

var attr = node.getAttribute('aria-errormessage'),
hasAttr = node.hasAttribute('aria-errormessage');

var doc = axe.commons.dom.getRootNode(node);

function validateAttrValue() {
var idref = attr && doc.getElementById(attr);
if (idref) {
return idref.getAttribute('role') === 'alert' ||
idref.getAttribute('aria-live') === 'assertive' ||
axe.utils.tokenList(node.getAttribute('aria-describedby') || '').indexOf(attr) > -1;
}
}

// limit results to elements that actually have this attribute
if (options.indexOf(attr) === -1 && hasAttr) {
if (!validateAttrValue()) {
this.data(attr);
return false;
}
}

return true;
11 changes: 11 additions & 0 deletions lib/checks/aria/errormessage.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"id": "aria-errormessage",
"evaluate": "errormessage.js",
"metadata": {
"impact": "critical",
"messages": {
"pass": "Uses a supported aria-errormessage technique",
"fail": "aria-errormessage value{{=it.data && it.data.length > 1 ? 's' : ''}} {{~it.data:value}} `{{=value}}{{~}}` must use a technique to announce the message (e.g., aria-live, aria-describedby, role=alert, etc.)"
}
}
}
11 changes: 8 additions & 3 deletions lib/checks/aria/valid-attr-value.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,18 @@ var invalid = [],
var attr, attrName,
attrs = node.attributes;

var skipAttrs = ['aria-errormessage'];

for (var i = 0, l = attrs.length; i < l; i++) {
attr = attrs[i];
attrName = attr.name;
if (options.indexOf(attrName) === -1 && aria.test(attrName) &&
!axe.commons.aria.validateAttrValue(node, attrName)) {
// skip any attributes handled elsewhere
if (!skipAttrs.includes(attrName)) {
if (options.indexOf(attrName) === -1 && aria.test(attrName) &&
!axe.commons.aria.validateAttrValue(node, attrName)) {

invalid.push(attrName + '="' + attr.nodeValue + '"');
invalid.push(attrName + '="' + attr.nodeValue + '"');
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions lib/commons/aria/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ lookupTables.attributes = {
type: 'nmtokens',
values: ['copy', 'move', 'reference', 'execute', 'popup', 'none']
},
'aria-errormessage': {
type: 'idref'
},
'aria-expanded': {
type: 'nmtoken',
values: ['true', 'false', 'undefined']
Expand Down
7 changes: 4 additions & 3 deletions lib/rules/aria-valid-attr-value.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@
"description": "Ensures all ARIA attributes have valid values",
"help": "ARIA attributes must conform to valid values"
},
"all": [],
"any": [
"aria-valid-attr-value"
"all": [
"aria-valid-attr-value",
"aria-errormessage"
],
"any": [],
"none": []
}
49 changes: 49 additions & 0 deletions test/checks/aria/errormessage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
describe('aria-errormessage', function () {
'use strict';

var fixture = document.getElementById('fixture');

var checkContext = axe.testUtils.MockCheckContext();

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

it('should return false if aria-errormessage value is invalid', function () {
var testHTML = '<div></div>';
testHTML += '<div id="plain"></div>';
fixture.innerHTML = testHTML;
var target = fixture.children[0];
target.setAttribute('aria-errormessage', 'plain');
assert.isFalse(checks['aria-errormessage'].evaluate.call(checkContext, target));
});

it('should return true if aria-errormessage id is alert', function () {
var testHTML = '<div></div>';
testHTML += '<div id="alert" role="alert"></div>';
fixture.innerHTML = testHTML;
var target = fixture.children[0];
target.setAttribute('aria-errormessage', 'alert');
assert.isTrue(checks['aria-errormessage'].evaluate.call(checkContext, target));
});

it('should return true if aria-errormessage id is aria-live=assertive', function () {
var testHTML = '<div></div>';
testHTML += '<div id="live" aria-live="assertive"></div>';
fixture.innerHTML = testHTML;
var target = fixture.children[0];
target.setAttribute('aria-errormessage', 'live');
assert.isTrue(checks['aria-errormessage'].evaluate.call(checkContext, target));
});

it('should return true if aria-errormessage id is aria-describedby', function () {
var testHTML = '<div></div>';
testHTML += '<div id="plain"></div>';
fixture.innerHTML = testHTML;
var target = fixture.children[0];
target.setAttribute('aria-errormessage', 'plain');
target.setAttribute('aria-describedby', 'plain');
assert.isTrue(checks['aria-errormessage'].evaluate.call(checkContext, target));
});
});
4 changes: 2 additions & 2 deletions test/integration/rules/aria-allowed-attr/passes.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@
["#pass43"], ["#pass44"], ["#pass45"], ["#pass46"], ["#pass47"], ["#pass48"], ["#pass49"],
["#pass50"], ["#pass51"], ["#pass52"], ["#pass53"], ["#pass54"], ["#pass55"], ["#pass56"],
["#pass57"], ["#pass58"], ["#pass59"], ["#pass60"], ["#pass61"], ["#pass62"], ["#pass63"],
["#pass64"], ["#pass65"], ["#pass66"], ["#pass67"], ["#pass68"]
["#pass64"], ["#pass65"], ["#pass66"], ["#pass67"], ["#pass68"]
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ <h2>Violations</h2>
<div aria-valuemax="stuff" id="violation32">hi</div>
<div aria-valuemin="stuff" id="violation33">hi</div>
<div aria-valuenow="stuff" id="violation34">hi</div>
<div aria-errormessage="violation35-ref" id="violation35">hi</div><div id="violation35-ref"></div>
</div>
<h2>Possible False Positives</h2>
<div>
Expand Down Expand Up @@ -245,6 +246,10 @@ <h2>Possible False Positives</h2>
<div aria-valuenow="-.1" id="pass165">hi</div>
<div aria-valuenow="-412" id="pass166">hi</div>
<div aria-valuetext="stuff" id="pass167">hi</div>
<div aria-errormessage="pass168-ref" id="pass168">hi</div><div id="pass168-ref" role="alert"></div>
<div aria-errormessage="pass68" id="pass169">hi</div>
<div aria-errormessage="ref" aria-describedby="ref" id="pass170">hi</div>


<div id="ref">Hi</div>
<div id="ref2">Hi2</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
["#violation12"], ["#violation13"], ["#violation14"], ["#violation15"], ["#violation16"], ["#violation17"],
["#violation18"], ["#violation19"], ["#violation20"], ["#violation21"], ["#violation22"], ["#violation23"],
["#violation24"], ["#violation25"], ["#violation26"], ["#violation27"], ["#violation28"], ["#violation29"],
["#violation30"], ["#violation31"], ["#violation32"], ["#violation33"], ["#violation34"]
["#violation30"], ["#violation31"], ["#violation32"], ["#violation33"], ["#violation34"],["#violation35"]
],
"passes": [
["#pass1"], ["#pass2"], ["#pass3"], ["#pass4"], ["#pass5"], ["#pass6"], ["#pass7"], ["#pass8"], ["#pass9"],
Expand All @@ -31,6 +31,7 @@
["#pass140"], ["#pass141"], ["#pass142"], ["#pass143"], ["#pass144"], ["#pass145"], ["#pass146"],
["#pass147"], ["#pass148"], ["#pass149"], ["#pass150"], ["#pass151"], ["#pass152"], ["#pass153"],
["#pass154"], ["#pass155"], ["#pass156"], ["#pass157"], ["#pass158"], ["#pass159"], ["#pass160"],
["#pass161"], ["#pass162"], ["#pass163"], ["#pass164"], ["#pass165"], ["#pass166"], ["#pass167"]
["#pass161"], ["#pass162"], ["#pass163"], ["#pass164"], ["#pass165"], ["#pass166"], ["#pass167"],
["#pass168"], ["#pass169"], ["#pass170"]
]
}

0 comments on commit c96f58c

Please sign in to comment.