Skip to content

Commit 5fe849f

Browse files
lgandeckiKent C. Dodds
authored and
Kent C. Dodds
committed
feat(queryByTitle): add new query for title attribute (testing-library#34)
* poc for getting/querying by title * updated docs, tests, simplified implementation
1 parent d22a9ff commit 5fe849f

File tree

4 files changed

+59
-0
lines changed

4 files changed

+59
-0
lines changed

README.md

+10
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ when a real user uses it.
7676
* [`getByPlaceholderText(container: HTMLElement, text: TextMatch): HTMLElement`](#getbyplaceholdertextcontainer-htmlelement-text-textmatch-htmlelement)
7777
* [`getByText(container: HTMLElement, text: TextMatch): HTMLElement`](#getbytextcontainer-htmlelement-text-textmatch-htmlelement)
7878
* [`getByAltText(container: HTMLElement, text: TextMatch): HTMLElement`](#getbyalttextcontainer-htmlelement-text-textmatch-htmlelement)
79+
* [`getByTitle(container: HTMLElement, title: ExactTextMatch): HTMLElement`](#getbytitlecontainer-htmlelement-title-exacttextmatch-htmlelement)
7980
* [`getByTestId(container: HTMLElement, text: ExactTextMatch): HTMLElement`](#getbytestidcontainer-htmlelement-text-exacttextmatch-htmlelement)
8081
* [`wait`](#wait)
8182
* [`waitForElement`](#waitforelement)
@@ -250,6 +251,15 @@ and [`<area>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/area)
250251
const incrediblesPosterImg = getByAltText(container, /incredibles.*poster$/i)
251252
```
252253

254+
### `getByTitle(container: HTMLElement, title: ExactTextMatch): HTMLElement`
255+
256+
This will return the element that has the matching `title` attribute.
257+
258+
```javascript
259+
// <span title="Delete" id="2" />
260+
const deleteElement = getByTitle(container, 'Delete')
261+
```
262+
253263
### `getByTestId(container: HTMLElement, text: ExactTextMatch): HTMLElement`
254264

255265
A shortcut to `` container.querySelector(`[data-testid="${yourId}"]`) `` (and it

src/__tests__/__snapshots__/element-queries.js.snap

+8
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ exports[`get throws a useful error message 5`] = `
4040
</div>"
4141
`;
4242

43+
exports[`get throws a useful error message 6`] = `
44+
"Unable to find an element with the title: LucyRicardo.
45+
46+
<div>
47+
<div />
48+
</div>"
49+
`;
50+
4351
exports[`label with no form control 1`] = `
4452
"Found a label with the text of: alone, however no form control was found associated to that label. Make sure you're using the \\"for\\" attribute or \\"aria-labelledby\\" attribute correctly.
4553

src/__tests__/element-queries.js

+15
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ test('get throws a useful error message', () => {
2323
getByText,
2424
getByTestId,
2525
getByAltText,
26+
getByTitle,
2627
} = render('<div />')
2728
expect(() => getByLabelText('LucyRicardo')).toThrowErrorMatchingSnapshot()
2829
expect(() =>
@@ -31,6 +32,7 @@ test('get throws a useful error message', () => {
3132
expect(() => getByText('LucyRicardo')).toThrowErrorMatchingSnapshot()
3233
expect(() => getByTestId('LucyRicardo')).toThrowErrorMatchingSnapshot()
3334
expect(() => getByAltText('LucyRicardo')).toThrowErrorMatchingSnapshot()
35+
expect(() => getByTitle('LucyRicardo')).toThrowErrorMatchingSnapshot()
3436
})
3537

3638
test('can get elements by matching their text content', () => {
@@ -117,6 +119,19 @@ test('get element by its alt text', () => {
117119
expect(getByAltText(/fin.*nem.*poster$/i).src).toBe('/finding-nemo.png')
118120
})
119121

122+
test('query/get element by its title', () => {
123+
const {getByTitle, queryByTitle} = render(`
124+
<div>
125+
<span title="Ignore this" id="1"/>
126+
<span title="Delete" id="2"/>
127+
<span title="Ignore this as well" id="3"/>
128+
</div>
129+
`)
130+
131+
expect(getByTitle('Delete').id).toEqual('2')
132+
expect(queryByTitle('Delete').id).toEqual('2')
133+
})
134+
120135
test('can get elements by data-testid attribute', () => {
121136
const {queryByTestId} = render(`<div data-testid="firstName"></div>`)
122137
expect(queryByTestId('firstName')).toBeInTheDOM()

src/queries.js

+26
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,28 @@ function queryByText(container, text, opts) {
6868
return firstResultOrNull(queryAllByText, container, text, opts)
6969
}
7070

71+
const queryAllByTitle = (...args) =>
72+
queryAllByAttribute('title', ...args, {exact: true})
73+
74+
const queryByTitle = (...args) =>
75+
queryByAttribute('title', ...args, {exact: true})
76+
77+
function getAllByTitle(container, title, ...rest) {
78+
const els = queryAllByTitle(container, title, ...rest)
79+
if (!els.length) {
80+
throw new Error(
81+
`Unable to find an element with the title: ${title}. \n\n${debugDOM(
82+
container,
83+
)}`,
84+
)
85+
}
86+
return els
87+
}
88+
89+
function getByTitle(...args) {
90+
return firstResultOrNull(getAllByTitle, ...args)
91+
}
92+
7193
// this is just a utility and not an exposed query.
7294
// There are no plans to expose this.
7395
function queryAllByAttribute(attribute, container, text, {exact = false} = {}) {
@@ -215,6 +237,10 @@ export {
215237
queryAllByTestId,
216238
getByTestId,
217239
getAllByTestId,
240+
queryByTitle,
241+
queryAllByTitle,
242+
getByTitle,
243+
getAllByTitle,
218244
}
219245

220246
/* eslint complexity:["error", 14] */

0 commit comments

Comments
 (0)