Query a button with specific text
Asked Answered
S

5

53

I have a (Jest) test to determine if a button exists:

it('renders a signup button', () => {
  expect(sut.getByText('Sign up for free')).toBeDefined()
})

This test because there is both a button AND heading with "Sign up for free" text in the component.

Screenshot showing both a heading and button with "Sign up for free" text

A testid could be added to the button, but I'd prefer to follow the react-testing-library principle of simulating user behaviour.

I feel it's legitimate a user would want to "click the button labelled 'Sign up for free'". In this situation, specifying the type of HTML element makes sense as a <button /> is a distinctive element to the user, as opposed to be <h2 /> vs <h3 />.

How can I query for a button element labelled "Sign up for free"? For example can getByText() be further limited by a query selector?

Starnes answered 16/10, 2019 at 7:40 Comment(0)
M
112

I'm surprised no one here gives the most idiomatic answer yet. You can use getByRole() and pass an accessible name. The accessible name is the text of the button or the value of aria-label attribute.

It can be used to query a specific element if multiple elements with the same role are presented on the screen.

Text button

<button>Text Button</button>
screen.getByRole('button', {
  name: /text button/i
})

Icon button

<button aria-label='edit'>
  <edit-icon />
</button>
screen.getByRole('button', {
  name: /edit/i
})
Musketry answered 4/11, 2020 at 1:28 Comment(3)
Thanks for this answer! The name property didn't exist in my version of React Testing Library so I had to update the package. Just in case others come across the same problem.Cataract
Here is current documentation which explains why getByRole is the most idiomatic. The Testing Library philosophy is to emulate actual usage as much as possible. Using accessibility tree objects emulates both visual/mouse users as well as those who use assistive technology such as screen readers.Lobby
This to me looks like another example the bad design of ReactTestingLibrary. I had to do the following: const myButton = page.getAllByRole('button').filter((it) => it.textContent === 'Text Button')[0]Tasha
T
40

You can pass options to your query to change its default behavior:

getByText('Sign up for free', { selector: 'button' })

You can find the full documentation here

Torrential answered 17/10, 2019 at 10:42 Comment(0)
G
16

You can do it like this:

getByText('Sign up for free').closest('button')

You can read more about closest from here

Gutshall answered 16/10, 2019 at 8:18 Comment(1)
This will still find multiple elements, failing in react-testing-library >= 7.0. I only want to select a single element.Starnes
H
0

If your query returns multiple html elements, you can also use:

const elements = getAllByText('Sign up for free');

This will return an array of elements that match the query. Then if you know which element you need, you can access like this:nodes[1]

You can add the word 'All' to the different selectors to get an array of all matching queries (getAllByRole, queryAllByText, etc.)

Headgear answered 28/2, 2022 at 15:23 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Cleareyed
B
-1

Also... if it is necessary, you can use screen.queryBy* without throw an error in the query operation

Queries in react-testing-library

Blondellblondelle answered 24/4, 2023 at 18:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.