Skip to content

Commit 9a19474

Browse files
eunjae-leeKent C. Dodds
authored and
Kent C. Dodds
committed
feat(queryByCurrentValue): add get/query by current value (testing-library#169)
* feat(queryByCurrentValue): add get/query by current value * feat(queryByCurrentValue): exports (query|get)AllByCurrentValue * chore: change the order of exports * fix: add implementation for `select` element at `queryAllByCurrentValue` * chore: add tests for get/queryByCurrentValue * chore: add test for getAllByCurrentValue to throw * chore: rename xxxByCurrentValue -> xxxByDisplayValue * docs: add `getByDisplayValue` * docs: add `eunjae-lee` as a contributor * docs: remove `getByAltText`, `getByTitle` and `getByValue` * docs: update `getByDisplayValue` * chore: add test for 100% coverage * docs: remove unnecessary `console.log(...)` * Revert "docs: remove `getByAltText`, `getByTitle` and `getByValue`" This reverts commit c960865af18f2ecc81a6770806eef95cc7dd89f7. * docs: remove `getBySelectText` and `getByValue` * docs: update description on `getByDisplayName`
1 parent ce79c72 commit 9a19474

File tree

4 files changed

+154
-38
lines changed

4 files changed

+154
-38
lines changed

.all-contributorsrc

+9
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,15 @@
440440
"contributions": [
441441
"code"
442442
]
443+
},
444+
{
445+
"login": "eunjae-lee",
446+
"name": "Eunjae Lee",
447+
"avatar_url": "https://avatars3.githubusercontent.com/u/499898?v=4",
448+
"profile": "https://twitter.com/eunjae_lee",
449+
"contributions": [
450+
"code"
451+
]
443452
}
444453
]
445454
}

README.md

+36-38
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
[![downloads][downloads-badge]][npmtrends]
1818
[![MIT License][license-badge]][license]
1919

