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.

138 lines
5.4 KiB

4 years ago
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.queryAllByLabelText = queryAllByLabelText;
exports.getAllByLabelText = getAllByLabelText;
exports.findByLabelText = exports.findAllByLabelText = exports.getByLabelText = exports.queryByLabelText = void 0;
var _config = require("../config");
var _allUtils = require("./all-utils");
var _text = require("./text");
function queryAllLabelsByText(container, text, {
exact = true,
trim,
collapseWhitespace,
normalizer
} = {}) {
const matcher = exact ? _allUtils.matches : _allUtils.fuzzyMatches;
const matchNormalizer = (0, _allUtils.makeNormalizer)({
collapseWhitespace,
trim,
normalizer
});
return Array.from(container.querySelectorAll('label')).filter(label => {
let textToMatch = label.textContent; // The children of a textarea are part of `textContent` as well. We
// need to remove them from the string so we can match it afterwards.
Array.from(label.querySelectorAll('textarea')).forEach(textarea => {
textToMatch = textToMatch.replace(textarea.value, '');
}); // The children of a select are also part of `textContent`, so we
// need also to remove their text.
Array.from(label.querySelectorAll('select')).forEach(select => {
textToMatch = textToMatch.replace(select.textContent, '');
});
return matcher(textToMatch, label, text, matchNormalizer);
});
}
function queryAllByLabelText(container, text, {
selector = '*',
exact = true,
collapseWhitespace,
trim,
normalizer
} = {}) {
const matchNormalizer = (0, _allUtils.makeNormalizer)({
collapseWhitespace,
trim,
normalizer
});
const labels = queryAllLabelsByText(container, text, {
exact,
normalizer: matchNormalizer
});
const labelledElements = labels.reduce((matchedElements, label) => {
const elementsForLabel = [];
if (label.control) {
elementsForLabel.push(label.control);
}
/* istanbul ignore if */
if (label.getAttribute('for')) {
// we're using this notation because with the # selector we would have to escape special characters e.g. user.name
// see https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector#Escaping_special_characters
// <label for="someId">text</label><input id="someId" />
// .control support has landed in jsdom (https://github.com/jsdom/jsdom/issues/2175)
elementsForLabel.push(container.querySelector(`[id="${label.getAttribute('for')}"]`));
}
if (label.getAttribute('id')) {
// <label id="someId">text</label><input aria-labelledby="someId" />
container.querySelectorAll(`[aria-labelledby~="${label.getAttribute('id')}"]`).forEach(element => elementsForLabel.push(element));
}
if (label.childNodes.length) {
// <label>text: <input /></label>
label.querySelectorAll('button, input, meter, output, progress, select, textarea').forEach(element => elementsForLabel.push(element));
}
return matchedElements.concat(elementsForLabel);
}, []).filter(element => element !== null).concat((0, _allUtils.queryAllByAttribute)('aria-label', container, text, {
exact
}));
const possibleAriaLabelElements = (0, _text.queryAllByText)(container, text, {
exact,
normalizer: matchNormalizer
});
const ariaLabelledElements = possibleAriaLabelElements.reduce((allLabelledElements, nextLabelElement) => {
const labelId = nextLabelElement.getAttribute('id');
if (!labelId) return allLabelledElements; // ARIA labels can label multiple elements
const labelledNodes = Array.from(container.querySelectorAll(`[aria-labelledby~="${labelId}"]`));
return allLabelledElements.concat(labelledNodes);
}, []);
return Array.from(new Set([...labelledElements, ...ariaLabelledElements])).filter(element => element.matches(selector));
} // the getAll* query would normally look like this:
// const getAllByLabelText = makeGetAllQuery(
// queryAllByLabelText,
// (c, text) => `Unable to find a label with the text of: ${text}`,
// )
// however, we can give a more helpful error message than the generic one,
// so we're writing this one out by hand.
function getAllByLabelText(container, text, ...rest) {
const els = queryAllByLabelText(container, text, ...rest);
if (!els.length) {
const labels = queryAllLabelsByText(container, text, ...rest);
if (labels.length) {
throw (0, _config.getConfig)().getElementError(`Found a label with the text of: ${text}, however no form control was found associated to that label. Make sure you're using the "for" attribute or "aria-labelledby" attribute correctly.`, container);
} else {
throw (0, _config.getConfig)().getElementError(`Unable to find a label with the text of: ${text}`, container);
}
}
return els;
} // the reason mentioned above is the same reason we're not using buildQueries
const getMultipleError = (c, text) => `Found multiple elements with the text of: ${text}`;
const queryByLabelText = (0, _allUtils.makeSingleQuery)(queryAllByLabelText, getMultipleError);
exports.queryByLabelText = queryByLabelText;
const getByLabelText = (0, _allUtils.makeSingleQuery)(getAllByLabelText, getMultipleError);
exports.getByLabelText = getByLabelText;
const findAllByLabelText = (0, _allUtils.makeFindQuery)(getAllByLabelText);
exports.findAllByLabelText = findAllByLabelText;
const findByLabelText = (0, _allUtils.makeFindQuery)(getByLabelText);
exports.findByLabelText = findByLabelText;