Skip to content

Commit 8b29d43

Browse files
author
Kent C. Dodds
authored
feat(findBy*): adds findBy* query type allowing for async element queries (#224)
* feat(findBy*): adds findBy* query type allowing for async element queries Closes #203 * undo something * add a real async test
1 parent df8863f commit 8b29d43

11 files changed

+164
-13
lines changed

src/__tests__/element-queries.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import 'jest-dom/extend-expect'
21
import {configure} from '../config'
32
import {render, renderIntoDocument} from './helpers/test-utils'
43

src/__tests__/example.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
// query utilities:
22
import {getByLabelText, getByText, getByTestId, queryByTestId, wait} from '../'
3-
// adds special assertions like toHaveTextContent
4-
import 'jest-dom/extend-expect'
53

64
function getExampleDOM() {
75
// This is just a raw example of setting up some DOM

src/__tests__/helpers/test-utils.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import {getQueriesForElement} from '../../get-queries-for-element'
22

3-
function render(html) {
4-
const container = document.createElement('div')
3+
function render(html, {container = document.createElement('div')} = {}) {
54
container.innerHTML = html
65
const containerQueries = getQueriesForElement(container)
7-
return {container, ...containerQueries}
6+
function rerender(newHtml) {
7+
return render(newHtml, {container})
8+
}
9+
return {container, rerender, ...containerQueries}
810
}
911

1012
function renderIntoDocument(html) {

src/__tests__/queries.find.js

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import {render} from './helpers/test-utils'
2+
3+
test('find asynchronously finds elements', async () => {
4+
const {
5+
findByLabelText,
6+
findAllByLabelText,
7+
8+
findByPlaceholderText,
9+
findAllByPlaceholderText,
10+
11+
findByText,
12+
findAllByText,
13+
14+
findByAltText,
15+
findAllByAltText,
16+
17+
findByTitle,
18+
findAllByTitle,
19+
20+
findByDisplayValue,
21+
findAllByDisplayValue,
22+
23+
findByRole,
24+
findAllByRole,
25+
26+
findByTestId,
27+
findAllByTestId,
28+
} = render(`
29+
<div>
30+
<div data-testid="test-id" aria-label="test-label">test text content</div>
31+
<select><option>display value</option></select>
32+
<input placeholder="placeholder" />
33+
<img alt="test alt text" src="/lucy-ricardo.png" />
34+
<span title="test title" />
35+
<div role="dialog"></div>
36+
</div>
37+
`)
38+
await expect(findByLabelText('test-label')).resolves.toBeTruthy()
39+
await expect(findAllByLabelText('test-label')).resolves.toHaveLength(1)
40+
41+
await expect(findByPlaceholderText('placeholder')).resolves.toBeTruthy()
42+
await expect(findAllByPlaceholderText('placeholder')).resolves.toHaveLength(1)
43+
44+
await expect(findByText('test text content')).resolves.toBeTruthy()
45+
await expect(findAllByText('test text content')).resolves.toHaveLength(1)
46+
47+
await expect(findByAltText('test alt text')).resolves.toBeTruthy()
48+
await expect(findAllByAltText('test alt text')).resolves.toHaveLength(1)
49+
50+
await expect(findByTitle('test title')).resolves.toBeTruthy()
51+
await expect(findAllByTitle('test title')).resolves.toHaveLength(1)
52+
53+
await expect(findByDisplayValue('display value')).resolves.toBeTruthy()
54+
await expect(findAllByDisplayValue('display value')).resolves.toHaveLength(1)
55+
56+
await expect(findByRole('dialog')).resolves.toBeTruthy()
57+
await expect(findAllByRole('dialog')).resolves.toHaveLength(1)
58+
59+
await expect(findByTestId('test-id')).resolves.toBeTruthy()
60+
await expect(findAllByTestId('test-id')).resolves.toHaveLength(1)
61+
})
62+
63+
test('find rejects when something cannot be found', async () => {
64+
const {
65+
findByLabelText,
66+
findAllByLabelText,
67+
68+
findByPlaceholderText,
69+
findAllByPlaceholderText,
70+
71+
findByText,
72+
findAllByText,
73+
74+
findByAltText,
75+
findAllByAltText,
76+
77+
findByTitle,
78+
findAllByTitle,
79+
80+
findByDisplayValue,
81+
findAllByDisplayValue,
82+
83+
findByRole,
84+
findAllByRole,
85+
86+
findByTestId,
87+
findAllByTestId,
88+
} = render(`<div />`)
89+
90+
// I just don't want multiple lines for these.
91+
// qo = queryOptions
92+
// wo = waitForElementOptions
93+
const qo = {} // query options
94+
const wo = {timeout: 10} // wait options
95+
96+
await expect(findByLabelText('x', qo, wo)).rejects.toThrow('x')
97+
await expect(findAllByLabelText('x', qo, wo)).rejects.toThrow('x')
98+
99+
await expect(findByPlaceholderText('x', qo, wo)).rejects.toThrow('x')
100+
await expect(findAllByPlaceholderText('x', qo, wo)).rejects.toThrow('x')
101+
102+
await expect(findByText('x', qo, wo)).rejects.toThrow('x')
103+
await expect(findAllByText('x', qo, wo)).rejects.toThrow('x')
104+
105+
await expect(findByAltText('x', qo, wo)).rejects.toThrow('x')
106+
await expect(findAllByAltText('x', qo, wo)).rejects.toThrow('x')
107+
108+
await expect(findByTitle('x', qo, wo)).rejects.toThrow('x')
109+
await expect(findAllByTitle('x', qo, wo)).rejects.toThrow('x')
110+
111+
await expect(findByDisplayValue('x', qo, wo)).rejects.toThrow('x')
112+
await expect(findAllByDisplayValue('x', qo, wo)).rejects.toThrow('x')
113+
114+
await expect(findByRole('x', qo, wo)).rejects.toThrow('x')
115+
await expect(findAllByRole('x', qo, wo)).rejects.toThrow('x')
116+
117+
await expect(findByTestId('x', qo, wo)).rejects.toThrow('x')
118+
await expect(findAllByTestId('x', qo, wo)).rejects.toThrow('x')
119+
})
120+
121+
test('actually works with async code', async () => {
122+
const {findByTestId, container, rerender} = render(`<div />`)
123+
setTimeout(() => rerender(`<div data-testid="div">correct dom</div>`), 20)
124+
await expect(findByTestId('div', {}, {container})).resolves.toBeTruthy()
125+
})

src/__tests__/text-matchers.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import 'jest-dom/extend-expect'
21
import cases from 'jest-in-case'
32

43
import {getDefaultNormalizer} from '../'

src/__tests__/wait-for-dom-change.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
import {waitForDomChange} from '../'
2-
// adds special assertions like toBeTruthy
3-
import 'jest-dom/extend-expect'
42
import {render} from './helpers/test-utils'
53

64
const skipSomeTime = delayMs =>

src/__tests__/wait-for-element-to-be-removed.fake-timers.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import 'jest-dom/extend-expect'
21
import {waitForElementToBeRemoved} from '../'
32
import {render} from './helpers/test-utils'
43

src/__tests__/wait-for-element-to-be-removed.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import 'jest-dom/extend-expect'
21
import {waitForElementToBeRemoved} from '../'
32
import {renderIntoDocument} from './helpers/test-utils'
43

src/__tests__/wait-for-element.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
import {waitForElement, wait} from '../'
2-
// adds special assertions like toBeTruthy
3-
import 'jest-dom/extend-expect'
42
import {render} from './helpers/test-utils'
53

64
const skipSomeTime = delayMs =>

src/queries.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
queryAllByAttribute,
77
queryByAttribute,
88
} from './query-helpers'
9+
import {waitForElement} from './wait-for-element'
910
import {getConfig} from './config'
1011

1112
// Here are the queries for the library.
@@ -375,6 +376,38 @@ function getByDisplayValue(...args) {
375376
return firstResultOrNull(getAllByDisplayValue, ...args)
376377
}
377378

379+
function makeFinder(getter) {
380+
return (container, text, options, waitForElementOptions) =>
381+
waitForElement(
382+
() => getter(container, text, options),
383+
waitForElementOptions,
384+
)
385+
}
386+
387+
export const findByLabelText = makeFinder(getByLabelText)
388+
export const findAllByLabelText = makeFinder(getAllByLabelText)
389+
390+
export const findByPlaceholderText = makeFinder(getByPlaceholderText)
391+
export const findAllByPlaceholderText = makeFinder(getAllByPlaceholderText)
392+
393+
export const findByText = makeFinder(getByText)
394+
export const findAllByText = makeFinder(getAllByText)
395+
396+
export const findByAltText = makeFinder(getByAltText)
397+
export const findAllByAltText = makeFinder(getAllByAltText)
398+
399+
export const findByTitle = makeFinder(getByTitle)
400+
export const findAllByTitle = makeFinder(getAllByTitle)
401+
402+
export const findByDisplayValue = makeFinder(getByDisplayValue)
403+
export const findAllByDisplayValue = makeFinder(getAllByDisplayValue)
404+
405+
export const findByRole = makeFinder(getByRole)
406+
export const findAllByRole = makeFinder(getAllByRole)
407+
408+
export const findByTestId = makeFinder(getByTestId)
409+
export const findAllByTestId = makeFinder(getAllByTestId)
410+
378411
export {
379412
queryByPlaceholderText,
380413
queryAllByPlaceholderText,

tests/setup-env.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import 'jest-dom/extend-expect'

0 commit comments

Comments
 (0)