Found multiple elements error in React Testing Library
Asked Answered
T

6

44

Im having a problem with a query, I'm trying to get two radio inputs, I don't have any problem with one of them, but with the other one React Testing Library thrown an error: It Found multiple elements with the role "radio" and name /to/i:

queries

test('Render form with default items', () => {
  const handleUpdateValue = jest.fn();
  const handleNextStep = jest.fn();
  render(
    <Form
      handleNextStep={handleNextStep}
      updateValue={handleUpdateValue}
      transferFundsValues={{}}
    />
  );

  const amountInput = screen.getByLabelText(/amount/i);
  const fromRadio = screen.getByLabelText(/from/i);
  const toRadio = screen.getByLabelText(/to/i);
  const messageInput = screen.getByLabelText(/message/i);

  const continueButton = screen.getByRole('button', { name: /continue/i });
  const cancelButton = screen.getByRole('button', { name: /cancel/i });

  // If no value has been entered to the inputs, the continue button must be
  // disabled
  expect(continueButton).toBeDisabled();
});

Html structure

<label for="transferFunds_from" class="ant-form-item-required" title="From">From</label>
<input id="transferFunds_from" type="radio" class="ant-radio-button-input" value="">

<label for="transferFunds_to" class="ant-form-item-required" title="To">To</label>
<input id="transferFunds_to" type="radio" class="ant-radio-button-input" value="">

Error thrown by RTL

 TestingLibraryElementError: Found multiple elements with the role "radio" and name `/to/i`

    Here are the matching elements:

    <input
      class="ant-radio-button-input"
      id="transferFunds_from"
      type="radio"
      value=""
    />

    <input
      class="ant-radio-button-input"
      id="transferFunds_to"
      type="radio"
      value=""
    />

I don't know if I'm doing something wrong in the HTML structure or if it's a React Testing Library error.

Terceira answered 26/8, 2021 at 18:22 Comment(3)
Are these the full tests? I think we may need a bit more context. Usually you get that error if you try getByRole and there's multiple elements, yet I don't see that called anywhereRociorock
@JonathanS. I update my question with the complete test...Gourde
Did you ever find a solution to this?Gentianella
V
41

Just a quick tip, if you have multiple matching elements, you can query like this:

HTML:

<a href="/my-element">My element</a>
<a href="/my-element">My element</a>

TEST:

test('renders my element', () => {
  let link = screen.getAllByText('My element')[0] as HTMLAnchorElement;
  expect(link.href).toContain('/my-element');
});
Vomiturition answered 15/10, 2021 at 2:16 Comment(3)
Is this the best practice or would it be better to use data-testid on original doc and use it on tests when more than 1 element are present?Amphibole
You can do that as well, if you prefer.Vomiturition
Also, in my case I actually wanted to see that there was two instances of what I was searching for. In such a case I used getAllByText('some text').toHaveLength(2)Oeildeboeuf
E
17

What was causing this for me was simply having another render() in the test file that was not inside an it().... so the component was being rendered twice.

rookie mistake :-)

Effete answered 27/5, 2022 at 10:48 Comment(1)
Along similar lines, I ran into this in a test file that had both enzyme and RTL tests. Had to call wrapper.unmount() on earlier tests so that there was no extra lingering component by the time my RTL test ranTinea
A
11

If you have multiple matching elements try this one

<Typography component={"span"}>
  Some text
</Typography>

getAllByText if more then 1 Matches it`ll return array

Types of Queries Please check the documentation Summary Table

it('It will display Some text', () => {
    const subTitle = screen.getAllByText(/Some text/i);
    expect(subTitle[0]).toBeInTheDocument();
})
Acotyledon answered 6/10, 2022 at 1:48 Comment(0)
F
1

If you are having multiple tests under it and you have a single render function in the describe then you can try putting that render function inside a beforeEach

describe('This is a test section'), () => {

  beforeEach(() => render(<Element {...testProps}/>))

  it('smaller test',() => {
    // actual test
  })
})

and then try to run the test. This should solve it. If not then you can try to run the cleanup function and clear all the mocks after each test

Fumy answered 3/7, 2023 at 6:14 Comment(0)
R
0

I wrote similar expects and for me works well. Maybe something is wrong with your current @testing-library/react version. Try 10.4.9

The code that I used

import React from 'react'
import { render, screen } from '@testing-library/react'

function Form() {
  return (
    <div>
      <label
        htmlFor="transferFunds_from"
        className="ant-form-item-required"
        title="From"
      >
        From
      </label>
      <input
        id="transferFunds_from"
        type="radio"
        className="ant-radio-button-input"
        value=""
      />

      <label
        htmlFor="transferFunds_to"
        className="ant-form-item-required"
        title="To"
      >
        To
      </label>
      <input
        id="transferFunds_to"
        type="radio"
        className="ant-radio-button-input"
        value=""
      />
    </div>
  )
}

test('Render form with default items', () => {
  render(<Form />)

  const fromRadio = screen.getByLabelText(/from/i)
  const toRadio = screen.getByLabelText(/to/i)

  expect(fromRadio).toBeVisible()
  expect(toRadio).toBeVisible()
})
Rangefinder answered 26/8, 2021 at 18:50 Comment(1)
I'm using @testing-library/react: ^11.2.3. So I need to downgrade to 10.4.9?Gourde
M
0

You can fix it using string instead of regex:

const toRadio = screen.getByLabelText("to");

There is some problem with two caracters names in Jest.

Mathieu answered 22/6, 2023 at 3:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.