How can I find and click a button that has no text using React Testing Library?
Asked Answered
P

5

27

Many React Testing Library examples show how to find and click a button using the getByText query, as in:

fireEvent.click(getByText("Create"))

OR

userEvent.click(getByText("Create"))

However, it's common to have buttons with no text and only SVG icons, like Material UI's icon buttons or floating action buttons. Is there a recommended way to query for and click buttons like these? For context, I'm using the higher-level events provided by the companion user-event library.

Prewitt answered 27/2, 2020 at 0:5 Comment(1)
Wouldn't that be a case for using getByTestId()?Soche
M
53

For icon buttons, add an aria-label attribute like below:

<button aria-label='edit'>
  <edit-icon />
</button>

Then in your test, pass the accessible name when calling getByRole()

screen.getByRole('button', {
  name: /edit/i
})

From the docs:

The accessible name is for simple cases equal to e.g. the label of a form element, or the text content of a button, or the value of the aria-label attribute.

Melanimelania answered 30/11, 2020 at 15:44 Comment(0)
D
7

There are several ways to query an element, without seeing your hierarchy of elements, it's hard to say. But, there are several ways to query an element, an alternative to using getByText() could be getByRole('button'). If you want to add a data-testid to the element you could use getByTestId(). There are some more available queries found here: https://testing-library.com/docs/dom-testing-library/api-queries

Daffi answered 27/2, 2020 at 2:4 Comment(2)
I see, so there'll need to be one or more identifiable attributes added to the button like role, aria-label, alt, or data-testid to enable one of those other queries. With the Material UI icon button and floating action button examples, they appear to add aria-labels like aria-label="delete", which would enable querying with getByLabelText.Prewitt
@RomanScher What you want to be thinking is "What text is a screen reader going to read when focus is on this button?" and use the appropriate method for getting it by that text (getByLabelText is often what you want). If your answer to the screen reader question is that it won't read anything, then you should address that.Immunochemistry
A
3

There are a bunch of different ways to do it, including everyone's favorite fallback, data-tested. But if you're using Material UI, you might be looking for the most "MUI" way to do this. Two ideas:

  • The MUI documentation shows all its buttons wrapped with a label element with an htmlFor property. You could do this and then use getByLabelText()
  • Your icon buttons probably have (and should!) a tooltip, and the tooltip text is probably coming from a title property. Then you can get the button with getByTitle().
Adjudge answered 29/5, 2020 at 13:37 Comment(1)
title is not advised as far as I can tell (but can't find a source back)Fisch
J
2

For me non of above answers works, what is worked for me is:

screen.getByRole('button', { name: /<icon-file-name>/i });

In my case the button with only svg file.

Jagannath answered 5/10, 2021 at 9:13 Comment(0)
B
1

The best possible way of finding an element is to simulate the most User oriented approach. So probably User expects the role button and then searches for an icon in your case. That's where semantic HTML plays a role for elements structure inside your component.

MUI buttons also implement a name attribute for some icon buttons used inside another component e.g. Select and I strongly recommend using this attribute for testing purpose.

Please remember that, your tests should be unaware of implementation, so identification should rely on name, role, label and other "natural" attributes. But if that is not possible using data-testid should be your last resort.

A very good overall approach (not only for icon buttons) is to specify a name property alongside role in getByRole query:

const listOpenButton = screen.getByRole("button", { name: /open/i });

Also a data-testid approach:

const listOpenButton = screen.getByTestId("myButtonId");
Brandenburg answered 27/8, 2021 at 8:1 Comment(3)
I'm using react native paper, based off MUI. But I don't see any "name" property in the dom, where do you find the name?Polyvinyl
@Polyvinyl I have no prior experience with React Native nor paper, but their docs suggest using testID property assuming you are trying to test your button component link.Brandenburg
thanks for the reply, yea I ended up using testID, but it just goes against the "test the ui as the user would use it" philosophyPolyvinyl

© 2022 - 2024 — McMap. All rights reserved.