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
awaitonfindBy.
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.