Skip to content

Commit d893896

Browse files
committed
refacor: move queries to TS / prettify some code according ABC
1 parent ffc8f26 commit d893896

22 files changed

+163
-106
lines changed

src/config.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ export function runWithExpensiveErrorDiagnosticsDisabled<T>(
5353
}
5454
}
5555

56-
export function configure(newConfig: Partial<Config> | ConfigFn) {
56+
export function configure(newConfig: ConfigFn | Partial<Config>) {
5757
if (typeof newConfig === 'function') {
5858
// Pass the existing config out to the provided function
5959
// and accept a delta in return

src/get-node-text.js renamed to src/get-node-text.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import {TEXT_NODE} from './helpers'
22

3-
function getNodeText(node) {
3+
function getNodeText(node: HTMLElement): string {
44
if (node.matches('input[type=submit], input[type=button]')) {
5-
return node.value
5+
return (node as HTMLInputElement).value
66
}
77

88
return Array.from(node.childNodes)

src/label-helpers.ts

+8-5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import {Nullish} from '../types'
12
import {TEXT_NODE} from './helpers'
23

34
const labelledNodeNames = [
@@ -11,7 +12,7 @@ const labelledNodeNames = [
1112
]
1213

1314
function getTextContent(
14-
node: Node | Element | HTMLInputElement,
15+
node: Element | HTMLInputElement | Node,
1516
): string | null {
1617
if (labelledNodeNames.includes(node.nodeName.toLowerCase())) {
1718
return ''
@@ -24,7 +25,7 @@ function getTextContent(
2425
.join('')
2526
}
2627

27-
function getLabelContent(element: Element): string | null {
28+
function getLabelContent(element: Element): Nullish<string> {
2829
let textContent: string | null
2930
if (element.tagName.toLowerCase() === 'label') {
3031
textContent = getTextContent(element)
@@ -58,12 +59,14 @@ function getLabels(
5859
container: Element,
5960
element: Element,
6061
{selector = '*'} = {},
61-
) {
62+
): {content: Nullish<string>; formControl: Nullish<HTMLElement>}[] {
6263
const ariaLabelledBy = element.getAttribute('aria-labelledby')
6364
const labelsId = ariaLabelledBy ? ariaLabelledBy.split(' ') : []
6465
return labelsId.length
6566
? labelsId.map(labelId => {
66-
const labellingElement = container.querySelector(`[id="${labelId}"]`)
67+
const labellingElement = container.querySelector<HTMLElement>(
68+
`[id="${labelId}"]`,
69+
)
6770
return labellingElement
6871
? {content: getLabelContent(labellingElement), formControl: null}
6972
: {content: '', formControl: null}
@@ -73,7 +76,7 @@ function getLabels(
7376
const formControlSelector =
7477
'button, input, meter, output, progress, select, textarea'
7578
const labelledFormControl = Array.from(
76-
label.querySelectorAll(formControlSelector),
79+
label.querySelectorAll<HTMLElement>(formControlSelector),
7780
).filter(formControlElement => formControlElement.matches(selector))[0]
7881
return {content: textToMatch, formControl: labelledFormControl}
7982
})
File renamed without changes.

src/queries/alt-text.js renamed to src/queries/alt-text.ts

+8-5
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,26 @@
11
import {wrapAllByQueryWithSuggestion} from '../query-helpers'
22
import {checkContainerType} from '../helpers'
3+
import {AllByBoundAttribute, GetErrorFunction} from '../../types'
34
import {matches, fuzzyMatches, makeNormalizer, buildQueries} from './all-utils'
45

5-
function queryAllByAltText(
6+
const queryAllByAltText: AllByBoundAttribute = (
67
container,
78
alt,
89
{exact = true, collapseWhitespace, trim, normalizer} = {},
9-
) {
10+
) => {
1011
checkContainerType(container)
1112
const matcher = exact ? matches : fuzzyMatches
1213
const matchNormalizer = makeNormalizer({collapseWhitespace, trim, normalizer})
13-
return Array.from(container.querySelectorAll('img,input,area')).filter(node =>
14+
return Array.from(
15+
container.querySelectorAll<HTMLElement>('img,input,area'),
16+
).filter(node =>
1417
matcher(node.getAttribute('alt'), node, alt, matchNormalizer),
1518
)
1619
}
1720

18-
const getMultipleError = (c, alt) =>
21+
const getMultipleError: GetErrorFunction = (c, alt) =>
1922
`Found multiple elements with the alt text: ${alt}`
20-
const getMissingError = (c, alt) =>
23+
const getMissingError: GetErrorFunction = (c, alt) =>
2124
`Unable to find an element with the alt text: ${alt}`
2225

2326
const queryAllByAltTextWithSuggestions = wrapAllByQueryWithSuggestion(

src/queries/display-value.js renamed to src/queries/display-value.ts

+24-18
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {wrapAllByQueryWithSuggestion} from '../query-helpers'
22
import {checkContainerType} from '../helpers'
3+
import {AllByBoundAttribute, GetErrorFunction} from '../../types'
34
import {
45
getNodeText,
56
matches,
@@ -8,33 +9,38 @@ import {
89
buildQueries,
910
} from './all-utils'
1011

11-
function queryAllByDisplayValue(
12+
const queryAllByDisplayValue: AllByBoundAttribute = (
1213
container,
1314
value,
1415
{exact = true, collapseWhitespace, trim, normalizer} = {},
15-
) {
16+
) => {
1617
checkContainerType(container)
1718
const matcher = exact ? matches : fuzzyMatches
1819
const matchNormalizer = makeNormalizer({collapseWhitespace, trim, normalizer})
19-
return Array.from(container.querySelectorAll(`input,textarea,select`)).filter(
20-
node => {
21-
if (node.tagName === 'SELECT') {
22-
const selectedOptions = Array.from(node.options).filter(
23-
option => option.selected,
24-
)
25-
return selectedOptions.some(optionNode =>
26-
matcher(getNodeText(optionNode), optionNode, value, matchNormalizer),
27-
)
28-
} else {
29-
return matcher(node.value, node, value, matchNormalizer)
30-
}
31-
},
32-
)
20+
return Array.from(
21+
container.querySelectorAll<HTMLElement>(`input,textarea,select`),
22+
).filter(node => {
23+
if (node.tagName === 'SELECT') {
24+
const selectedOptions = Array.from(
25+
(node as HTMLSelectElement).options,
26+
).filter(option => option.selected)
27+
return selectedOptions.some(optionNode =>
28+
matcher(getNodeText(optionNode), optionNode, value, matchNormalizer),
29+
)
30+
} else {
31+
return matcher(
32+
(node as HTMLInputElement).value,
33+
node,
34+
value,
35+
matchNormalizer,
36+
)
37+
}
38+
})
3339
}
3440

35-
const getMultipleError = (c, value) =>
41+
const getMultipleError: GetErrorFunction = (c, value) =>
3642
`Found multiple elements with the display value: ${value}.`
37-
const getMissingError = (c, value) =>
43+
const getMissingError: GetErrorFunction = (c, value) =>
3844
`Unable to find an element with the display value: ${value}.`
3945

4046
const queryAllByDisplayValueWithSuggestions = wrapAllByQueryWithSuggestion(
File renamed without changes.

src/queries/label-text.js renamed to src/queries/label-text.ts

+26-12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {getConfig} from '../config'
22
import {checkContainerType} from '../helpers'
33
import {getLabels, getRealLabels, getLabelContent} from '../label-helpers'
4+
import {AllByText, GetErrorFunction, Nullish} from '../../types'
45
import {
56
fuzzyMatches,
67
matches,
@@ -12,19 +13,21 @@ import {
1213
wrapSingleQueryWithSuggestion,
1314
} from './all-utils'
1415

15-
function queryAllLabels(container) {
16-
return Array.from(container.querySelectorAll('label,input'))
16+
function queryAllLabels(
17+
container: HTMLElement,
18+
): {textToMatch: Nullish<string>; node: HTMLElement}[] {
19+
return Array.from(container.querySelectorAll<HTMLElement>('label,input'))
1720
.map(node => {
1821
return {node, textToMatch: getLabelContent(node)}
1922
})
2023
.filter(({textToMatch}) => textToMatch !== null)
2124
}
2225

23-
function queryAllLabelsByText(
26+
const queryAllLabelsByText: AllByText = (
2427
container,
2528
text,
2629
{exact = true, trim, collapseWhitespace, normalizer} = {},
27-
) {
30+
) => {
2831
const matcher = exact ? matches : fuzzyMatches
2932
const matchNormalizer = makeNormalizer({collapseWhitespace, trim, normalizer})
3033

@@ -37,27 +40,32 @@ function queryAllLabelsByText(
3740
.map(({node}) => node)
3841
}
3942

40-
function queryAllByLabelText(
43+
const queryAllByLabelText: AllByText = (
4144
container,
4245
text,
4346
{selector = '*', exact = true, collapseWhitespace, trim, normalizer} = {},
44-
) {
47+
) => {
4548
checkContainerType(container)
4649

4750
const matcher = exact ? matches : fuzzyMatches
4851
const matchNormalizer = makeNormalizer({collapseWhitespace, trim, normalizer})
49-
const matchingLabelledElements = Array.from(container.querySelectorAll('*'))
52+
const matchingLabelledElements = Array.from(
53+
container.querySelectorAll<HTMLElement>('*'),
54+
)
5055
.filter(element => {
5156
return (
5257
getRealLabels(element).length || element.hasAttribute('aria-labelledby')
5358
)
5459
})
55-
.reduce((labelledElements, labelledElement) => {
60+
.reduce<HTMLElement[]>((labelledElements, labelledElement) => {
5661
const labelList = getLabels(container, labelledElement, {selector})
5762
labelList
5863
.filter(label => Boolean(label.formControl))
5964
.forEach(label => {
60-
if (matcher(label.content, label.formControl, text, matchNormalizer))
65+
if (
66+
matcher(label.content, label.formControl, text, matchNormalizer) &&
67+
label.formControl
68+
)
6169
labelledElements.push(label.formControl)
6270
})
6371
const labelsValue = labelList
@@ -92,6 +100,9 @@ function queryAllByLabelText(
92100
return labelledElements
93101
}, [])
94102
.concat(
103+
// TODO: Remove ignore after `queryAllByAttribute` will be moved to TS
104+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
105+
// @ts-expect-error
95106
queryAllByAttribute('aria-label', container, text, {
96107
exact,
97108
normalizer: matchNormalizer,
@@ -110,7 +121,7 @@ function queryAllByLabelText(
110121
// )
111122
// however, we can give a more helpful error message than the generic one,
112123
// so we're writing this one out by hand.
113-
const getAllByLabelText = (container, text, ...rest) => {
124+
const getAllByLabelText: AllByText = (container, text, ...rest) => {
114125
const els = queryAllByLabelText(container, text, ...rest)
115126
if (!els.length) {
116127
const labels = queryAllLabelsByText(container, text, ...rest)
@@ -146,7 +157,10 @@ const getAllByLabelText = (container, text, ...rest) => {
146157
return els
147158
}
148159

149-
function getTagNameOfElementAssociatedWithLabelViaFor(container, label) {
160+
function getTagNameOfElementAssociatedWithLabelViaFor(
161+
container: Element,
162+
label: Element,
163+
): Nullish<string> {
150164
const htmlFor = label.getAttribute('for')
151165
if (!htmlFor) {
152166
return null
@@ -157,7 +171,7 @@ function getTagNameOfElementAssociatedWithLabelViaFor(container, label) {
157171
}
158172

159173
// the reason mentioned above is the same reason we're not using buildQueries
160-
const getMultipleError = (c, text) =>
174+
const getMultipleError: GetErrorFunction = (c, text) =>
161175
`Found multiple elements with the text of: ${text}`
162176
const queryByLabelText = wrapSingleQueryWithSuggestion(
163177
makeSingleQuery(queryAllByLabelText, getMultipleError),

src/queries/placeholder-text.js renamed to src/queries/placeholder-text.ts

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
import {wrapAllByQueryWithSuggestion} from '../query-helpers'
22
import {checkContainerType} from '../helpers'
3+
import {AllByBoundAttribute, GetErrorFunction} from '../../types'
34
import {queryAllByAttribute, buildQueries} from './all-utils'
45

5-
function queryAllByPlaceholderText(...args) {
6-
checkContainerType(...args)
6+
const queryAllByPlaceholderText: AllByBoundAttribute = (...args) => {
7+
checkContainerType(args[0])
8+
// TODO: Remove ignore after `queryAllByAttribute` will be moved to TS
9+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
10+
// @ts-expect-error
711
return queryAllByAttribute('placeholder', ...args)
812
}
9-
const getMultipleError = (c, text) =>
13+
const getMultipleError: GetErrorFunction = (c, text) =>
1014
`Found multiple elements with the placeholder text of: ${text}`
11-
const getMissingError = (c, text) =>
15+
const getMissingError: GetErrorFunction = (c, text) =>
1216
`Unable to find an element with the placeholder text of: ${text}`
1317

1418
const queryAllByPlaceholderTextWithSuggestions = wrapAllByQueryWithSuggestion(

src/queries/test-id.js renamed to src/queries/test-id.ts

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
import {checkContainerType} from '../helpers'
22
import {wrapAllByQueryWithSuggestion} from '../query-helpers'
3+
import {AllByBoundAttribute, GetErrorFunction} from '../../types'
34
import {queryAllByAttribute, getConfig, buildQueries} from './all-utils'
45

56
const getTestIdAttribute = () => getConfig().testIdAttribute
67

7-
function queryAllByTestId(...args) {
8-
checkContainerType(...args)
8+
const queryAllByTestId: AllByBoundAttribute = (...args) => {
9+
checkContainerType(args[0])
10+
// TODO: Remove ignore after `queryAllByAttribute` will be moved to TS
11+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
12+
// @ts-expect-error
913
return queryAllByAttribute(getTestIdAttribute(), ...args)
1014
}
1115

12-
const getMultipleError = (c, id) =>
16+
const getMultipleError: GetErrorFunction = (c, id) =>
1317
`Found multiple elements by: [${getTestIdAttribute()}="${id}"]`
14-
const getMissingError = (c, id) =>
18+
const getMissingError: GetErrorFunction = (c, id) =>
1519
`Unable to find an element by: [${getTestIdAttribute()}="${id}"]`
1620

1721
const queryAllByTestIdWithSuggestions = wrapAllByQueryWithSuggestion(

src/queries/text.js renamed to src/queries/text.ts

+15-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {wrapAllByQueryWithSuggestion} from '../query-helpers'
22
import {checkContainerType} from '../helpers'
33
import {DEFAULT_IGNORE_TAGS} from '../config'
4+
import {AllByText, GetErrorFunction} from '../../types'
45
import {
56
fuzzyMatches,
67
matches,
@@ -9,7 +10,7 @@ import {
910
buildQueries,
1011
} from './all-utils'
1112

12-
function queryAllByText(
13+
const queryAllByText: AllByText = (
1314
container,
1415
text,
1516
{
@@ -20,22 +21,28 @@ function queryAllByText(
2021
ignore = DEFAULT_IGNORE_TAGS,
2122
normalizer,
2223
} = {},
23-
) {
24+
) => {
2425
checkContainerType(container)
2526
const matcher = exact ? matches : fuzzyMatches
2627
const matchNormalizer = makeNormalizer({collapseWhitespace, trim, normalizer})
27-
let baseArray = []
28+
let baseArray: HTMLElement[] = []
2829
if (typeof container.matches === 'function' && container.matches(selector)) {
2930
baseArray = [container]
3031
}
31-
return [...baseArray, ...Array.from(container.querySelectorAll(selector))]
32-
.filter(node => !ignore || !node.matches(ignore))
33-
.filter(node => matcher(getNodeText(node), node, text, matchNormalizer))
32+
return (
33+
[
34+
...baseArray,
35+
...Array.from(container.querySelectorAll<HTMLElement>(selector)),
36+
]
37+
// TODO: `matches` according lib.dom.d.ts can get only `string` but according our code it can handle also boolean :)
38+
.filter(node => !ignore || !node.matches(ignore as string))
39+
.filter(node => matcher(getNodeText(node), node, text, matchNormalizer))
40+
)
3441
}
3542

36-
const getMultipleError = (c, text) =>
43+
const getMultipleError: GetErrorFunction = (c, text) =>
3744
`Found multiple elements with the text: ${text}`
38-
const getMissingError = (c, text) =>
45+
const getMissingError: GetErrorFunction = (c, text) =>
3946
`Unable to find an element with the text: ${text}. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.`
4047

4148
const queryAllByTextWithSuggestions = wrapAllByQueryWithSuggestion(

0 commit comments

Comments
 (0)