Parent node in react-testing-library

Viewed 32150

The component that I have testing renders something this:

<div>Text<span>span text</span></div>

As it turns out for testing the only reliable text that I have is the 'span text' but I want to get the 'Text' part of the <div>. Using Jest and react-testing-library I can

await screen.findByText(spanText)

This returns an HTMLElement but it seems limited as I don't have any of the context around the element. For example HTML methods like parentNode and previousSibling return null or undefined. Ideally I would like to get the text content of the parent <div>. Any idea how I can do this with either Jest or react-testing-library?

3 Answers

A good solution for this is the closest function. In description of closest function is written: Returns the first (starting at element) including ancestor that matches selectors, and null otherwise.

The solution would look like this:

screen.getByText("span text").closest("div")

Admittedly, Testing Library doesn't communicate clearly how to do this. It includes an eslint rule no-direct-node-access that says "Avoid direct Node access. Prefer using the methods from Testing Library". This gives the impression that TL exposes a method for a situation like this, but at the moment it does not.

It could be you don't want to use .closest(), either because your project enforces that eslint rule, or because it is not always a reliable selector. I've found two alternative ways to tackle a situation like you describe.

  1. within(): If your element is inside another element that is selectable by a Testing Library method (like a footer or an element with unique text), you can use within() like:
within(screen.getByRole('footer')).getByText('Text');
  1. find() within the element with a custom function:
screen.getAllByText('Text').find(div => div.innerHTML.includes('span text'));

Doesn't look the prettiest, but you can pass any JS function you want so it's very flexible and controllable.

Ps. if you use my second option depending on your TypeScript config you may need to make an undefined check before asserting on the element with Testing Library's expect(...).toBeDefined().

But I used HTML methods a lot and there was no problem. What was your problem with HTML methods?

You can try this code.

const spanElement = screen.getElementByText('span text');
const parentDiv = spanElement.parentElement as HTMLElement;
within(parentDiv).getElementByText('...');
Related