UNPKG

6.19 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.buildQueries = buildQueries;
7exports.getElementError = getElementError;
8exports.getMultipleElementsFoundError = getMultipleElementsFoundError;
9exports.makeFindQuery = makeFindQuery;
10exports.makeGetAllQuery = makeGetAllQuery;
11exports.makeSingleQuery = makeSingleQuery;
12exports.queryAllByAttribute = queryAllByAttribute;
13exports.queryByAttribute = queryByAttribute;
14exports.wrapSingleQueryWithSuggestion = exports.wrapAllByQueryWithSuggestion = void 0;
15var _suggestions = require("./suggestions");
16var _matches = require("./matches");
17var _waitFor = require("./wait-for");
18var _config = require("./config");
19function getElementError(message, container) {
20 return (0, _config.getConfig)().getElementError(message, container);
21}
22function getMultipleElementsFoundError(message, container) {
23 return getElementError(`${message}\n\n(If this is intentional, then use the \`*AllBy*\` variant of the query (like \`queryAllByText\`, \`getAllByText\`, or \`findAllByText\`)).`, container);
24}
25function queryAllByAttribute(attribute, container, text, {
26 exact = true,
27 collapseWhitespace,
28 trim,
29 normalizer
30} = {}) {
31 const matcher = exact ? _matches.matches : _matches.fuzzyMatches;
32 const matchNormalizer = (0, _matches.makeNormalizer)({
33 collapseWhitespace,
34 trim,
35 normalizer
36 });
37 return Array.from(container.querySelectorAll(`[${attribute}]`)).filter(node => matcher(node.getAttribute(attribute), node, text, matchNormalizer));
38}
39function queryByAttribute(attribute, container, text, options) {
40 const els = queryAllByAttribute(attribute, container, text, options);
41 if (els.length > 1) {
42 throw getMultipleElementsFoundError(`Found multiple elements by [${attribute}=${text}]`, container);
43 }
44 return els[0] || null;
45}
46
47// this accepts a query function and returns a function which throws an error
48// if more than one elements is returned, otherwise it returns the first
49// element or null
50function makeSingleQuery(allQuery, getMultipleError) {
51 return (container, ...args) => {
52 const els = allQuery(container, ...args);
53 if (els.length > 1) {
54 const elementStrings = els.map(element => getElementError(null, element).message).join('\n\n');
55 throw getMultipleElementsFoundError(`${getMultipleError(container, ...args)}
56
57Here are the matching elements:
58
59${elementStrings}`, container);
60 }
61 return els[0] || null;
62 };
63}
64function getSuggestionError(suggestion, container) {
65 return (0, _config.getConfig)().getElementError(`A better query is available, try this:
66${suggestion.toString()}
67`, container);
68}
69
70// this accepts a query function and returns a function which throws an error
71// if an empty list of elements is returned
72function makeGetAllQuery(allQuery, getMissingError) {
73 return (container, ...args) => {
74 const els = allQuery(container, ...args);
75 if (!els.length) {
76 throw (0, _config.getConfig)().getElementError(getMissingError(container, ...args), container);
77 }
78 return els;
79 };
80}
81
82// this accepts a getter query function and returns a function which calls
83// waitFor and passing a function which invokes the getter.
84function makeFindQuery(getter) {
85 return (container, text, options, waitForOptions) => {
86 return (0, _waitFor.waitFor)(() => {
87 return getter(container, text, options);
88 }, {
89 container,
90 ...waitForOptions
91 });
92 };
93}
94const wrapSingleQueryWithSuggestion = (query, queryAllByName, variant) => (container, ...args) => {
95 const element = query(container, ...args);
96 const [{
97 suggest = (0, _config.getConfig)().throwSuggestions
98 } = {}] = args.slice(-1);
99 if (element && suggest) {
100 const suggestion = (0, _suggestions.getSuggestedQuery)(element, variant);
101 if (suggestion && !queryAllByName.endsWith(suggestion.queryName)) {
102 throw getSuggestionError(suggestion.toString(), container);
103 }
104 }
105 return element;
106};
107exports.wrapSingleQueryWithSuggestion = wrapSingleQueryWithSuggestion;
108const wrapAllByQueryWithSuggestion = (query, queryAllByName, variant) => (container, ...args) => {
109 const els = query(container, ...args);
110 const [{
111 suggest = (0, _config.getConfig)().throwSuggestions
112 } = {}] = args.slice(-1);
113 if (els.length && suggest) {
114 // get a unique list of all suggestion messages. We are only going to make a suggestion if
115 // all the suggestions are the same
116 const uniqueSuggestionMessages = [...new Set(els.map(element => (0, _suggestions.getSuggestedQuery)(element, variant)?.toString()))];
117 if (
118 // only want to suggest if all the els have the same suggestion.
119 uniqueSuggestionMessages.length === 1 && !queryAllByName.endsWith(
120 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- TODO: Can this be null at runtime?
121 (0, _suggestions.getSuggestedQuery)(els[0], variant).queryName)) {
122 throw getSuggestionError(uniqueSuggestionMessages[0], container);
123 }
124 }
125 return els;
126};
127
128// TODO: This deviates from the published declarations
129// However, the implementation always required a dyadic (after `container`) not variadic `queryAllBy` considering the implementation of `makeFindQuery`
130// This is at least statically true and can be verified by accepting `QueryMethod<Arguments, HTMLElement[]>`
131exports.wrapAllByQueryWithSuggestion = wrapAllByQueryWithSuggestion;
132function buildQueries(queryAllBy, getMultipleError, getMissingError) {
133 const queryBy = wrapSingleQueryWithSuggestion(makeSingleQuery(queryAllBy, getMultipleError), queryAllBy.name, 'query');
134 const getAllBy = makeGetAllQuery(queryAllBy, getMissingError);
135 const getBy = makeSingleQuery(getAllBy, getMultipleError);
136 const getByWithSuggestions = wrapSingleQueryWithSuggestion(getBy, queryAllBy.name, 'get');
137 const getAllWithSuggestions = wrapAllByQueryWithSuggestion(getAllBy, queryAllBy.name.replace('query', 'get'), 'getAll');
138 const findAllBy = makeFindQuery(wrapAllByQueryWithSuggestion(getAllBy, queryAllBy.name, 'findAll'));
139 const findBy = makeFindQuery(wrapSingleQueryWithSuggestion(getBy, queryAllBy.name, 'find'));
140 return [queryBy, getAllWithSuggestions, getByWithSuggestions, findAllBy, findBy];
141}
\No newline at end of file