Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get by HTML element with React Testing Library?

I'm using the getByTestId function in React Testing Library:

const button = wrapper.getByTestId("button");
expect(heading.textContent).toBe("something");

Is it possible / advisable to search for HTML elements instead? So something like this:

const button = wrapper.getByHTML("button");
const heading = wrapper.getByHTML("h1");
like image 870
Evanss Avatar asked Jan 17 '19 11:01

Evanss


People also ask

How do I get by id in React testing library?

I found a way to do this. import App from './App'; import { render, queryByAttribute } from 'react-testing-library'; const getById = queryByAttribute. bind(null, 'id'); const dom = render(<App />); const table = getById(dom. container, 'directory-table');

How do I get the element by className in React testing library?

To find elements by className in React testing library: Render a component and destructure the container object from the result. Use the getElementsByClassName() method on the container to find elements by class name.

How do I use snapshot testing in React library?

When writing snapshot tests for a React component, you first need to have code in a working state. Then, generate a snapshot of its expected output given certain data. The snapshot tests are committed alongside the component. Jest, a testing framework, will compare the snapshot to the rendered output for the test.


3 Answers

I'm not sure what wrapper is in this case. But to answer your two questions: yes it's possible to get by HTML element and no, it's not advisable.

This is how you would do it:

// Possible but not advisable
const { container } = render(<MyComponent />)
// `container` is just a DOM node
const button = container.querySelector('button')

Since you get back a DOM node you can use all the normal DOM APIs such as querySelector.

Now, why is this not advisable. A big selling point of react-testing-library is that you test your components as a user does. This means not relying on implementation details. For instance, you don't have direct access to a component's state.

Writing tests this way is a bit harder but allows you to write more robust tests.

In your case, I would argue that the underlying HTML is an implementation detail. What happens if you change your HTML structure so that the h1 is now an h2 or a div? The test will break. If instead, you look at these elements by text the tag becomes irrelevant.

In some cases, the normal query helpers are not enough. For those events you can use a data-testid and use getByTestId.

like image 89
Giorgio Polvara - Gpx Avatar answered Oct 14 '22 07:10

Giorgio Polvara - Gpx


Depending on the type of element you're querying for, you might also find the byRole API to be useful:

https://testing-library.com/docs/queries/byrole/

For example, the level was particularly useful for me to test that default <h1> elem was correctly being overridden:

it('correctly renders override header level', () => {
  const { getByRole } = render(<Heading overrideHeadingLevel="h6" />)

  expect(getByRole('heading', { level: 6 })).toBeInTheDocument()
})
like image 39
Ksenija Gogic Avatar answered Oct 14 '22 05:10

Ksenija Gogic


another possible solution

consider rendering your component.

render(<ReactComponent />);

const button = screen.getByText((content, element) => element.tagName.toLowerCase() === 'button');

and if you have multiple buttons use getAllByText and refer to the target element you need to pick.

like image 43
samehanwar Avatar answered Oct 14 '22 05:10

samehanwar