UNPKG

axe-core

Version:

Accessibility engine for automated Web UI testing

96 lines (77 loc) 2.7 kB
const requiredOwned = axe.commons.aria.requiredOwned; const implicitNodes = axe.commons.aria.implicitNodes; const matchesSelector = axe.commons.utils.matchesSelector; const idrefs = axe.commons.dom.idrefs; const reviewEmpty = options && Array.isArray(options.reviewEmpty) ? options.reviewEmpty : []; function owns(node, virtualTree, role, ariaOwned) { if (node === null) { return false; } var implicit = implicitNodes(role), selector = ['[role="' + role + '"]']; if (implicit) { selector = selector.concat(implicit); } selector = selector.join(','); return ariaOwned ? (matchesSelector(node, selector) || !!axe.utils.querySelectorAll(virtualTree, selector)[0]) : !!axe.utils.querySelectorAll(virtualTree, selector)[0]; } function ariaOwns(nodes, role) { var index, length; for (index = 0, length = nodes.length; index < length; index++) { if (nodes[index] === null) { continue; } let virtualTree = axe.utils.getNodeFromTree(axe._tree[0], nodes[index]); if (owns(nodes[index], virtualTree, role, true)) { return true; } } return false; } function missingRequiredChildren(node, childRoles, all, role) { /* eslint max-statements: ["error", 22], complexity: ["error", 17] */ var i, l = childRoles.length, missing = [], ownedElements = idrefs(node, 'aria-owns'); for (i = 0; i < l; i++) { var r = childRoles[i]; if (owns(node, virtualNode, r) || ariaOwns(ownedElements, r)) { if (!all) { return null; } } else { if (all) { missing.push(r); } } } // combobox exceptions if (role === 'combobox') { // remove 'textbox' from missing roles if combobox is a native text-type input var textboxIndex = missing.indexOf('textbox'); var textTypeInputs = ['text', 'search', 'email', 'url', 'tel']; if (textboxIndex >= 0 && node.tagName === 'INPUT' && textTypeInputs.includes(node.type)) { missing.splice(textboxIndex, 1); } // remove 'listbox' from missing roles if combobox is collapsed var listboxIndex = missing.indexOf('listbox'); var expanded = node.getAttribute('aria-expanded'); if (listboxIndex >= 0 && (!expanded || expanded === 'false')) { missing.splice(listboxIndex, 1); } } if (missing.length) { return missing; } if (!all && childRoles.length) { return childRoles; } return null; } var role = node.getAttribute('role'); var required = requiredOwned(role); if (!required) { return true; } var all = false; var childRoles = required.one; if (!childRoles) { var all = true; childRoles = required.all; } var missing = missingRequiredChildren(node, childRoles, all, role); if (!missing) { return true; } this.data(missing); if (reviewEmpty.includes(role)) { return undefined; } else { return false; }