Skip to content

Commit

Permalink
feat(getByRole): add queries for dom attriburte role (#94)
Browse files Browse the repository at this point in the history
**What**: Add queries for role dom attribute

<!-- Why are these changes necessary? -->

**Why**: As evidenced by [testing-library/jest-dom#55](testing-library/jest-dom#55) having a role attribute query would be helpful when attempting to get elements that don't fit the other queries.

My example was a dialog who did not have any other matching queries and due to the associated library. I was able to add data-testid but that added the attribute too low in the generated dom not to the container root as expected, this is a problem with the library not dom-testing-library.

<!-- How were these changes implemented? -->

**How**: I added new query selectors for the node attribute.

<!-- Have you done all of these things?  -->

**Checklist**:

<!-- add "N/A" to the end of each line that's irrelevant to your changes -->

<!-- to check an item, place an "x" in the box like so: "- [x] Documentation" -->

- [x] Documentation
- [x] Tests
- [x] Ready to be merged <!-- In your opinion, is this ready to be merged as soon as it's reviewed? -->
- [x] Added myself to contributors table <!-- this is optional, see the contributing guidelines for instructions -->

<!-- feel free to add additional comments -->
  • Loading branch information
JeffBaumgardt authored and Kent C. Dodds committed Sep 4, 2018
1 parent 98c67e2 commit fe02135
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 4 deletions.
10 changes: 10 additions & 0 deletions .all-contributorsrc
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,16 @@
"contributions": [
"code"
]
},
{
"login": "JeffBaumgardt",
"name": "Jeff Baumgardt",
"avatar_url": "https://avatars2.githubusercontent.com/u/777527?v=4",
"profile": "https://github.com/JeffBaumgardt",
"contributions": [
"code",
"doc"
]
}
]
}
25 changes: 23 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
[![downloads][downloads-badge]][npmtrends]
[![MIT License][license-badge]][license]

