Skip to content

Commit 664d980

Browse files
committed
fix(ByLabelText): support IE
Polyfill HTMLInputElement.labels to support IE and other legacy browsers. Closes #723.
1 parent 54aebf7 commit 664d980

File tree

2 files changed

+83
-4
lines changed

2 files changed

+83
-4
lines changed

src/__tests__/element-queries.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1182,3 +1182,65 @@ test('return a proper error message when no label is found and there is an aria-
11821182
</div>"
11831183
`)
11841184
})
1185+
1186+
// https://github.com/testing-library/dom-testing-library/issues/723
1187+
it('gets form controls by label text on IE and other legacy browsers', () => {
1188+
// Simulate lack of support for HTMLInputElement.prototype.labels
1189+
const inputLabelsSpy = jest
1190+
.spyOn(HTMLInputElement.prototype, 'labels', 'get')
1191+
.mockReturnValue(undefined)
1192+
1193+
const {getByLabelText} = renderIntoDocument(`
1194+
<div>
1195+
<label>
1196+
1st<input id="first-id" />
1197+
</label>
1198+
<div>
1199+
<label for="second-id">2nd</label>
1200+
<input id="second-id" />
1201+
</div>
1202+
<div>
1203+
<label id="third-label">3rd</label>
1204+
<input aria-labelledby="third-label" id="third-id" />
1205+
</div>
1206+
<div>
1207+
<label for="fourth.id">4th</label>
1208+
<input id="fourth.id" />
1209+
</div>
1210+
<div>
1211+
<div>
1212+
<label id="fifth-label-one">5th one</label>
1213+
<label id="fifth-label-two">5th two</label>
1214+
<input aria-labelledby="fifth-label-one fifth-label-two" id="fifth-id" />
1215+
</div>
1216+
<div>
1217+
<input id="sixth-label-one" value="6th one"/>
1218+
<input id="sixth-label-two" value="6th two"/>
1219+
<label id="sixth-label-three">6th three</label>
1220+
<input aria-labelledby="sixth-label-one sixth-label-two sixth-label-three" id="sixth-id" />
1221+
</div>
1222+
<div>
1223+
<span id="seventh-label-one">7th one</span>
1224+
<input aria-labelledby="seventh-label-one" id="seventh-id" />
1225+
</div>
1226+
<div>
1227+
<label id="eighth.label">8th one</label>
1228+
<input aria-labelledby="eighth.label" id="eighth.id" />
1229+
</div>
1230+
</div>
1231+
`)
1232+
expect(getByLabelText('1st').id).toBe('first-id')
1233+
expect(getByLabelText('2nd').id).toBe('second-id')
1234+
expect(getByLabelText('3rd').id).toBe('third-id')
1235+
expect(getByLabelText('4th').id).toBe('fourth.id')
1236+
expect(getByLabelText('5th one').id).toBe('fifth-id')
1237+
expect(getByLabelText('5th two').id).toBe('fifth-id')
1238+
expect(getByLabelText('6th one').id).toBe('sixth-id')
1239+
expect(getByLabelText('6th two').id).toBe('sixth-id')
1240+
expect(getByLabelText('6th one 6th two').id).toBe('sixth-id')
1241+
expect(getByLabelText('6th one 6th two 6th three').id).toBe('sixth-id')
1242+
expect(getByLabelText('7th one').id).toBe('seventh-id')
1243+
expect(getByLabelText('8th one').id).toBe('eighth.id')
1244+
1245+
inputLabelsSpy.mockRestore()
1246+
})

src/queries/label-text.js

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,9 @@ function queryAllByLabelText(
7272
const matcher = exact ? matches : fuzzyMatches
7373
const matchNormalizer = makeNormalizer({collapseWhitespace, trim, normalizer})
7474
const matchingLabelledElements = Array.from(container.querySelectorAll('*'))
75-
.filter(
76-
element => element.labels || element.hasAttribute('aria-labelledby'),
77-
)
75+
.filter(element => {
76+
return getLabels(element) || element.hasAttribute('aria-labelledby')
77+
})
7878
.reduce((labelledElements, labelledElement) => {
7979
const labelsId = labelledElement.getAttribute('aria-labelledby')
8080
? labelledElement.getAttribute('aria-labelledby').split(' ')
@@ -86,7 +86,7 @@ function queryAllByLabelText(
8686
)
8787
return labellingElement ? getLabelContent(labellingElement) : ''
8888
})
89-
: Array.from(labelledElement.labels).map(label => {
89+
: Array.from(getLabels(labelledElement)).map(label => {
9090
const textToMatch = getLabelContent(label)
9191
const formControlSelector =
9292
'button, input, meter, output, progress, select, textarea'
@@ -235,3 +235,20 @@ export {
235235
findAllByLabelText,
236236
findByLabelText,
237237
}
238+
239+
// Based on https://github.com/eps1lon/dom-accessibility-api/pull/352
240+
function getLabels(element) {
241+
if (element.labels !== undefined) return element.labels
242+
243+
if (!isLabelable(element)) return null
244+
245+
const labels = element.ownerDocument.querySelectorAll('label')
246+
return Array.from(labels).filter(label => label.control === element)
247+
}
248+
249+
function isLabelable(element) {
250+
return (
251+
element.tagName.match(/BUTTON|METER|OUTPUT|PROGRESS|SELECT|TEXTAREA/) ||
252+
(element.tagName === 'INPUT' && element.getAttribute('type') !== 'hidden')
253+
)
254+
}

0 commit comments

Comments
 (0)