Skip to content

Inconsistent behavior of selector option #372

Closed
@airjp73

Description

@airjp73
  • DOM Testing Library version: 6.3.0
  • node version: 8.12.0 (& whatever codesandbox is on)
  • npm (or yarn) version: 6.4.1 (& whatever codesandbox is on)

Relevant code or config:

I have two main examples:

{/* Label associated with aria-labelledby */}
<label id="label1">Hi</label>
<span aria-labelledby="label1">Bye</span>
<input id="input1" aria-labelledby="label1" />

it('should find the input element', () => {
  const result = render(<Comp />);
  result.getByLabelText('Hi', { selector: 'input' });
  // Throws because multiple elements were matched
});
{/* Label associated by nesting */}
<label>
  <span>This one works</span>
  <input />
</label>

it('should not work because the label is nested in a span', () => {
  const result = render(<Comp />);
  result.getByLabelText('This one works');
  // Works fine
});

The documentation here suggests that the second one should not work and that the selector option is necessary.

What you did:

I was trying to test an interaction with a dropdown I made using Downshift. My hope was that I could select the input element using getByLabelText but that does not appear to be the case. In Downshift, multiple elements (e.g. the input element, the option list itself, the root div) get associated with the label via aria-labelledby. When I tried to filter the options down using the selector option, that lead me down this rabbit hole.

What happened:

It did not work the way I had hoped (filtering the results down based on the selector I provided). However, it also doesn't appear to work the way the documentation says it's supposed to work. The documentation I linked about provides this example:

<label> <span>Username</span> <input /> </label>

And says this:

It will NOT find the input node for label text broken up by elements. For this case, you can provide a selector in the options:

So it appears that the selector option for the getByLabelText is intended for filtering out elements that are inside labels. But as can be seen the codesandbox below, it is not actually necessary in the example given.

Reproduction:

https://codesandbox.io/embed/react-testing-library-demo-jipd1

Problem description:

It seems like the purpose and behavior of the selector option is inconsistent. In the reproduction above, you can see that it works with the getByText query the way I, personally, would expect it to. If two elements have the same text but only one matches the provided selector, that one gets returned. For getByLabelText though, it does not work that way. If I have multiple elements that point to the same label via aria-labelledby and I do a getByLabelText, providing a selector doesn't do anything and it throws an error unless I use getAllByLabelText.

Suggested solution:

I think it would make sense for it to behave more like the way it does for getByText. So it would:

  1. Find all labels with the matching text
  2. Find all elements that are labelled by those labels
  3. Filter down the results based on the provided selector.

If you agree, I would be happy to take a stab at this and put up a PR.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions