Skip to content

Commit 3726901

Browse files
authored
feat(rule): add additional elements to check for incomplete with required children (#1547)
1 parent 861371a commit 3726901

File tree

6 files changed

+93
-17
lines changed

6 files changed

+93
-17
lines changed

lib/checks/aria/required-children.js

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,20 +39,23 @@ function ariaOwns(nodes, role) {
3939
}
4040

4141
function missingRequiredChildren(node, childRoles, all, role) {
42-
var i,
43-
l = childRoles.length,
42+
var index,
43+
length = childRoles.length,
4444
missing = [],
4545
ownedElements = idrefs(node, 'aria-owns');
4646

47-
for (i = 0; i < l; i++) {
48-
var r = childRoles[i];
49-
if (owns(node, virtualNode, r) || ariaOwns(ownedElements, r)) {
47+
for (index = 0; index < length; index++) {
48+
var childRole = childRoles[index];
49+
if (
50+
owns(node, virtualNode, childRole) ||
51+
ariaOwns(ownedElements, childRole)
52+
) {
5053
if (!all) {
5154
return null;
5255
}
5356
} else {
5457
if (all) {
55-
missing.push(r);
58+
missing.push(childRole);
5659
}
5760
}
5861
}
@@ -109,7 +112,12 @@ if (!missing) {
109112

110113
this.data(missing);
111114

112-
if (reviewEmpty.includes(role)) {
115+
// Only review empty nodes when a node is both empty and does not have an aria-owns relationship
116+
if (
117+
reviewEmpty.includes(role) &&
118+
node.children.length === 0 &&
119+
idrefs(node, 'aria-owns').length === 0
120+
) {
113121
return undefined;
114122
} else {
115123
return false;

lib/checks/aria/required-children.json

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,18 @@
22
"id": "aria-required-children",
33
"evaluate": "required-children.js",
44
"options": {
5-
"reviewEmpty": ["listbox"]
5+
"reviewEmpty": [
6+
"doc-bibliography",
7+
"doc-endnotes",
8+
"grid",
9+
"list",
10+
"listbox",
11+
"table",
12+
"tablist",
13+
"tree",
14+
"treegrid",
15+
"rowgroup"
16+
]
617
},
718
"metadata": {
819
"impact": "critical",

lib/commons/aria/index.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,9 @@ lookupTable.role = {
624624
attributes: {
625625
allowed: ['aria-expanded', 'aria-errormessage']
626626
},
627-
owned: null,
627+
owned: {
628+
one: ['doc-biblioentry']
629+
},
628630
nameFrom: ['author'],
629631
context: null,
630632
unsupported: false,
@@ -746,7 +748,9 @@ lookupTable.role = {
746748
attributes: {
747749
allowed: ['aria-expanded', 'aria-errormessage']
748750
},
749-
owned: ['doc-endnote'],
751+
owned: {
752+
one: ['doc-endnote']
753+
},
750754
namefrom: ['author'],
751755
context: null,
752756
unsupported: false,
@@ -1280,7 +1284,9 @@ lookupTable.role = {
12801284
'aria-errormessage'
12811285
]
12821286
},
1283-
owned: null,
1287+
owned: {
1288+
one: ['menuitem', 'menuitemradio', 'menuitemcheckbox']
1289+
},
12841290
nameFrom: ['author'],
12851291
context: null,
12861292
unsupported: false,

test/checks/aria/required-children.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,35 @@ describe('aria-required-children', function() {
103103
);
104104
});
105105

106+
it('should return undefined when element is empty and is in reviewEmpty options', function() {
107+
var params = checkSetup('<div role="list" id="target"></div>', {
108+
reviewEmpty: ['list']
109+
});
110+
assert.isUndefined(
111+
checks['aria-required-children'].evaluate.apply(checkContext, params)
112+
);
113+
});
114+
115+
it('should return false when children do not have correct role and is in reviewEmpty options', function() {
116+
var params = checkSetup(
117+
'<div role="list" id="target"><div role="menuitem"></div></div>',
118+
{ reviewEmpty: ['list'] }
119+
);
120+
assert.isFalse(
121+
checks['aria-required-children'].evaluate.apply(checkContext, params)
122+
);
123+
});
124+
125+
it('should return false when owned children do not have correct role and is in reviewEmpty options', function() {
126+
var params = checkSetup(
127+
'<div role="list" id="target" aria-owns="ownedchild"></div><div id="ownedchild" role="menuitem"></div>',
128+
{ reviewEmpty: ['list'] }
129+
);
130+
assert.isFalse(
131+
checks['aria-required-children'].evaluate.apply(checkContext, params)
132+
);
133+
});
134+
106135
(shadowSupported ? it : xit)(
107136
'should pass all existing required children in shadow tree when all required',
108137
function() {
Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
11
<div role="list" id="pass1"><div role="listitem" id="pass2">Item 1</div></div>
22
<div role="list" id="pass3" aria-owns="pass4"></div>
33
<div role="listitem" id="pass4"></div>
4-
<div role="list" id="fail1"></div>
5-
<div role="list" id="fail2"><div role="menuitem" id="pass5"></div></div>
6-
<div role="list" id="fail3" aria-owns="pass6"></div>
4+
<div role="list" id="fail1"><div role="menuitem" id="pass5"></div></div>
5+
<div role="list" id="fail2" aria-owns="pass6"></div>
6+
<div role="menu" id="fail3"></div>
7+
<div role="menubar" id="fail4"></div>
8+
<div role="row" id="fail5"></div>
79
<div role="menuitem" id="pass6"></div>
810
<div role="list" id="pass7" aria-owns="parent"></div>
911
<div id="parent"><div role="listitem" id="pass8"></div></div>
10-
<div role="listbox" id="incomplete1"></div>
12+
<div role="grid" id="incomplete1"></div>
13+
<div role="list" id="incomplete2"></div>
14+
<div role="listbox" id="incomplete3"></div>
15+
<div role="table" id="incomplete4"></div>
16+
<div role="tablist" id="incomplete5"></div>
17+
<div role="tree" id="incomplete6"></div>
18+
<div role="treegrid" id="incomplete7"></div>
19+
<div role="rowgroup" id="incomplete8"></div>
20+
<div role="doc-bibliography" id="incomplete9"></div>
21+
<div role="doc-endnotes" id="incomplete10"></div>

test/integration/rules/aria-required-children/aria-required-children.json

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"description": "aria-required-children test",
33
"rule": "aria-required-children",
4-
"violations": [["#fail1"], ["#fail2"], ["#fail3"]],
4+
"violations": [["#fail1"], ["#fail2"], ["#fail3"], ["#fail4"], ["#fail5"]],
55
"passes": [
66
["#pass1"],
77
["#pass2"],
@@ -12,5 +12,16 @@
1212
["#pass7"],
1313
["#pass8"]
1414
],
15-
"incomplete": [["#incomplete1"]]
15+
"incomplete": [
16+
["#incomplete1"],
17+
["#incomplete2"],
18+
["#incomplete3"],
19+
["#incomplete4"],
20+
["#incomplete5"],
21+
["#incomplete6"],
22+
["#incomplete7"],
23+
["#incomplete8"],
24+
["#incomplete9"],
25+
["#incomplete10"]
26+
]
1627
}

0 commit comments

Comments
 (0)