20-
[![All Contributors](https://img.shields.io/badge/all_contributors-44-orange.svg?style=flat-square)](#contributors)
20+
[![All Contributors](https://img.shields.io/badge/all_contributors-45-orange.svg?style=flat-square)](#contributors)
2121
[![PRs Welcome][prs-badge]][prs]
2222
[![Code of Conduct][coc-badge]][coc]
2323

@@ -81,11 +81,10 @@ when a real user uses it.
8181
- [Usage](#usage)
8282
- [`getByLabelText`](#getbylabeltext)
8383
- [`getByPlaceholderText`](#getbyplaceholdertext)
84-
- [`getBySelectText`](#getbyselecttext)
8584
- [`getByText`](#getbytext)
8685
- [`getByAltText`](#getbyalttext)
8786
- [`getByTitle`](#getbytitle)
88-
- [`getByValue`](#getbyvalue)
87+
- [`getByDisplayValue`](#getbydisplayvalue)
8988
- [`getByRole`](#getbyrole)
9089
- [`getByTestId`](#getbytestid)
9190
- [`wait`](#wait)
@@ -276,35 +275,6 @@ const inputNode = getByPlaceholderText(container, 'Username')
276275
> NOTE: a placeholder is not a good substitute for a label so you should
277276
> generally use `getByLabelText` instead.
278277
279-
### `getBySelectText`
280-
281-
```typescript
282-
getBySelectText(
283-
container: HTMLElement,
284-
text: TextMatch,
285-
options?: {
286-
exact?: boolean = true,
287-
collapseWhitespace?: boolean = true,
288-
trim?: boolean = true,
289-
}): HTMLElement
290-
```
291-
292-
This will search for a `<select>` whose selected `<option>` matches the given [`TextMatch`](#textmatch). This would find the `<select>` node in a situation
293-
where the first value acts as a sort of placeholder for the dropdown.
294-
295-
```javascript
296-
// <select>
297-
// <option value="">Day of the Week</option>
298-
// <option value="1">Monday</option>
299-
// <option value="2">Tuesday</option>
300-
// <option value="3">Wednesday</option>
301-
// </select>
302-
const selectNode = getBySelectText(container, 'Day of the Week')
303-
```
304-
305-
> Note: It is highly preferred to use `getByLabelText` over this method. This
306-
> method should only be used in the event where there is no label text available.
307-
308278
### `getByText`
309279

310280
```typescript
@@ -390,10 +360,10 @@ Will also find a `title` element within an SVG.
390360
const closeElement = getByTitle(container, 'Close')
391361
```
392362

393-
### `getByValue`
363+
### `getByDisplayValue`
394364

395365
```typescript
396-
getByValue(
366+
getByDisplayValue(
397367
container: HTMLElement,
398368
value: TextMatch,
399369
options?: {
@@ -403,13 +373,41 @@ getByValue(
403373
}): HTMLElement
404374
```
405375

406-
Returns the element that has the matching value.
376+
Returns the `input`, `textarea`, or `select` element that has the matching display value.
377+
378+
#### `input`
379+
380+
```javascript
381+
// <input type="text" id="lastName" />
382+
// document.getElementById('lastName').value = 'Norris'
383+
384+
const lastNameInput = getByDisplayValue(container, 'Norris')
385+
```
386+
387+
#### `textarea`
407388

408389
```javascript
409-
// <input type="text" id="lastName" defaultValue="Norris" />
410-
const lastNameInput = getByValue('Norris')
390+
// <textarea id="messageTextArea"></textarea>
391+
// document.getElementById('messageTextArea').value = 'Hello World'
392+
393+
const messageTextArea = getByDisplayValue(container, 'Hello World')
411394
```
412395

396+
#### `select`
397+
398+
```javascript
399+
// <select id="state-select" data-testid="state">
400+
// <option value="">State</option>
401+
// <option value="AL">Alabama</option>
402+
// <option selected value="AK" >Alaska</option>
403+
// <option value="AZ">Arizona</option>
404+
// </select>
405+
406+
const selectElement = getByDisplayName(container, 'Alaska')
407+
```
408+
409+
In case of `select`, this will search for a `<select>` whose selected `<option>` matches the given [`TextMatch`](#textmatch).
410+
413411
### `getByRole`
414412

415413
```typescript
@@ -1147,7 +1145,7 @@ Thanks goes to these people ([emoji key][emojis]):
11471145
| [<img src="https://avatars2.githubusercontent.com/u/21689428?v=4" width="100px;"/><br /><sub><b>Jonathan Stoye</b></sub>](http://jonathanstoye.de)<br />[📖](https://github.com/kentcdodds/dom-testing-library/commits?author=JonathanStoye "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/4126644?v=4" width="100px;"/><br /><sub><b>Sanghyeon Lee</b></sub>](https://github.com/yongdamsh)<br />[💡](#example-yongdamsh "Examples") | [<img src="https://avatars3.githubusercontent.com/u/8015514?v=4" width="100px;"/><br /><sub><b>Justice Mba </b></sub>](https://github.com/Dajust)<br />[💻](https://github.com/kentcdodds/dom-testing-library/commits?author=Dajust "Code") [📖](https://github.com/kentcdodds/dom-testing-library/commits?author=Dajust "Documentation") [🤔](#ideas-Dajust "Ideas, Planning, & Feedback") | [<img src="https://avatars3.githubusercontent.com/u/340761?v=4" width="100px;"/><br /><sub><b>Wayne Crouch</b></sub>](https://github.com/wgcrouch)<br />[💻](https://github.com/kentcdodds/dom-testing-library/commits?author=wgcrouch "Code") | [<img src="https://avatars1.githubusercontent.com/u/4996462?v=4" width="100px;"/><br /><sub><b>Ben Elliott</b></sub>](http://benjaminelliott.co.uk)<br />[💻](https://github.com/kentcdodds/dom-testing-library/commits?author=benelliott "Code") | [<img src="https://avatars3.githubusercontent.com/u/577921?v=4" width="100px;"/><br /><sub><b>Ruben Costa</b></sub>](http://nuances.co)<br />[💻](https://github.com/kentcdodds/dom-testing-library/commits?author=rubencosta "Code") | [<img src="https://avatars2.githubusercontent.com/u/4982001?v=4" width="100px;"/><br /><sub><b>Robert Smith</b></sub>](http://rbrtsmith.com/)<br />[🐛](https://github.com/kentcdodds/dom-testing-library/issues?q=author%3Arbrtsmith "Bug reports") [🤔](#ideas-rbrtsmith "Ideas, Planning, & Feedback") [📖](https://github.com/kentcdodds/dom-testing-library/commits?author=rbrtsmith "Documentation") |
11481146
| [<img src="https://avatars3.githubusercontent.com/u/881986?v=4" width="100px;"/><br /><sub><b>dadamssg</b></sub>](https://github.com/dadamssg)<br />[💻](https://github.com/kentcdodds/dom-testing-library/commits?author=dadamssg "Code") | [<img src="https://avatars1.githubusercontent.com/u/186971?v=4" width="100px;"/><br /><sub><b>Neil Kistner</b></sub>](https://neilkistner.com/)<br />[💻](https://github.com/kentcdodds/dom-testing-library/commits?author=wyze "Code") | [<img src="https://avatars3.githubusercontent.com/u/1448597?v=4" width="100px;"/><br /><sub><b>Ben Chauvette</b></sub>](http://bdchauvette.net/)<br />[💻](https://github.com/kentcdodds/dom-testing-library/commits?author=bdchauvette "Code") | [<img src="https://avatars2.githubusercontent.com/u/777527?v=4" width="100px;"/><br /><sub><b>Jeff Baumgardt</b></sub>](https://github.com/JeffBaumgardt)<br />[💻](https://github.com/kentcdodds/dom-testing-library/commits?author=JeffBaumgardt "Code") [📖](https://github.com/kentcdodds/dom-testing-library/commits?author=JeffBaumgardt "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/4658208?v=4" width="100px;"/><br /><sub><b>Matan Kushner</b></sub>](http://matchai.me)<br />[💻](https://github.com/kentcdodds/dom-testing-library/commits?author=matchai "Code") [📖](https://github.com/kentcdodds/dom-testing-library/commits?author=matchai "Documentation") [🤔](#ideas-matchai "Ideas, Planning, & Feedback") [⚠️](https://github.com/kentcdodds/dom-testing-library/commits?author=matchai "Tests") | [<img src="https://avatars2.githubusercontent.com/u/5779538?v=4" width="100px;"/><br /><sub><b>Alex Wendte</b></sub>](http://www.wendtedesigns.com/)<br />[💻](https://github.com/kentcdodds/dom-testing-library/commits?author=themostcolm "Code") [📖](https://github.com/kentcdodds/dom-testing-library/commits?author=themostcolm "Documentation") [⚠️](https://github.com/kentcdodds/dom-testing-library/commits?author=themostcolm "Tests") | [<img src="https://avatars0.githubusercontent.com/u/2196208?v=4" width="100px;"/><br /><sub><b>Tamas Fodor</b></sub>](https://github.com/ruffle1986)<br />[📖](https://github.com/kentcdodds/dom-testing-library/commits?author=ruffle1986 "Documentation") |
11491147
| [<img src="https://avatars3.githubusercontent.com/u/14793495?v=4" width="100px;"/><br /><sub><b>Benjamin Eckardt</b></sub>](https://github.com/BenjaminEckardt)<br />[💻](https://github.com/kentcdodds/dom-testing-library/commits?author=BenjaminEckardt "Code") | [<img src="https://avatars3.githubusercontent.com/u/205752?v=4" width="100px;"/><br /><sub><b>Ryan Campbell</b></sub>](https://github.com/campbellr)<br />[📖](https://github.com/kentcdodds/dom-testing-library/commits?author=campbellr "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/1335519?v=4" width="100px;"/><br /><sub><b>Taylor Briggs</b></sub>](https://taylor-briggs.com)<br />[⚠️](https://github.com/kentcdodds/dom-testing-library/commits?author=TaylorBriggs "Tests") | [<img src="https://avatars2.githubusercontent.com/u/132233?v=4" width="100px;"/><br /><sub><b>John Gozde</b></sub>](https://github.com/jgoz)<br />[💻](https://github.com/kentcdodds/dom-testing-library/commits?author=jgoz "Code") | [<img src="https://avatars2.githubusercontent.com/u/3382565?v=4" width="100px;"/><br /><sub><b>C. T. Lin</b></sub>](https://github.com/chentsulin)<br />[📖](https://github.com/kentcdodds/dom-testing-library/commits?author=chentsulin "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/5312329?v=4" width="100px;"/><br /><sub><b>Terrence Wong</b></sub>](http://terrencewwong.com)<br />[💻](https://github.com/kentcdodds/dom-testing-library/commits?author=terrencewwong "Code") | [<img src="https://avatars0.githubusercontent.com/u/12230408?v=4" width="100px;"/><br /><sub><b>Soo Jae Hwang</b></sub>](https://www.ossfinder.com)<br />[💻](https://github.com/kentcdodds/dom-testing-library/commits?author=misoguy "Code") |
1150-
| [<img src="https://avatars0.githubusercontent.com/u/19773?v=4" width="100px;"/><br /><sub><b>Royston Shufflebotham</b></sub>](https://github.com/RoystonS)<br />[🐛](https://github.com/kentcdodds/dom-testing-library/issues?q=author%3ARoystonS "Bug reports") [💻](https://github.com/kentcdodds/dom-testing-library/commits?author=RoystonS "Code") [📖](https://github.com/kentcdodds/dom-testing-library/commits?author=RoystonS "Documentation") [⚠️](https://github.com/kentcdodds/dom-testing-library/commits?author=RoystonS "Tests") | [<img src="https://avatars0.githubusercontent.com/u/591673?v=4" width="100px;"/><br /><sub><b>Vadim Brodsky</b></sub>](http://www.vadimbrodsky.com)<br />[💻](https://github.com/kentcdodds/dom-testing-library/commits?author=VadimBrodsky "Code") |
1148+
| [<img src="https://avatars0.githubusercontent.com/u/19773?v=4" width="100px;"/><br /><sub><b>Royston Shufflebotham</b></sub>](https://github.com/RoystonS)<br />[🐛](https://github.com/kentcdodds/dom-testing-library/issues?q=author%3ARoystonS "Bug reports") [💻](https://github.com/kentcdodds/dom-testing-library/commits?author=RoystonS "Code") [📖](https://github.com/kentcdodds/dom-testing-library/commits?author=RoystonS "Documentation") [⚠️](https://github.com/kentcdodds/dom-testing-library/commits?author=RoystonS "Tests") | [<img src="https://avatars0.githubusercontent.com/u/591673?v=4" width="100px;"/><br /><sub><b>Vadim Brodsky</b></sub>](http://www.vadimbrodsky.com)<br />[💻](https://github.com/kentcdodds/dom-testing-library/commits?author=VadimBrodsky "Code") | [<img src="https://avatars3.githubusercontent.com/u/499898?v=4" width="100px;"/><br /><sub><b>Eunjae Lee</b></sub>](https://twitter.com/eunjae_lee)<br />[💻](https://github.com/kentcdodds/dom-testing-library/commits?author=eunjae-lee "Code") |
11511149

11521150
<!-- ALL-CONTRIBUTORS-LIST:END -->
11531151

src/__tests__/element-queries.js

+63
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,7 @@ test('getAll* matchers throw for 0 matches', () => {
347347
getAllByPlaceholderText,
348348
getAllByText,
349349
getAllByRole,
350+
getAllByDisplayValue,
350351
} = render(`
351352
<div role="container">
352353
<label>No Matches Please</label>
@@ -361,6 +362,7 @@ test('getAll* matchers throw for 0 matches', () => {
361362
expect(() => getAllByPlaceholderText('nope')).toThrow()
362363
expect(() => getAllByText('nope')).toThrow()
363364
expect(() => getAllByRole('nope')).toThrow()
365+
expect(() => getAllByDisplayValue('nope')).toThrow()
364366
})
365367

366368
test('queryAll* matchers return an array for 0 matches', () => {
@@ -565,4 +567,65 @@ test('getByText ignores script tags by default', () => {
565567
expect(getAllByText(/hello/i, {ignore: false})).toHaveLength(3)
566568
})
567569

570+
test('get/query input element by current value', () => {
571+
const {
572+
getByDisplayValue,
573+
queryByDisplayValue,
574+
getByTestId,
575+
} = renderIntoDocument(`
576+
<div>
577+
<input placeholder="name" type="text" data-testid="name" value="Mercury" />
578+
</div>
579+
`)
580+
expect(getByDisplayValue('Mercury').placeholder).toEqual('name')
581+
expect(queryByDisplayValue('Mercury').placeholder).toEqual('name')
582+
583+
getByTestId('name').value = 'Norris'
584+
expect(getByDisplayValue('Norris').placeholder).toEqual('name')
585+
expect(queryByDisplayValue('Norris').placeholder).toEqual('name')
586+
587+
expect(queryByDisplayValue('Nor', {exact: false}).placeholder).toEqual('name')
588+
})
589+
590+
test('get/query select element by current value', () => {
591+
const {
592+
getByDisplayValue,
593+
queryByDisplayValue,
594+
getByTestId,
595+
} = renderIntoDocument(`
596+
<select id="state-select" data-testid="state">
597+
<option value="">State</option>
598+
<option value="AL">Alabama</option>
599+
<option selected value="AK" >Alaska</option>
600+
<option value="AZ">Arizona</option>
601+
</select>
602+
`)
603+
604+
expect(getByDisplayValue('Alaska').id).toEqual('state-select')
605+
expect(queryByDisplayValue('Alaska').id).toEqual('state-select')
606+
607+
getByTestId('state').value = 'AL'
608+
expect(getByDisplayValue('Alabama').id).toEqual('state-select')
609+
expect(queryByDisplayValue('Alabama').id).toEqual('state-select')
610+
})
611+
612+
test('get/query textarea element by current value', () => {
613+
const {
614+
getByDisplayValue,
615+
queryByDisplayValue,
616+
getByTestId,
617+
} = renderIntoDocument(`
618+
<textarea id="content-textarea" data-testid="content">
619+
Hello
620+
</textarea>
621+
`)
622+
623+
expect(getByDisplayValue('Hello').id).toEqual('content-textarea')
624+
expect(queryByDisplayValue('Hello').id).toEqual('content-textarea')
625+
626+
getByTestId('content').value = 'World'
627+
expect(getByDisplayValue('World').id).toEqual('content-textarea')
628+
expect(queryByDisplayValue('World').id).toEqual('content-textarea')
629+
})
630+
568631
/* eslint jsx-a11y/label-has-for:0 */

src/queries.js

+46
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,33 @@ function queryByAltText(...args) {
180180
return firstResultOrNull(queryAllByAltText, ...args)
181181
}
182182

183+
function queryAllByDisplayValue(
184+
container,
185+
value,
186+
{exact = true, collapseWhitespace = true, trim = true} = {},
187+
) {
188+
const matcher = exact ? matches : fuzzyMatches
189+
const matchOpts = {collapseWhitespace, trim}
190+
return Array.from(container.querySelectorAll(`input,textarea,select`)).filter(
191+
node => {
192+
if (node.tagName === 'SELECT') {
193+
const selectedOptions = Array.from(node.options).filter(
194+
option => option.selected,
195+
)
196+
return selectedOptions.some(optionNode =>
197+
matcher(getNodeText(optionNode), optionNode, value, matchOpts),
198+
)
199+
} else {
200+
return matcher(node.value, node, value, matchOpts)
201+
}
202+
},
203+
)
204+
}
205+
206+
function queryByDisplayValue(...args) {
207+
return firstResultOrNull(queryAllByDisplayValue, ...args)
208+
}
209+
183210
// getters
184211
// the reason we're not dynamically generating these functions that look so similar:
185212
// 1. The error messages are specific to each one and depend on arguments
@@ -325,6 +352,21 @@ function getBySelectText(...args) {
325352
return firstResultOrNull(getAllBySelectText, ...args)
326353
}
327354

355+
function getAllByDisplayValue(container, value, ...rest) {
356+
const els = queryAllByDisplayValue(container, value, ...rest)
357+
if (!els.length) {
358+
throw getElementError(
359+
`Unable to find an element with the value: ${value}.`,
360+
container,
361+
)
362+
}
363+
return els
364+
}
365+
366+
function getByDisplayValue(...args) {
367+
return firstResultOrNull(getAllByDisplayValue, ...args)
368+
}
369+
328370
export {
329371
queryByPlaceholderText,
330372
queryAllByPlaceholderText,
@@ -358,6 +400,10 @@ export {
358400
queryAllByValue,
359401
getByValue,
360402
getAllByValue,
403+
queryByDisplayValue,
404+
queryAllByDisplayValue,
405+
getByDisplayValue,
406+
getAllByDisplayValue,
361407
queryByRole,
362408
queryAllByRole,
363409
getAllByRole,

0 commit comments

Comments
 (0)