@@ -212,6 +212,73 @@ test('can get sibling elements with aria-labelledby attrib ute', () => {
expect(result[0].id).toBe('icon')
})
+test('can filter results of label query based on selector', () => {
+ const {getAllByLabelText} = render(`
+
+ `)
+
+ const result = getAllByLabelText('Test Label', {selector: '.fancy-input'})
+ expect(result).toHaveLength(1)
+ expect(result[0].id).toBe('input1')
+})
+
+test('can find any form control when label text is inside other elements', () => {
+ const {getAllByLabelText} = render(`
+
+ `)
+
+ const result = getAllByLabelText('Test Label')
+ expect(result).toHaveLength(7)
+})
+
+test('can find non-input elements when aria-labelledby a label', () => {
+ const {getAllByLabelText} = render(`
+
+
+
+ `)
+
+ const result = getAllByLabelText('Test Label')
+ expect(result).toHaveLength(1)
+ expect(result[0].nodeName).toBe('UL')
+})
+
+test('can find the correct element when there are multiple matching labels', () => {
+ const {getByLabelText} = render(`
+
+
+ `)
+
+ const result = getByLabelText('Test Label', {selector: 'input'})
+ expect(result.nodeName).toBe('INPUT')
+})
+
test('get can get form controls by placeholder', () => {
const {getByPlaceholderText} = render(`
,
diff --git a/src/queries/label-text.js b/src/queries/label-text.js
index 4875b4a26..3b394f410 100644
--- a/src/queries/label-text.js
+++ b/src/queries/label-text.js
@@ -46,9 +46,10 @@ function queryAllByLabelText(
normalizer: matchNormalizer,
})
const labelledElements = labels
- .map(label => {
+ .reduce((matchedElements, label) => {
+ const elementsForLabel = []
if (label.control) {
- return label.control
+ elementsForLabel.push(label.control)
}
/* istanbul ignore if */
if (label.getAttribute('for')) {
@@ -57,21 +58,27 @@ function queryAllByLabelText(
//
// .control support has landed in jsdom (https://github.com/jsdom/jsdom/issues/2175)
- return container.querySelector(`[id="${label.getAttribute('for')}"]`)
+ elementsForLabel.push(
+ container.querySelector(`[id="${label.getAttribute('for')}"]`),
+ )
}
if (label.getAttribute('id')) {
//
- return container.querySelector(
- `[aria-labelledby~="${label.getAttribute('id')}"]`,
- )
+ container
+ .querySelectorAll(`[aria-labelledby~="${label.getAttribute('id')}"]`)
+ .forEach(element => elementsForLabel.push(element))
}
if (label.childNodes.length) {
//
- return label.querySelector(selector)
+ const formControlSelector =
+ 'button, input, meter, output, progress, select, textarea'
+ label
+ .querySelectorAll(formControlSelector)
+ .forEach(element => elementsForLabel.push(element))
}
- return null
- })
- .filter(label => label !== null)
+ return matchedElements.concat(elementsForLabel)
+ }, [])
+ .filter(element => element !== null)
.concat(queryAllByAttribute('aria-label', container, text, {exact}))
const possibleAriaLabelElements = queryAllByText(container, text, {
@@ -95,7 +102,9 @@ function queryAllByLabelText(
[],
)
- return Array.from(new Set([...labelledElements, ...ariaLabelledElements]))
+ return Array.from(
+ new Set([...labelledElements, ...ariaLabelledElements]),
+ ).filter(element => element.matches(selector))
}
// the getAll* query would normally look like this: