How to Query and Test Within a Specific Component in Jest

Last Updated:
Use Within to Test in React Testing Library

Are you trying to target a specific element inside the DOM in Jest to make testing simpler and not sure how to do it?

This post on querying within components using within will hopefully point you in the right direction. A relatively simple way to check inside an element using React Testing Library.

Context

There is an component that has three cards outlining a product. Each card has a title element and a button that fires a function. We want to test if the correct function fires, when the Cat Food “Buy Item” button is clicked.

Jest Test Within Element Example

This looks like this:

import "./styles.css";
import { purchaseFunction } from "./api";

const Card = ({ title, slug }) => (
  <div className="card">
    <h2>{title}</h2>
    <button className="button" onClick={() => purchaseFunction(slug)}>
      Buy Item
    </button>
  </div>
);

const Products = ({ items }) => (
  <div className="products">
    {items.map(({ title, slug }) => (
      <Card key={slug} title={title} slug={slug} />
    ))}
  </div>
);

export default function App() {
  const items = [
    { title: "Cat Food", slug: "cat-food" },
    { title: "Dog Food", slug: "dog-food" },
    { title: "Waffles", slug: "waffles" }
  ];

  return (
    <div className="app">
      <h1>Shop</h1>
      <Products items={items} />
    </div>
  );
}

A working example of the above so you can see the code in action: React Testing Library Within CodeSandbox.

The issue is that each button has the same label “Buy Item”. How can the jest test target a specific section of the component? How can we use React Testing Library focus down into a DOM node and only use a section in the test?

What To Do?

There are several options at this point. It would be easy to apply a testid to each button with a unique name, but this wouldn’t be testing the proper component. Using the testid query is only recommended for cases where you can’t match by role or text or it doesn’t make sense. More detail on this can be found in the React Testing Library priority page.

It would also be possible to use queryAllByText to find each ‘Buy Item’ button, then find the second button. Like so:

test("purchaseFunction called with correct product slug on second button click", () => {
  render(<App />);

  // Get the dog food buy button from an array of all buy buttons.
  const DogFoodButton = screen.queryAllByText("Buy Item")[1];

  userEvent.click(DogFoodButton);

  expect(purchaseFunction).toHaveBeenCalledWith("dog-food");
});

However this is very brittle and if the card positions are switched/moved the test will break. We do not want to test the order of the cards. We want to test if a particular button is pressed.

The Cleaner Way To Test

This is where within is super handy. It allows the test to be focused within a particular DOM element. To run a jest test inside an element block. I would recommend using this way to Jest test within a React component.

This would be handled like so:

test("purchaseFunction called with correct product slug on Dog Food click", () => {
  render(<App />);

  // Get the specific card and bind to query functions using within.
  const DogFoodCard = within(screen.getByText("Dog Food").parentElement);

  // Now we can click the specific button within that card.
  userEvent.click(DogFoodCard.getByRole("button", { name: "Buy Item" }));

  expect(purchaseFunction).toHaveBeenCalledWith("dog-food");
});

Although the test is a little longer, it is more explicit in what is happening. It allows jest queries to be restricted with within a particular element meaning that the tests themselves can be far more succinct and cleaner. Hopefully this answers the question of how to make queries in Jest test within context of particular element. Fingers crossed an easy copy/paste example for how use react testing library to test within a component.

For more React and Jest hints and tips take a look at the React Category, and Jest Testing Category!

Related Posts

Get helpful Jest Pieces right to your inbox

Keep up to date with all helpful bits of Jest snippets and articles.