Skip to content

Commit 256f899

Browse files
alexkrolickKent C. Dodds
authored and
Kent C. Dodds
committed
feat(queries): expose helper functions (#66)
These are useful for creating additional queries outside the library
1 parent 2d98da2 commit 256f899

File tree

6 files changed

+103
-67
lines changed

6 files changed

+103
-67
lines changed

src/index.js

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
import {getQueriesForElement} from './get-queries-for-element'
22
import * as queries from './queries'
3-
4-
// exporting on the queries namespace as a convenience
5-
// in addition to exporting the queries themselves
6-
export {queries}
3+
import * as queryHelpers from './query-helpers'
74

85
export * from './queries'
96
export * from './wait'
@@ -12,11 +9,15 @@ export * from './matches'
129
export * from './get-node-text'
1310
export * from './events'
1411
export * from './get-queries-for-element'
12+
export * from './query-helpers'
1513
export * from './pretty-dom'
1614

1715
export {
1816
// The original name of bindElementToQueries was weird
1917
// The new name is better. Remove this in the next major version bump.
2018
getQueriesForElement as bindElementToQueries,
2119
getQueriesForElement as within,
20+
// export query utils under a namespace for convenience:
21+
queries,
22+
queryHelpers,
2223
}

src/queries.js

+6-46
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,16 @@
11
import {fuzzyMatches, matches} from './matches'
22
import {getNodeText} from './get-node-text'
3-
import {prettyDOM} from './pretty-dom'
4-
5-
function debugDOM(htmlElement) {
6-
const limit = process.env.DEBUG_PRINT_LIMIT || 7000
7-
const inNode = typeof process !== 'undefined' && process.versions !== undefined && process.versions.node !== undefined
8-
const inCypress = typeof window !== 'undefined' && window.Cypress
9-
/* istanbul ignore else */
10-
if (inCypress) {
11-
return ''
12-
} else if (inNode) {
13-
return prettyDOM(htmlElement, limit)
14-
} else {
15-
return prettyDOM(htmlElement, limit, {highlight: false})
16-
}
17-
}
18-
19-
function getElementError(message, container) {
20-
return new Error([message, debugDOM(container)].filter(Boolean).join('\n\n'))
21-
}
3+
import {
4+
getElementError,
5+
firstResultOrNull,
6+
queryAllByAttribute,
7+
queryByAttribute,
8+
} from './query-helpers'
229

2310
// Here are the queries for the library.
2411
// The queries here should only be things that are accessible to both users who are using a screen reader
2512
// and those who are not using a screen reader (with the exception of the data-testid attribute query).
2613

27-
function firstResultOrNull(queryFunction, ...args) {
28-
const result = queryFunction(...args)
29-
if (result.length === 0) return null
30-
return result[0]
31-
}
32-
3314
function queryAllLabelsByText(
3415
container,
3516
text,
@@ -101,27 +82,6 @@ function queryByText(...args) {
10182
return firstResultOrNull(queryAllByText, ...args)
10283
}
10384

104-
// this is just a utility and not an exposed query.
105-
// There are no plans to expose this.
106-
function queryAllByAttribute(
107-
attribute,
108-
container,
109-
text,
110-
{exact = true, collapseWhitespace = true, trim = true} = {},
111-
) {
112-
const matcher = exact ? matches : fuzzyMatches
113-
const matchOpts = {collapseWhitespace, trim}
114-
return Array.from(container.querySelectorAll(`[${attribute}]`)).filter(node =>
115-
matcher(node.getAttribute(attribute), node, text, matchOpts),
116-
)
117-
}
118-
119-
// this is just a utility and not an exposed query.
120-
// There are no plans to expose this.
121-
function queryByAttribute(...args) {
122-
return firstResultOrNull(queryAllByAttribute, ...args)
123-
}
124-
12585
const queryByPlaceholderText = queryByAttribute.bind(null, 'placeholder')
12686
const queryAllByPlaceholderText = queryAllByAttribute.bind(null, 'placeholder')
12787
const queryByTestId = queryByAttribute.bind(null, 'data-testid')

src/query-helpers.js

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import {prettyDOM} from './pretty-dom'
2+
import {fuzzyMatches, matches} from './matches'
3+
4+
/* eslint-disable complexity */
5+
function debugDOM(htmlElement) {
6+
const limit = process.env.DEBUG_PRINT_LIMIT || 7000
7+
const inNode =
8+
typeof process !== 'undefined' &&
9+
process.versions !== undefined &&
10+
process.versions.node !== undefined
11+
const inCypress = typeof window !== 'undefined' && window.Cypress
12+
/* istanbul ignore else */
13+
if (inCypress) {
14+
return ''
15+
} else if (inNode) {
16+
return prettyDOM(htmlElement, limit)
17+
} else {
18+
return prettyDOM(htmlElement, limit, {highlight: false})
19+
}
20+
}
21+
/* eslint-enable complexity */
22+
23+
function getElementError(message, container) {
24+
return new Error([message, debugDOM(container)].filter(Boolean).join('\n\n'))
25+
}
26+
27+
function firstResultOrNull(queryFunction, ...args) {
28+
const result = queryFunction(...args)
29+
if (result.length === 0) return null
30+
return result[0]
31+
}
32+
33+
function queryAllByAttribute(
34+
attribute,
35+
container,
36+
text,
37+
{exact = true, collapseWhitespace = true, trim = true} = {},
38+
) {
39+
const matcher = exact ? matches : fuzzyMatches
40+
const matchOpts = {collapseWhitespace, trim}
41+
return Array.from(container.querySelectorAll(`[${attribute}]`)).filter(node =>
42+
matcher(node.getAttribute(attribute), node, text, matchOpts),
43+
)
44+
}
45+
46+
function queryByAttribute(...args) {
47+
return firstResultOrNull(queryAllByAttribute, ...args)
48+
}
49+
50+
export {
51+
debugDOM,
52+
getElementError,
53+
firstResultOrNull,
54+
queryAllByAttribute,
55+
queryByAttribute,
56+
}

typings/index.d.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
// TypeScript Version: 2.8
22
import * as queries from './queries'
3+
import * as queryHelpers from './query-helpers'
34

4-
export {queries}
5+
export {queries, queryHelpers}
56

67
export * from './queries'
8+
export * from './query-helpers'
79
export * from './wait'
810
export * from './wait-for-element'
911
export * from './matches'

typings/queries.d.ts

+5-16
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,9 @@
11
import {Matcher, MatcherOptions} from './matches'
2-
3-
export interface SelectorMatcherOptions extends MatcherOptions {
4-
selector?: string
5-
}
6-
7-
export type QueryByAttribute = (
8-
container: HTMLElement,
9-
id: Matcher,
10-
options?: MatcherOptions,
11-
) => HTMLElement | null
12-
13-
export type AllByAttribute = (
14-
container: HTMLElement,
15-
id: Matcher,
16-
options?: MatcherOptions,
17-
) => HTMLElement[]
2+
import {
3+
QueryByAttribute,
4+
AllByAttribute,
5+
SelectorMatcherOptions,
6+
} from './query-helpers'
187

198
export type GetByAttribute = (
209
container: HTMLElement,

typings/query-helpers.d.ts

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import {Matcher, MatcherOptions} from './matches'
2+
3+
export interface SelectorMatcherOptions extends MatcherOptions {
4+
selector?: string
5+
}
6+
7+
export type QueryByAttribute = (
8+
container: HTMLElement,
9+
id: Matcher,
10+
options?: MatcherOptions,
11+
) => HTMLElement | null
12+
13+
export type AllByAttribute = (
14+
container: HTMLElement,
15+
id: Matcher,
16+
options?: MatcherOptions,
17+
) => HTMLElement[]
18+
19+
export const queryByAttribute: QueryByAttribute
20+
export const queryAllByAttribute: AllByAttribute
21+
export const firstResultOrNull: (
22+
fn: AllByAttribute,
23+
container?: HTMLElement,
24+
id?: Matcher,
25+
options?: MatcherOptions,
26+
) => HTMLElement | null
27+
export const debugDOM: (htmlElement: HTMLElement) => string
28+
export const getElementError: (message: string, container: HTMLElement) => Error

0 commit comments

Comments
 (0)