Cristian Flórez
Cristian Flórez

Reputation: 2771

Found multiple elements error in React Testing Library

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.

Upvotes: 47

Views: 95055

Answers (7)

Mark Swardstrom
Mark Swardstrom

Reputation: 18070

I'm using vitest and didn't have this in initially:

    afterEach(cleanup);

this can be added to the test, or it may be due to the config.

test: {
  globals: true
}

This can be added to vite.config.ts

More information here: https://github.com/testing-library/vue-testing-library/issues/296

Upvotes: 0

Nishith
Nishith

Reputation: 1118

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

Upvotes: 1

Marcos Querino
Marcos Querino

Reputation: 1

You can fix it using string instead of regex:

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

There is some problem with two caracters names in Jest.

Upvotes: 0

JosephA91
JosephA91

Reputation: 697

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');
});

Upvotes: 44

Ivan K.
Ivan K.

Reputation: 1094

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();
})

Upvotes: 12

Ross Mawdsley
Ross Mawdsley

Reputation: 361

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 :-)

Upvotes: 19

user9760669
user9760669

Reputation:

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()
})

Upvotes: 0

Related Questions