Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .size-snapshot.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"dist/dom-testing-library.umd.js": {
"bundled": 115443,
"minified": 50960,
"gzipped": 15294
"bundled": 122519,
"minified": 52052,
"gzipped": 15632
}
}
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,10 +211,16 @@ const inputNode = getByLabelText(container, 'Username')
// <label for="username-input">Username</label>
// <input id="username-input" />
//
// The aria-labelledby attribute
// The aria-labelledby attribute with form elements
// <label id="username-label">Username</label>
// <input aria-labelledby="username-label" />
//
// The aria-labelledby attribute with other elements
// <section aria-labelledby="section-one-header">
// <h3 id="section-one-header">Section One</h3>
// <p>some content...</p>
// <section>
//
// Wrapper labels
// <label>Username <input /></label>
//
Expand Down
23 changes: 22 additions & 1 deletion src/__tests__/element-queries.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ test('matches case with RegExp matcher', () => {
expect(queryByText(/Step 1 of 4/)).not.toBeTruthy()
})

test('get can get form controls by label text', () => {
test('can get form controls by label text', () => {
const {getByLabelText} = render(`
<div>
<label>
Expand Down Expand Up @@ -116,6 +116,27 @@ test('get can get form controls by label text', () => {
expect(getByLabelText('5th two').id).toBe('fifth-id')
})

test('can get elements labelled with aria-labelledby attribute', () => {
const {getByLabelText, getAllByLabelText} = render(`
<div>
<h1 id="content-header">The Gettysburg Address</h1>
<main id="sibling-of-content-header" aria-labelledby="content-header">
<section aria-labelledby="content-header section-one-header" id="section-one">
<h2 id="section-one-header">Section One</h2>
<p>Four score and seven years ago, ...</p>
</section>
</main>
<p>The Gettysburg Address</p>
</div>
`)
const result = getAllByLabelText('The Gettysburg Address').map(el => el.id)
expect(result).toHaveLength(2)
expect(result).toEqual(
expect.arrayContaining(['sibling-of-content-header', 'section-one']),
)
expect(getByLabelText('Section One').id).toBe('section-one')
})

test('get can get form controls by placeholder', () => {
const {getByPlaceholderText} = render(`
<input id="username-id" placeholder="username" />,
Expand Down
23 changes: 22 additions & 1 deletion src/queries.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,28 @@ function queryAllByLabelText(
.filter(label => label !== null)
.concat(queryAllByAttribute('aria-label', container, text, {exact}))

return labelledElements
const possibleAriaLabelElements = queryAllByText(container, text, {
exact,
...matchOpts,
}).filter(el => el.tagName !== 'LABEL') // don't reprocess labels

const ariaLabelledElements = possibleAriaLabelElements.reduce(
(allLabelledElements, nextLabelElement) => {
const labelId = nextLabelElement.getAttribute('id')

if (!labelId) return allLabelledElements

// ARIA labels can label multiple elements
const labelledNodes = Array.from(
container.querySelectorAll(`[aria-labelledby~="${labelId}"]`),
)

return allLabelledElements.concat(labelledNodes)
},
[],
)

return Array.from(new Set([...labelledElements, ...ariaLabelledElements]))
}

function queryByLabelText(...args) {
Expand Down