[![All Contributors](https://img.shields.io/badge/all_contributors-31-orange.svg?style=flat-square)](#contributors)
[![All Contributors](https://img.shields.io/badge/all_contributors-32-orange.svg?style=flat-square)](#contributors)
[![PRs Welcome][prs-badge]][prs]
[![Code of Conduct][coc-badge]][coc]

Expand Down Expand Up @@ -351,6 +351,27 @@ Returns the element that has the matching value.
const lastNameInput = getByValue('Norris')
```

### `getByRole`

```typescript
getByRole(
container: HTMLElement,
text: TextMatch,
options?: {
exact?: boolean = true,
collapseWhitespace?: boolean = false,
trim?: boolean = true,
}): HTMLElement`
```

A shortcut to `` container.querySelector(`[role="${yourRole}"]`) `` (and it
also accepts a [`TextMatch`](#textmatch)).

```javascript
// <div role="dialog">...</div>
const dialogContainer = getByTestrole(container, 'dialog')
```

### `getByTestId`

```typescript
Expand Down Expand Up @@ -933,7 +954,7 @@ Thanks goes to these people ([emoji key][emojis]):
| [<img src="https://avatars1.githubusercontent.com/u/1241511?s=460&v=4" width="100px;"/><br /><sub><b>Anto Aravinth</b></sub>](https://github.com/antoaravinth)<br />[馃捇](https://github.com/kentcdodds/dom-testing-library/commits?author=antoaravinth "Code") [鈿狅笍](https://github.com/kentcdodds/dom-testing-library/commits?author=antoaravinth "Tests") [馃摉](https://github.com/kentcdodds/dom-testing-library/commits?author=antoaravinth "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/3462296?v=4" width="100px;"/><br /><sub><b>Jonah Moses</b></sub>](https://github.com/JonahMoses)<br />[馃摉](https://github.com/kentcdodds/dom-testing-library/commits?author=JonahMoses "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/4002543?v=4" width="100px;"/><br /><sub><b>艁ukasz Gandecki</b></sub>](http://team.thebrain.pro)<br />[馃捇](https://github.com/kentcdodds/dom-testing-library/commits?author=lgandecki "Code") [鈿狅笍](https://github.com/kentcdodds/dom-testing-library/commits?author=lgandecki "Tests") [馃摉](https://github.com/kentcdodds/dom-testing-library/commits?author=lgandecki "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/498274?v=4" width="100px;"/><br /><sub><b>Ivan Babak</b></sub>](https://sompylasar.github.io)<br />[馃悰](https://github.com/kentcdodds/dom-testing-library/issues?q=author%3Asompylasar "Bug reports") [馃](#ideas-sompylasar "Ideas, Planning, & Feedback") [馃捇](https://github.com/kentcdodds/dom-testing-library/commits?author=sompylasar "Code") [馃摉](https://github.com/kentcdodds/dom-testing-library/commits?author=sompylasar "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/4439618?v=4" width="100px;"/><br /><sub><b>Jesse Day</b></sub>](https://github.com/jday3)<br />[馃捇](https://github.com/kentcdodds/dom-testing-library/commits?author=jday3 "Code") | [<img src="https://avatars0.githubusercontent.com/u/15199?v=4" width="100px;"/><br /><sub><b>Ernesto Garc铆a</b></sub>](http://gnapse.github.io)<br />[馃挰](#question-gnapse "Answering Questions") [馃捇](https://github.com/kentcdodds/dom-testing-library/commits?author=gnapse "Code") [馃摉](https://github.com/kentcdodds/dom-testing-library/commits?author=gnapse "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/2747424?v=4" width="100px;"/><br /><sub><b>Josef Maxx Blake</b></sub>](http://jomaxx.com)<br />[馃捇](https://github.com/kentcdodds/dom-testing-library/commits?author=jomaxx "Code") [馃摉](https://github.com/kentcdodds/dom-testing-library/commits?author=jomaxx "Documentation") [鈿狅笍](https://github.com/kentcdodds/dom-testing-library/commits?author=jomaxx "Tests") |
| [<img src="https://avatars3.githubusercontent.com/u/725236?v=4" width="100px;"/><br /><sub><b>Alex Cook</b></sub>](https://github.com/alecook)<br />[馃摉](https://github.com/kentcdodds/dom-testing-library/commits?author=alecook "Documentation") [馃挕](#example-alecook "Examples") | [<img src="https://avatars3.githubusercontent.com/u/10348212?v=4" width="100px;"/><br /><sub><b>Daniel Cook</b></sub>](https://github.com/dfcook)<br />[馃捇](https://github.com/kentcdodds/dom-testing-library/commits?author=dfcook "Code") [馃摉](https://github.com/kentcdodds/dom-testing-library/commits?author=dfcook "Documentation") [鈿狅笍](https://github.com/kentcdodds/dom-testing-library/commits?author=dfcook "Tests") | [<img src="https://avatars2.githubusercontent.com/u/21194045?s=400&v=4" width="100px;"/><br /><sub><b>Thomas Chia</b></sub>](https://github.com/thchia)<br />[馃悰](https://github.com/kentcdodds/dom-testing-library/issues?q=author%3Athchia "Bug reports") [馃捇](https://github.com/kentcdodds/dom-testing-library/commits?author=thchia "Code") | [<img src="https://avatars1.githubusercontent.com/u/28659384?v=4" width="100px;"/><br /><sub><b>Tim Deschryver</b></sub>](https://github.com/tdeschryver)<br />[馃捇](https://github.com/kentcdodds/dom-testing-library/commits?author=tdeschryver "Code") [鈿狅笍](https://github.com/kentcdodds/dom-testing-library/commits?author=tdeschryver "Tests") | [<img src="https://avatars3.githubusercontent.com/u/1571667?v=4" width="100px;"/><br /><sub><b>Alex Krolick</b></sub>](https://alexkrolick.com)<br />[馃捇](https://github.com/kentcdodds/dom-testing-library/commits?author=alexkrolick "Code") | [<img src="https://avatars2.githubusercontent.com/u/2224291?v=4" width="100px;"/><br /><sub><b>Maddi Joyce</b></sub>](http://www.maddijoyce.com)<br />[馃捇](https://github.com/kentcdodds/dom-testing-library/commits?author=maddijoyce "Code") | [<img src="https://avatars1.githubusercontent.com/u/25429764?v=4" width="100px;"/><br /><sub><b>Peter Kamps</b></sub>](https://github.com/npeterkamps)<br />[馃悰](https://github.com/kentcdodds/dom-testing-library/issues?q=author%3Anpeterkamps "Bug reports") [馃捇](https://github.com/kentcdodds/dom-testing-library/commits?author=npeterkamps "Code") [鈿狅笍](https://github.com/kentcdodds/dom-testing-library/commits?author=npeterkamps "Tests") |
| [<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") |
| [<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://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") |

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

Expand Down
8 changes: 8 additions & 0 deletions src/__tests__/__snapshots__/element-queries.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ exports[`get throws a useful error message 7`] = `
</div>"
`;

exports[`get throws a useful error message 8`] = `
"Unable to find an element by role=LucyRicardo
<div>
<div />
</div>"
`;

exports[`get throws a useful error message without DOM in Cypress 1`] = `"Unable to find a label with the text of: LucyRicardo"`;

exports[`get throws a useful error message without DOM in Cypress 2`] = `"Unable to find an element with the placeholder text of: LucyRicardo"`;
Expand Down
22 changes: 20 additions & 2 deletions src/__tests__/element-queries.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ test('get throws a useful error message', () => {
getByAltText,
getByTitle,
getByValue,
getByRole,
} = render('<div />')
expect(() => getByLabelText('LucyRicardo')).toThrowErrorMatchingSnapshot()
expect(() =>
Expand All @@ -39,6 +40,7 @@ test('get throws a useful error message', () => {
expect(() => getByAltText('LucyRicardo')).toThrowErrorMatchingSnapshot()
expect(() => getByTitle('LucyRicardo')).toThrowErrorMatchingSnapshot()
expect(() => getByValue('LucyRicardo')).toThrowErrorMatchingSnapshot()
expect(() => getByRole('LucyRicardo')).toThrowErrorMatchingSnapshot()
})

test('can get elements by matching their text content', () => {
Expand Down Expand Up @@ -209,8 +211,9 @@ test('getAll* matchers return an array', () => {
getAllByLabelText,
getAllByPlaceholderText,
getAllByText,
getAllByRole,
} = render(`
<div>
<div role="container">
<img
data-testid="poster"
alt="finding nemo poster"
Expand All @@ -234,6 +237,7 @@ test('getAll* matchers return an array', () => {
expect(getAllByPlaceholderText(/The Rock/)).toHaveLength(1)
expect(getAllByLabelText('User Name')).toHaveLength(1)
expect(getAllByText(/^where/i)).toHaveLength(1)
expect(getAllByRole(/container/i)).toHaveLength(1)
})

test('getAll* matchers throw for 0 matches', () => {
Expand All @@ -243,8 +247,9 @@ test('getAll* matchers throw for 0 matches', () => {
getAllByLabelText,
getAllByPlaceholderText,
getAllByText,
getAllByRole,
} = render(`
<div>
<div role="container">
<label>No Matches Please</label>
</div>,
`)
Expand All @@ -255,6 +260,7 @@ test('getAll* matchers throw for 0 matches', () => {
expect(() => getAllByLabelText('no matches please')).toThrow()
expect(() => getAllByPlaceholderText('nope')).toThrow()
expect(() => getAllByText('nope')).toThrow()
expect(() => getAllByRole('nope')).toThrow()
})

test('queryAll* matchers return an array for 0 matches', () => {
Expand All @@ -264,6 +270,7 @@ test('queryAll* matchers return an array for 0 matches', () => {
queryAllByLabelText,
queryAllByPlaceholderText,
queryAllByText,
queryAllByRole,
} = render(`
<div>
</div>,
Expand All @@ -273,6 +280,7 @@ test('queryAll* matchers return an array for 0 matches', () => {
expect(queryAllByLabelText('nope')).toHaveLength(0)
expect(queryAllByPlaceholderText('nope')).toHaveLength(0)
expect(queryAllByText('nope')).toHaveLength(0)
expect(queryAllByRole('nope')).toHaveLength(0)
})

test('using jest helpers to assert element states', () => {
Expand Down Expand Up @@ -375,6 +383,16 @@ test('using jest helpers to check element class names', () => {
).toThrowError()
})

test('using jest helpers to check element role', () => {
const {getByRole} = render(`
<div role="dialog">
<span>Contents</span>
</div>
`)

expect(getByRole('dialog')).toHaveTextContent('Contents')
})

test('test the debug helper prints the dom state here', () => {
const originalDebugPrintLimit = process.env.DEBUG_PRINT_LIMIT
const Large = `<div>
Expand Down
18 changes: 18 additions & 0 deletions src/queries.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ const queryByTestId = queryByAttribute.bind(null, 'data-testid')
const queryAllByTestId = queryAllByAttribute.bind(null, 'data-testid')
const queryByValue = queryByAttribute.bind(null, 'value')
const queryAllByValue = queryAllByAttribute.bind(null, 'value')
const queryByRole = queryByAttribute.bind(null, 'role')
const queryAllByRole = queryAllByAttribute.bind(null, 'role')

function queryAllByAltText(
container,
Expand Down Expand Up @@ -241,6 +243,18 @@ function getByAltText(...args) {
return firstResultOrNull(getAllByAltText, ...args)
}

function getAllByRole(container, id, ...rest) {
const els = queryAllByRole(container, id, ...rest)
if (!els.length) {
throw getElementError(`Unable to find an element by role=${id}`, container)
}
return els
}

function getByRole(...args) {
return firstResultOrNull(getAllByRole, ...args)
}

export {
queryByPlaceholderText,
queryAllByPlaceholderText,
Expand Down Expand Up @@ -270,6 +284,10 @@ export {
queryAllByValue,
getByValue,
getAllByValue,
queryByRole,
queryAllByRole,
getAllByRole,
getByRole,
}

/* eslint complexity:["error", 14] */
4 changes: 4 additions & 0 deletions typings/queries.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,7 @@ export const queryByValue: QueryByAttribute
export const queryAllByValue: AllByAttribute
export const getByValue: GetByAttribute
export const getAllByValue: AllByAttribute
export const queryByTRole: QueryByAttribute
export const queryAllByTRole: AllByAttribute
export const getByTRole: GetByAttribute
export const getAllByTRole: AllByAttribute

0 comments on commit fe02135

Please sign in to comment.