You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
284 lines
9.2 KiB
284 lines
9.2 KiB
"use strict"; |
|
|
|
Object.defineProperty(exports, "__esModule", { |
|
value: true |
|
}); |
|
exports.queryByRole = exports.queryAllByRole = exports.getByRole = exports.getAllByRole = exports.findByRole = exports.findAllByRole = void 0; |
|
|
|
var _domAccessibilityApi = require("dom-accessibility-api"); |
|
|
|
var _ariaQuery = require("aria-query"); |
|
|
|
var _roleHelpers = require("../role-helpers"); |
|
|
|
var _queryHelpers = require("../query-helpers"); |
|
|
|
var _helpers = require("../helpers"); |
|
|
|
var _allUtils = require("./all-utils"); |
|
|
|
function queryAllByRole(container, role, { |
|
exact = true, |
|
collapseWhitespace, |
|
hidden = (0, _allUtils.getConfig)().defaultHidden, |
|
name, |
|
description, |
|
trim, |
|
normalizer, |
|
queryFallbacks = false, |
|
selected, |
|
checked, |
|
pressed, |
|
current, |
|
level, |
|
expanded |
|
} = {}) { |
|
(0, _helpers.checkContainerType)(container); |
|
const matcher = exact ? _allUtils.matches : _allUtils.fuzzyMatches; |
|
const matchNormalizer = (0, _allUtils.makeNormalizer)({ |
|
collapseWhitespace, |
|
trim, |
|
normalizer |
|
}); |
|
|
|
if (selected !== undefined) { |
|
var _allRoles$get; |
|
|
|
// guard against unknown roles |
|
if (((_allRoles$get = _ariaQuery.roles.get(role)) == null ? void 0 : _allRoles$get.props['aria-selected']) === undefined) { |
|
throw new Error(`"aria-selected" is not supported on role "${role}".`); |
|
} |
|
} |
|
|
|
if (checked !== undefined) { |
|
var _allRoles$get2; |
|
|
|
// guard against unknown roles |
|
if (((_allRoles$get2 = _ariaQuery.roles.get(role)) == null ? void 0 : _allRoles$get2.props['aria-checked']) === undefined) { |
|
throw new Error(`"aria-checked" is not supported on role "${role}".`); |
|
} |
|
} |
|
|
|
if (pressed !== undefined) { |
|
var _allRoles$get3; |
|
|
|
// guard against unknown roles |
|
if (((_allRoles$get3 = _ariaQuery.roles.get(role)) == null ? void 0 : _allRoles$get3.props['aria-pressed']) === undefined) { |
|
throw new Error(`"aria-pressed" is not supported on role "${role}".`); |
|
} |
|
} |
|
|
|
if (current !== undefined) { |
|
var _allRoles$get4; |
|
|
|
/* istanbul ignore next */ |
|
// guard against unknown roles |
|
// All currently released ARIA versions support `aria-current` on all roles. |
|
// Leaving this for symetry and forward compatibility |
|
if (((_allRoles$get4 = _ariaQuery.roles.get(role)) == null ? void 0 : _allRoles$get4.props['aria-current']) === undefined) { |
|
throw new Error(`"aria-current" is not supported on role "${role}".`); |
|
} |
|
} |
|
|
|
if (level !== undefined) { |
|
// guard against using `level` option with any role other than `heading` |
|
if (role !== 'heading') { |
|
throw new Error(`Role "${role}" cannot have "level" property.`); |
|
} |
|
} |
|
|
|
if (expanded !== undefined) { |
|
var _allRoles$get5; |
|
|
|
// guard against unknown roles |
|
if (((_allRoles$get5 = _ariaQuery.roles.get(role)) == null ? void 0 : _allRoles$get5.props['aria-expanded']) === undefined) { |
|
throw new Error(`"aria-expanded" is not supported on role "${role}".`); |
|
} |
|
} |
|
|
|
const subtreeIsInaccessibleCache = new WeakMap(); |
|
|
|
function cachedIsSubtreeInaccessible(element) { |
|
if (!subtreeIsInaccessibleCache.has(element)) { |
|
subtreeIsInaccessibleCache.set(element, (0, _roleHelpers.isSubtreeInaccessible)(element)); |
|
} |
|
|
|
return subtreeIsInaccessibleCache.get(element); |
|
} |
|
|
|
return Array.from(container.querySelectorAll( // Only query elements that can be matched by the following filters |
|
makeRoleSelector(role, exact, normalizer ? matchNormalizer : undefined))).filter(node => { |
|
const isRoleSpecifiedExplicitly = node.hasAttribute('role'); |
|
|
|
if (isRoleSpecifiedExplicitly) { |
|
const roleValue = node.getAttribute('role'); |
|
|
|
if (queryFallbacks) { |
|
return roleValue.split(' ').filter(Boolean).some(text => matcher(text, node, role, matchNormalizer)); |
|
} // if a custom normalizer is passed then let normalizer handle the role value |
|
|
|
|
|
if (normalizer) { |
|
return matcher(roleValue, node, role, matchNormalizer); |
|
} // other wise only send the first word to match |
|
|
|
|
|
const [firstWord] = roleValue.split(' '); |
|
return matcher(firstWord, node, role, matchNormalizer); |
|
} |
|
|
|
const implicitRoles = (0, _roleHelpers.getImplicitAriaRoles)(node); |
|
return implicitRoles.some(implicitRole => matcher(implicitRole, node, role, matchNormalizer)); |
|
}).filter(element => { |
|
if (selected !== undefined) { |
|
return selected === (0, _roleHelpers.computeAriaSelected)(element); |
|
} |
|
|
|
if (checked !== undefined) { |
|
return checked === (0, _roleHelpers.computeAriaChecked)(element); |
|
} |
|
|
|
if (pressed !== undefined) { |
|
return pressed === (0, _roleHelpers.computeAriaPressed)(element); |
|
} |
|
|
|
if (current !== undefined) { |
|
return current === (0, _roleHelpers.computeAriaCurrent)(element); |
|
} |
|
|
|
if (expanded !== undefined) { |
|
return expanded === (0, _roleHelpers.computeAriaExpanded)(element); |
|
} |
|
|
|
if (level !== undefined) { |
|
return level === (0, _roleHelpers.computeHeadingLevel)(element); |
|
} // don't care if aria attributes are unspecified |
|
|
|
|
|
return true; |
|
}).filter(element => { |
|
if (name === undefined) { |
|
// Don't care |
|
return true; |
|
} |
|
|
|
return (0, _allUtils.matches)((0, _domAccessibilityApi.computeAccessibleName)(element, { |
|
computedStyleSupportsPseudoElements: (0, _allUtils.getConfig)().computedStyleSupportsPseudoElements |
|
}), element, name, text => text); |
|
}).filter(element => { |
|
if (description === undefined) { |
|
// Don't care |
|
return true; |
|
} |
|
|
|
return (0, _allUtils.matches)((0, _domAccessibilityApi.computeAccessibleDescription)(element, { |
|
computedStyleSupportsPseudoElements: (0, _allUtils.getConfig)().computedStyleSupportsPseudoElements |
|
}), element, description, text => text); |
|
}).filter(element => { |
|
return hidden === false ? (0, _roleHelpers.isInaccessible)(element, { |
|
isSubtreeInaccessible: cachedIsSubtreeInaccessible |
|
}) === false : true; |
|
}); |
|
} |
|
|
|
function makeRoleSelector(role, exact, customNormalizer) { |
|
var _roleElements$get; |
|
|
|
if (typeof role !== 'string') { |
|
// For non-string role parameters we can not determine the implicitRoleSelectors. |
|
return '*'; |
|
} |
|
|
|
const explicitRoleSelector = exact && !customNormalizer ? `*[role~="${role}"]` : '*[role]'; |
|
const roleRelations = (_roleElements$get = _ariaQuery.roleElements.get(role)) != null ? _roleElements$get : new Set(); |
|
const implicitRoleSelectors = new Set(Array.from(roleRelations).map(({ |
|
name |
|
}) => name)); // Current transpilation config sometimes assumes `...` is always applied to arrays. |
|
// `...` is equivalent to `Array.prototype.concat` for arrays. |
|
// If you replace this code with `[explicitRoleSelector, ...implicitRoleSelectors]`, make sure every transpilation target retains the `...` in favor of `Array.prototype.concat`. |
|
|
|
return [explicitRoleSelector].concat(Array.from(implicitRoleSelectors)).join(','); |
|
} |
|
|
|
const getMultipleError = (c, role, { |
|
name |
|
} = {}) => { |
|
let nameHint = ''; |
|
|
|
if (name === undefined) { |
|
nameHint = ''; |
|
} else if (typeof name === 'string') { |
|
nameHint = ` and name "${name}"`; |
|
} else { |
|
nameHint = ` and name \`${name}\``; |
|
} |
|
|
|
return `Found multiple elements with the role "${role}"${nameHint}`; |
|
}; |
|
|
|
const getMissingError = (container, role, { |
|
hidden = (0, _allUtils.getConfig)().defaultHidden, |
|
name, |
|
description |
|
} = {}) => { |
|
if ((0, _allUtils.getConfig)()._disableExpensiveErrorDiagnostics) { |
|
return `Unable to find role="${role}"`; |
|
} |
|
|
|
let roles = ''; |
|
Array.from(container.children).forEach(childElement => { |
|
roles += (0, _roleHelpers.prettyRoles)(childElement, { |
|
hidden, |
|
includeDescription: description !== undefined |
|
}); |
|
}); |
|
let roleMessage; |
|
|
|
if (roles.length === 0) { |
|
if (hidden === false) { |
|
roleMessage = 'There are no accessible roles. But there might be some inaccessible roles. ' + 'If you wish to access them, then set the `hidden` option to `true`. ' + 'Learn more about this here: https://testing-library.com/docs/dom-testing-library/api-queries#byrole'; |
|
} else { |
|
roleMessage = 'There are no available roles.'; |
|
} |
|
} else { |
|
roleMessage = ` |
|
Here are the ${hidden === false ? 'accessible' : 'available'} roles: |
|
|
|
${roles.replace(/\n/g, '\n ').replace(/\n\s\s\n/g, '\n\n')} |
|
`.trim(); |
|
} |
|
|
|
let nameHint = ''; |
|
|
|
if (name === undefined) { |
|
nameHint = ''; |
|
} else if (typeof name === 'string') { |
|
nameHint = ` and name "${name}"`; |
|
} else { |
|
nameHint = ` and name \`${name}\``; |
|
} |
|
|
|
let descriptionHint = ''; |
|
|
|
if (description === undefined) { |
|
descriptionHint = ''; |
|
} else if (typeof description === 'string') { |
|
descriptionHint = ` and description "${description}"`; |
|
} else { |
|
descriptionHint = ` and description \`${description}\``; |
|
} |
|
|
|
return ` |
|
Unable to find an ${hidden === false ? 'accessible ' : ''}element with the role "${role}"${nameHint}${descriptionHint} |
|
|
|
${roleMessage}`.trim(); |
|
}; |
|
|
|
const queryAllByRoleWithSuggestions = (0, _queryHelpers.wrapAllByQueryWithSuggestion)(queryAllByRole, queryAllByRole.name, 'queryAll'); |
|
exports.queryAllByRole = queryAllByRoleWithSuggestions; |
|
const [queryByRole, getAllByRole, getByRole, findAllByRole, findByRole] = (0, _allUtils.buildQueries)(queryAllByRole, getMultipleError, getMissingError); |
|
exports.findByRole = findByRole; |
|
exports.findAllByRole = findAllByRole; |
|
exports.getByRole = getByRole; |
|
exports.getAllByRole = getAllByRole; |
|
exports.queryByRole = queryByRole; |