Skip to content

Commit

Permalink
fix(aria-required-children): allow reviewEmpty nodes to have empty ch…
Browse files Browse the repository at this point in the history
…ildren (#1791)

* fix(aria-required-children): allow reviewEmpty nodes to have empty children

* ignore presentation and none roles, rename function, ignore aria-label
  • Loading branch information
straker committed Sep 3, 2019
1 parent 2bef161 commit a5d727c
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 2 deletions.
17 changes: 16 additions & 1 deletion lib/checks/aria/required-children.js
Expand Up @@ -2,6 +2,7 @@ const requiredOwned = axe.commons.aria.requiredOwned;
const implicitNodes = axe.commons.aria.implicitNodes;
const matchesSelector = axe.utils.matchesSelector;
const idrefs = axe.commons.dom.idrefs;
const hasContentVirtual = axe.commons.dom.hasContentVirtual;
const reviewEmpty =
options && Array.isArray(options.reviewEmpty) ? options.reviewEmpty : [];

Expand Down Expand Up @@ -94,6 +95,19 @@ function missingRequiredChildren(node, childRoles, all, role) {
return null;
}

function hasDecendantWithRole(node) {
return (
node.children &&
node.children.some(child => {
const role = axe.commons.aria.getRole(child);
return (
!['presentation', 'none', null].includes(role) ||
hasDecendantWithRole(child)
);
})
);
}

var role = node.getAttribute('role');
var required = requiredOwned(role);

Expand All @@ -119,7 +133,8 @@ this.data(missing);
// Only review empty nodes when a node is both empty and does not have an aria-owns relationship
if (
reviewEmpty.includes(role) &&
node.children.length === 0 &&
!hasContentVirtual(virtualNode, false, true) &&
!hasDecendantWithRole(virtualNode) &&
idrefs(node, 'aria-owns').length === 0
) {
return undefined;
Expand Down
60 changes: 60 additions & 0 deletions test/checks/aria/required-children.js
Expand Up @@ -342,5 +342,65 @@ describe('aria-required-children', function() {
checks['aria-required-children'].evaluate.apply(checkContext, params)
);
});

it('should return undefined when the element has empty children', function() {
var params = checkSetup(
'<div role="listbox" id="target"><div></div></div>'
);
params[1] = {
reviewEmpty: ['listbox']
};
assert.isUndefined(
checks['aria-required-children'].evaluate.apply(checkContext, params)
);
});

it('should return false when the element has empty child with role', function() {
var params = checkSetup(
'<div role="listbox" id="target"><div role="grid"></div></div>'
);
params[1] = {
reviewEmpty: ['listbox']
};
assert.isFalse(
checks['aria-required-children'].evaluate.apply(checkContext, params)
);
});

it('should return undefined when the element has empty child with role=presentation', function() {
var params = checkSetup(
'<div role="listbox" id="target"><div role="presentation"></div></div>'
);
params[1] = {
reviewEmpty: ['listbox']
};
assert.isUndefined(
checks['aria-required-children'].evaluate.apply(checkContext, params)
);
});

it('should return undefined when the element has empty child with role=none', function() {
var params = checkSetup(
'<div role="listbox" id="target"><div role="none"></div></div>'
);
params[1] = {
reviewEmpty: ['listbox']
};
assert.isUndefined(
checks['aria-required-children'].evaluate.apply(checkContext, params)
);
});

it('should return undefined when the element has empty child and aria-label', function() {
var params = checkSetup(
'<div role="listbox" id="target" aria-label="listbox"><div></div></div>'
);
params[1] = {
reviewEmpty: ['listbox']
};
assert.isUndefined(
checks['aria-required-children'].evaluate.apply(checkContext, params)
);
});
});
});
Expand Up @@ -19,3 +19,4 @@
<div role="rowgroup" id="incomplete8"></div>
<div role="doc-bibliography" id="incomplete9"></div>
<div role="doc-endnotes" id="incomplete10"></div>
<div role="listbox" id="incomplete11"><div></div></div>
Expand Up @@ -22,6 +22,7 @@
["#incomplete7"],
["#incomplete8"],
["#incomplete9"],
["#incomplete10"]
["#incomplete10"],
["#incomplete11"]
]
}

0 comments on commit a5d727c

Please sign in to comment.