diff --git a/lib/checks/aria/aria-prohibited-attr-evaluate.js b/lib/checks/aria/aria-prohibited-attr-evaluate.js
index e6e2f9da7d..03bbc0cb14 100644
--- a/lib/checks/aria/aria-prohibited-attr-evaluate.js
+++ b/lib/checks/aria/aria-prohibited-attr-evaluate.js
@@ -33,7 +33,11 @@ export default function ariaProhibitedAttrEvaluate(
) {
const elementsAllowedAriaLabel = options?.elementsAllowedAriaLabel || [];
const { nodeName } = virtualNode.props;
- const role = getRole(virtualNode, { chromium: true });
+ const role = getRole(virtualNode, {
+ chromium: true,
+ // this check allows fallback roles. For example, `
` is legal.
+ fallback: true
+ });
const prohibitedList = listProhibitedAttrs(
role,
@@ -51,7 +55,7 @@ export default function ariaProhibitedAttrEvaluate(
return false;
}
- let messageKey = virtualNode.hasAttr('role') ? 'hasRole' : 'noRole';
+ let messageKey = role !== null ? 'hasRole' : 'noRole';
messageKey += prohibited.length > 1 ? 'Plural' : 'Singular';
this.data({ role, nodeName, messageKey, prohibited });
diff --git a/test/checks/aria/aria-prohibited-attr.js b/test/checks/aria/aria-prohibited-attr.js
index 4ae70f6bb0..116f31fc0d 100644
--- a/test/checks/aria/aria-prohibited-attr.js
+++ b/test/checks/aria/aria-prohibited-attr.js
@@ -138,4 +138,37 @@ describe('aria-prohibited-attr', function () {
var params = checkSetup('
');
assert.isFalse(checkEvaluate.apply(checkContext, params));
});
+
+ it('should not allow aria-label on divs that have an invalid role', function () {
+ var params = checkSetup(
+ '
'
+ );
+ assert.isTrue(checkEvaluate.apply(checkContext, params));
+ assert.deepEqual(checkContext._data, {
+ nodeName: 'div',
+ role: null,
+ messageKey: 'noRoleSingular',
+ prohibited: ['aria-label']
+ });
+ });
+
+ it('should allow aria-label on divs with a valid fallback role', function () {
+ var params = checkSetup(
+ '
'
+ );
+ assert.isFalse(checkEvaluate.apply(checkContext, params));
+ });
+
+ it('should not allow aria-label on divs with no valid fallback roles', function () {
+ var params = checkSetup(
+ '
'
+ );
+ assert.isTrue(checkEvaluate.apply(checkContext, params));
+ assert.deepEqual(checkContext._data, {
+ nodeName: 'div',
+ role: null,
+ messageKey: 'noRoleSingular',
+ prohibited: ['aria-label']
+ });
+ });
});
diff --git a/test/integration/rules/aria-prohibited-attr/aria-prohibited-attr.html b/test/integration/rules/aria-prohibited-attr/aria-prohibited-attr.html
index ec354260a3..3be7f40ea3 100644
--- a/test/integration/rules/aria-prohibited-attr/aria-prohibited-attr.html
+++ b/test/integration/rules/aria-prohibited-attr/aria-prohibited-attr.html
@@ -3,6 +3,7 @@
Foo
+
@@ -35,6 +36,8 @@
+
+
Foo
Foo
diff --git a/test/integration/rules/aria-prohibited-attr/aria-prohibited-attr.json b/test/integration/rules/aria-prohibited-attr/aria-prohibited-attr.json
index f6f9e7717b..9ac7375cbe 100644
--- a/test/integration/rules/aria-prohibited-attr/aria-prohibited-attr.json
+++ b/test/integration/rules/aria-prohibited-attr/aria-prohibited-attr.json
@@ -1,7 +1,14 @@
{
"description": "aria-prohibited-attr tests",
"rule": "aria-prohibited-attr",
- "passes": [["#pass1"], ["#pass2"], ["#pass3"], ["#pass4"], ["#pass5"]],
+ "passes": [
+ ["#pass1"],
+ ["#pass2"],
+ ["#pass3"],
+ ["#pass4"],
+ ["#pass5"],
+ ["#pass6"]
+ ],
"incomplete": [["#incomplete1"], ["#incomplete2"], ["#incomplete3"]],
"violations": [
["#fail1"],
@@ -32,6 +39,8 @@
["#fail26"],
["#fail27"],
["#fail28"],
- ["#fail29"]
+ ["#fail29"],
+ ["#fail30"],
+ ["#fail31"]
]
}
diff --git a/test/integration/virtual-rules/aria-prohibited-attr.js b/test/integration/virtual-rules/aria-prohibited-attr.js
index ccacf57b33..4f7fa95891 100644
--- a/test/integration/virtual-rules/aria-prohibited-attr.js
+++ b/test/integration/virtual-rules/aria-prohibited-attr.js
@@ -58,4 +58,52 @@ describe('aria-prohibited-attr virtual-rule', () => {
assert.lengthOf(results.violations, 1);
assert.lengthOf(results.incomplete, 0);
});
+
+ it('should fail for invalid role', () => {
+ const vNode = new axe.SerialVirtualNode({
+ nodeName: 'div',
+ attributes: {
+ role: 'foo',
+ 'aria-label': 'foo'
+ }
+ });
+ vNode.children = [];
+
+ const results = axe.runVirtualRule('aria-prohibited-attr', vNode);
+
+ assert.lengthOf(results.passes, 0);
+ assert.lengthOf(results.violations, 1);
+ assert.lengthOf(results.incomplete, 0);
+ });
+
+ it('should pass for fallback roles', () => {
+ const results = axe.runVirtualRule('aria-prohibited-attr', {
+ nodeName: 'div',
+ attributes: {
+ role: 'foo dialog',
+ 'aria-label': 'foo'
+ }
+ });
+
+ assert.lengthOf(results.passes, 1);
+ assert.lengthOf(results.violations, 0);
+ assert.lengthOf(results.incomplete, 0);
+ });
+
+ it('should fail for multiple invalid roles', () => {
+ const vNode = new axe.SerialVirtualNode({
+ nodeName: 'div',
+ attributes: {
+ role: 'foo bar',
+ 'aria-label': 'foo'
+ }
+ });
+ vNode.children = [];
+
+ const results = axe.runVirtualRule('aria-prohibited-attr', vNode);
+
+ assert.lengthOf(results.passes, 0);
+ assert.lengthOf(results.violations, 1);
+ assert.lengthOf(results.incomplete, 0);
+ });
});