diff --git a/src/__tests__/element-queries.js b/src/__tests__/element-queries.js
index b0dc39c8..05aade0c 100644
--- a/src/__tests__/element-queries.js
+++ b/src/__tests__/element-queries.js
@@ -229,8 +229,8 @@ test('can filter results of label query based on selector', () => {
expect(result[0].id).toBe('input1')
})
-test('can find any form control when label text is inside other elements', () => {
- const {getAllByLabelText} = render(`
+test('can find any labelable element when label text is inside other elements', () => {
+ const {getByLabelText} = render(`
`)
- const result = getAllByLabelText('Test Label')
- expect(result).toHaveLength(7)
+ const nodeTypes = [
+ 'button',
+ 'input',
+ 'meter',
+ 'output',
+ 'progress',
+ 'select',
+ 'textarea',
+ ]
+ nodeTypes.forEach(nodeType => {
+ expect(getByLabelText('Test Label', {selector: nodeType}).nodeName).toEqual(
+ nodeType.toUpperCase(),
+ )
+ })
+})
+
+// According to the spec, the first descendant of a label that is a labelable element is the labeled control
+// https://html.spec.whatwg.org/multipage/forms.html#the-label-element
+test('returns the labelable element control inside a label', () => {
+ const {getByLabelText} = render(`
+
+ `)
+
+ expect(getByLabelText('Test Label').nodeName).toEqual('BUTTON')
})
test('can find non-input elements when aria-labelledby a label', () => {
diff --git a/src/queries/label-text.js b/src/queries/label-text.js
index 588258d1..94eeed79 100644
--- a/src/queries/label-text.js
+++ b/src/queries/label-text.js
@@ -74,9 +74,10 @@ function queryAllByLabelText(
//
const formControlSelector =
'button, input, meter, output, progress, select, textarea'
- Array.from(
+ const labelledFormControl = Array.from(
label.querySelectorAll(formControlSelector),
- ).forEach(element => elementsForLabel.push(element))
+ ).filter(element => element.matches(selector))[0]
+ if (labelledFormControl) elementsForLabel.push(labelledFormControl)
}
return matchedElements.concat(elementsForLabel)
}, [])