Skip to content

Commit

Permalink
fix(aria-allowed-attr): allow aria-multiline=false for element with c…
Browse files Browse the repository at this point in the history
…ontenteditable (#4537)

Closes: #4463
  • Loading branch information
straker authored Jul 11, 2024
1 parent 2e242e1 commit f019068
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 5 deletions.
20 changes: 17 additions & 3 deletions lib/checks/aria/aria-allowed-attr-evaluate.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export default function ariaAllowedAttrEvaluate(node, options, virtualNode) {
if (
validateAttr(attrName) &&
!allowed.includes(attrName) &&
!ignoredAttrs(attrName, virtualNode.attr(attrName))
!ignoredAttrs(attrName, virtualNode.attr(attrName), virtualNode)
) {
invalid.push(attrName);
}
Expand All @@ -62,8 +62,22 @@ export default function ariaAllowedAttrEvaluate(node, options, virtualNode) {
return false;
}

function ignoredAttrs(attrName, attrValue) {
function ignoredAttrs(attrName, attrValue, vNode) {
// allow aria-required=false as screen readers consistently ignore it
// @see https://github.com/dequelabs/axe-core/issues/3756
return attrName === 'aria-required' && attrValue === 'false';
if (attrName === 'aria-required' && attrValue === 'false') {
return true;
}

// allow aria-multiline=false when contenteditable is set
// @see https://github.com/dequelabs/axe-core/issues/4463
if (
attrName === 'aria-multiline' &&
attrValue === 'false' &&
vNode.hasAttr('contenteditable')
) {
return true;
}

return false;
}
50 changes: 50 additions & 0 deletions test/checks/aria/aria-allowed-attr.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,56 @@ describe('aria-allowed-attr', () => {
assert.deepEqual(checkContext._data, ['aria-required="true"']);
});

it('should not report on aria-multiline=false with contenteditable', () => {
const vNode = queryFixture(
'<div id="target" role="combobox" aria-multiline="false" contenteditable></div>'
);

assert.isTrue(
axe.testUtils
.getCheckEvaluate('aria-allowed-attr')
.call(checkContext, null, null, vNode)
);
assert.isNull(checkContext._data);
});

it('should return false for unallowed aria-multiline=true and contenteditable', () => {
const vNode = queryFixture(
'<div id="target" role="combobox" aria-multiline="true" contenteditable></div>'
);

assert.isFalse(
axe.testUtils
.getCheckEvaluate('aria-allowed-attr')
.call(checkContext, null, null, vNode)
);
assert.deepEqual(checkContext._data, ['aria-multiline="true"']);
});

it('should return false for unallowed aria-multiline=false', () => {
const vNode = queryFixture(
'<div id="target" role="combobox" aria-multiline="false"></div>'
);

assert.isFalse(
axe.testUtils
.getCheckEvaluate('aria-allowed-attr')
.call(checkContext, null, null, vNode)
);
assert.deepEqual(checkContext._data, ['aria-multiline="false"']);
});

it('should return false for unallowed aria-multiline=true', () => {
const vNode = queryFixture('<div id="target" aria-multiline="true"></div>');

assert.isFalse(
axe.testUtils
.getCheckEvaluate('aria-allowed-attr')
.call(checkContext, null, null, vNode)
);
assert.deepEqual(checkContext._data, ['aria-multiline="true"']);
});

it('should return undefined for custom element that has no role and is not focusable', () => {
const vNode = queryFixture(
'<my-custom-element id="target" aria-expanded="true"></my-custom-element>'
Expand Down
4 changes: 4 additions & 0 deletions test/integration/rules/aria-allowed-attr/failures.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@
aria-orientation="horizontal"
id="fail5"
></audio>

<div id="fail6" role="combobox" aria-multiline="false"></div>
<div id="fail7" role="combobox" aria-multiline="true" contenteditable></div>
<div id="fail8" role="combobox" aria-multiline="true"></div>
11 changes: 10 additions & 1 deletion test/integration/rules/aria-allowed-attr/failures.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
{
"description": "aria-allowed-attr failing tests",
"rule": "aria-allowed-attr",
"violations": [["#fail1"], ["#fail2"], ["#fail3"], ["#fail4"], ["#fail5"]]
"violations": [
["#fail1"],
["#fail2"],
["#fail3"],
["#fail4"],
["#fail5"],
["#fail6"],
["#fail7"],
["#fail8"]
]
}
1 change: 1 addition & 0 deletions test/integration/rules/aria-allowed-attr/passes.html
Original file line number Diff line number Diff line change
Expand Up @@ -2172,3 +2172,4 @@

<!-- Ignored ARIA attributes -->
<button id="pass101" aria-required="false"></button>
<div id="pass102" role="combobox" aria-multiline="false" contenteditable></div>
3 changes: 2 additions & 1 deletion test/integration/rules/aria-allowed-attr/passes.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
["#pass98"],
["#pass99"],
["#pass100"],
["#pass101"]
["#pass101"],
["#pass102"]
]
}

0 comments on commit f019068

Please sign in to comment.