React

The right Testing Library queries, in priority order

Testing Library queries have an order: role, label, text, test id. The wrong query makes a test fragile or meaningless.

Key points

  • The order is role, label, text, test id: drop a level only when the one above does not exist.
  • queryBy is for absence, findBy for what arrives after a request.
  • A test that cannot find the role often points at an accessibility problem.

Testing Library has a priority order: role first, then label, then text, and data-testid only at the end.

The order, from the top

  • getByRole: it sees the page the way a screen reader does and checks the accessible name too.
  • getByLabelText: for fields with a linked label; it fails when the link is missing, which is a useful signal.
  • getByText: for static content and messages, not for fields.
  • getByTestId: the last resort, for parts with no role and no text, such as a layout container.

The right query in practice

import { render, screen } from "@testing-library/react";

render();

screen.getByRole("textbox", { name: /email/i });
screen.getByRole("button", { name: /accedi/i });
screen.queryByRole("alert");
screen.findByText(/benvenuto/i);

The three variants mean different things: getBy fails when the element is missing, queryBy returns null and is the only one you can use to check absence, and findBy waits, which suits what arrives after a request.

The failures that tell you something

  • Found multiple elements: two elements share an accessible name, so the label is ambiguous.
  • Unable to find role: the semantic role is missing, often because the click sits on a div.
  • Not wrapped in act: an update lands outside the wait; use await on findBy.

The command

npx vitest run -t "login"

The -t filter runs only the tests with that name: handy while you fix one query, without waiting for the whole suite.

Live records in the catalogue

Three components worth querying: input, login-form and multistep-form. To browse by category start from 111,985 components.

The limitation

A correct role does not guarantee a correct interaction: the query finds the button even when it is covered, disabled or off screen. jsdom computes no layout, so those defects stay invisible.

Where to continue

The five-test picture is in Testing Library: five tests; the checklist is in accessible React components; how to read documentation is in React documentation.

Frequently asked questions

getByRole or getByTestId?

getByRole when it exists. It checks the accessible name too; keep the test id for parts with no role and no text.

When do I use queryBy?

Only to check that an element is absent: it returns null instead of throwing.

Why findBy instead of waitFor?

findBy combines the wait and the query in one call; waitFor suits a wait around several assertions.

Does getByText find text inside a button?

Yes, but it is fragile: a button name changes with its role. Prefer getByRole with name.

Are queries case sensitive?

Not by default: matching ignores case and normalises whitespace.