Skip to content

Issue with *ByLabelText functions when using aria-labelledby with multiple IDs referencing aria-label #1352

Open
@romain-trotard

Description

@romain-trotard

Hello all :)

Thanks for the library 🔥

  • @testing-library/dom version: v10.4.0

Relevant code or config:

I made this branch with a test https://github.com/romain-trotard/dom-testing-library/tree/labelledby-multiple-repro and some comments on the code I think we should change.

  const {getByLabelText} = render(`
      <div id="frameworks-row" role="row" aria-label="Frameworks">
        <button aria-labelledby="select frameworks-row" id="select" aria-label="Select" type="button">Select</button>
        <span>Frameworks</span>
        <span>Other information</span>
      </div>
  `)

  // Do not find `Select Frameworks` because it takes element.textContent 
  // and not `aria-label` for the element with id `frameworks-row`
  expect(getByLabelText('Select Frameworks').id).toBe('select')
  expect(getByLabelText('Frameworks').id).toBe('frameworks-row')

What you did:

There are some use cases where we want to labelled an element with aria-labelledby that references an element that has aria-label.
For example, in the template above the button element has a aria-labelledby that references himself (that has aria-label) and the div with id frameworks-row (that has aria-label)

What happened:

The selector getByLabelText('Select Frameworks') does not work because when getting the element with id: frameworks-row, it's not the aria-label that is retrieved but the textContent (here Select Frameworks Other information)

Reproduction:

https://github.com/romain-trotard/dom-testing-library/tree/labelledby-multiple-repro

npm run test

Problem description:

The selector getByLabelText('Select Frameworks') does not work because when getting the element with id: frameworks-row, it's not the aria-label that is retrieved but the textContent (here Select Frameworks Other information)

Suggested solution:

Here

textContent = (element as HTMLInputElement).value || element.textContent

We should get the aria-label attribute before getting textContent, like this:

textContent = (element as HTMLInputElement).value || element.getAttribute('aria-label') || element.textContent

aria-label pb

But we also need to find a way to concat these labels (when working with aria-labelledby) here:

const labelList = getLabels(container, labelledElement, {selector})
labelList
.filter(label => Boolean(label.formControl))
.forEach(label => {
if (
matcher(label.content, label.formControl, text, matchNormalizer) &&
label.formControl
) {
labelledElements.push(label.formControl)
}
})
const labelsValue = labelList
.filter(label => Boolean(label.content))
.map(label => label.content)
if (
matcher(labelsValue.join(' '), labelledElement, text, matchNormalizer)
) {
labelledElements.push(labelledElement)
}
if (labelsValue.length > 1) {

Note: For the moment, I haven't given the solution much thought.

If the bug is acknowledged, I would be happy to make a fix ;)

Thanks :)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions