Skip to content

Commit a7842e5

Browse files
authored
fix(aria-valid-attr-value): allow aria-controls to pass when element is not in the DOM
fix(aria-valid-attr-value): allow aria-controls to pass when element is not in the DOM
1 parent 50cbdad commit a7842e5

File tree

2 files changed

+74
-17
lines changed

2 files changed

+74
-17
lines changed

lib/checks/aria/valid-attr-value.js

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,35 @@
11
options = Array.isArray(options) ? options : [];
22

3-
var invalid = [],
4-
aria = /^aria-/;
3+
const invalid = [];
4+
const aria = /^aria-/;
5+
const attrs = axe.utils.getNodeAttributes(node);
56

6-
var attr,
7-
attrName,
8-
attrs = axe.utils.getNodeAttributes(node);
7+
const skipAttrs = ['aria-errormessage'];
98

10-
var skipAttrs = ['aria-errormessage'];
9+
// aria-controls should only check if element exists if the element
10+
// doesn't have aria-expanded=false or aria-selected=false (tabs)
11+
// @see https://github.com/dequelabs/axe-core/issues/1463
12+
const preChecks = {
13+
'aria-controls': function() {
14+
return (
15+
node.getAttribute('aria-expanded') !== 'false' &&
16+
node.getAttribute('aria-selected') !== 'false'
17+
);
18+
}
19+
};
1120

12-
for (var i = 0, l = attrs.length; i < l; i++) {
13-
attr = attrs[i];
14-
attrName = attr.name;
21+
for (let i = 0, l = attrs.length; i < l; i++) {
22+
const attr = attrs[i];
23+
const attrName = attr.name;
1524
// skip any attributes handled elsewhere
16-
if (!skipAttrs.includes(attrName)) {
17-
if (
18-
options.indexOf(attrName) === -1 &&
19-
aria.test(attrName) &&
20-
!axe.commons.aria.validateAttrValue(node, attrName)
21-
) {
22-
invalid.push(attrName + '="' + attr.nodeValue + '"');
23-
}
25+
if (
26+
!skipAttrs.includes(attrName) &&
27+
options.indexOf(attrName) === -1 &&
28+
aria.test(attrName) &&
29+
(preChecks[attrName] ? preChecks[attrName]() : true) &&
30+
!axe.commons.aria.validateAttrValue(node, attrName)
31+
) {
32+
invalid.push(`${attrName}="${attr.nodeValue}"`);
2433
}
2534
}
2635

test/checks/aria/valid-attr-value.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,54 @@ describe('aria-valid-attr-value', function() {
129129
);
130130
});
131131

132+
it('should pass on aria-controls and aria-expanded=false when the element is not in the DOM', function() {
133+
fixtureSetup(
134+
'<button aria-controls="test" aria-expanded="false">Button</button>'
135+
);
136+
var passing1 = fixture.querySelector('button');
137+
assert.isTrue(
138+
checks['aria-valid-attr-value'].evaluate.call(checkContext, passing1)
139+
);
140+
});
141+
142+
it('should pass on aria-controls and aria-selected=false when the element is not in the DOM', function() {
143+
fixtureSetup(
144+
'<button aria-controls="test" aria-selected="false">Button</button>'
145+
);
146+
var passing1 = fixture.querySelector('button');
147+
assert.isTrue(
148+
checks['aria-valid-attr-value'].evaluate.call(checkContext, passing1)
149+
);
150+
});
151+
152+
it('should fail on aria-controls and aria-expanded=true when the element is not in the DOM', function() {
153+
fixtureSetup(
154+
'<button aria-controls="test" aria-expanded="true">Button</button>'
155+
);
156+
var failing1 = fixture.querySelector('button');
157+
assert.isFalse(
158+
checks['aria-valid-attr-value'].evaluate.call(checkContext, failing1)
159+
);
160+
});
161+
162+
it('should fail on aria-controls and aria-selected=true when the element is not in the DOM', function() {
163+
fixtureSetup(
164+
'<button aria-controls="test" aria-selected="true">Button</button>'
165+
);
166+
var failing1 = fixture.querySelector('button');
167+
assert.isFalse(
168+
checks['aria-valid-attr-value'].evaluate.call(checkContext, failing1)
169+
);
170+
});
171+
172+
it('should fail on aria-controls when the element is not in the DOM', function() {
173+
fixtureSetup('<button aria-controls="test">Button</button>');
174+
var failing1 = fixture.querySelector('button');
175+
assert.isFalse(
176+
checks['aria-valid-attr-value'].evaluate.call(checkContext, failing1)
177+
);
178+
});
179+
132180
describe('options', function() {
133181
it('should exclude supplied attributes', function() {
134182
fixture.innerHTML =

0 commit comments

Comments
 (0)