diff --git a/lib/checks/aria/aria-allowed-role.js b/lib/checks/aria/aria-allowed-role.js
index e221ef34c1..21cae12ca5 100644
--- a/lib/checks/aria/aria-allowed-role.js
+++ b/lib/checks/aria/aria-allowed-role.js
@@ -3,6 +3,7 @@
* https://www.w3.org/TR/html-aria/#docconformance
* https://www.w3.org/TR/SVG2/struct.html#implicit-aria-semantics
*/
+const { dom } = axe.commons;
const { allowImplicit = true, ignoredTags = [] } = options || {};
const tagName = node.nodeName.toUpperCase();
@@ -18,6 +19,10 @@ const unallowedRoles = axe.commons.aria.getElementUnallowedRoles(
if (unallowedRoles.length) {
this.data(unallowedRoles);
+ if (!dom.isVisible(node, true)) {
+ // flag hidden elements for review
+ return undefined;
+ }
return false;
}
return true;
diff --git a/lib/checks/aria/aria-allowed-role.json b/lib/checks/aria/aria-allowed-role.json
index f0a09782dd..15ac20dfd3 100644
--- a/lib/checks/aria/aria-allowed-role.json
+++ b/lib/checks/aria/aria-allowed-role.json
@@ -9,7 +9,8 @@
"impact": "minor",
"messages": {
"pass": "ARIA role is allowed for given element",
- "fail": "role{{=it.data && it.data.length > 1 ? 's' : ''}} {{=it.data.join(', ')}} {{=it.data && it.data.length > 1 ? 'are' : ' is'}} not allowed for given element"
+ "fail": "ARIA role{{=it.data && it.data.length > 1 ? 's' : ''}} {{=it.data.join(', ')}} {{=it.data && it.data.length > 1 ? 'are' : ' is'}} not allowed for given element",
+ "incomplete": "ARIA role{{=it.data && it.data.length > 1 ? 's' : ''}} {{=it.data.join(', ')}} must be removed when the element is made visible, as {{=it.data && it.data.length > 1 ? 'they are' : 'it is'}} not allowed for the element"
}
}
-}
\ No newline at end of file
+}
diff --git a/test/checks/aria/aria-allowed-role.js b/test/checks/aria/aria-allowed-role.js
index d3a56ef325..9f0736704a 100644
--- a/test/checks/aria/aria-allowed-role.js
+++ b/test/checks/aria/aria-allowed-role.js
@@ -12,6 +12,7 @@ describe('aria-allowed-role', function() {
it('returns true if given element is an ignoredTag in options', function() {
var node = document.createElement('article');
node.setAttribute('role', 'presentation');
+ fixture.appendChild(node);
var options = {
ignoredTags: ['article']
};
@@ -26,16 +27,15 @@ describe('aria-allowed-role', function() {
});
it('returns false with implicit role of row for TR when allowImplicit is set to false via options', function() {
- var node = document.createElement('table');
- node.setAttribute('role', 'grid');
- var row = document.createElement('tr');
- row.setAttribute('role', 'row');
+ fixture.innerHTML =
+ '
';
+ var target = fixture.querySelector('#target');
var options = {
allowImplicit: false
};
var actual = checks['aria-allowed-role'].evaluate.call(
checkContext,
- row,
+ target,
options
);
var expected = false;
@@ -51,6 +51,32 @@ describe('aria-allowed-role', function() {
);
});
+ it('returns undefined (needs review) when element is hidden and has unallowed role', function() {
+ fixture.innerHTML =
+ '';
+ var target = fixture.querySelector('#target');
+ var actual = checks['aria-allowed-role'].evaluate.call(
+ checkContext,
+ target
+ );
+ assert.isUndefined(actual);
+ });
+
+ it('returns undefined (needs review) when element is with in hidden parent and has unallowed role', function() {
+ fixture.innerHTML =
+ '
' +
+ '' +
+ '
';
+ var target = fixture.querySelector('#target');
+ var actual = checks['aria-allowed-role'].evaluate.call(
+ checkContext,
+ target
+ );
+ assert.isUndefined(actual);
+ });
+
it('returns true when BUTTON has type menu and role as menuitem', function() {
var node = document.createElement('button');
node.setAttribute('type', 'menu');
diff --git a/test/integration/rules/aria-allowed-role/aria-allowed-role.html b/test/integration/rules/aria-allowed-role/aria-allowed-role.html
index b27daccdfb..e4acd11792 100644
--- a/test/integration/rules/aria-allowed-role/aria-allowed-role.html
+++ b/test/integration/rules/aria-allowed-role/aria-allowed-role.html
@@ -55,3 +55,8 @@
+