webroad.online
  1. 1Web
  2. 2HTML
  3. 3CSS
  4. 4JavaScript
  5. 5TypeScript
  6. 6Git
  7. 7Tooling
  8. 8React
  9. 9State management
  10. 10Next.js
  11. 11Forms
  12. 12Data and backend
  13. 13SEO
  14. 14Tailwind CSS
  15. 15Animations
  16. 16Testing
  17. 17Architecture
Testing · Lesson 3 of 4

Testing Library: components like a user

Queries by role and label, get/query/find, user-event.

Updated

What Testing Library is

React Testing Library (RTL) is a library for testing components the way a person uses them: you find elements by what you see (text, label, role), you click, you type — and you check what shows up on screen. You don't look at internal state or props.

Its principle: "The more your tests resemble the way your software is used, the more confidence they can give you."

import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'

test('adds a todo', async () => {
  const user = userEvent.setup()
  render(<TodoApp />)

  await user.type(screen.getByLabelText('New task'), 'Learn RTL')
  await user.click(screen.getByRole('button', { name: 'Add' }))

  expect(screen.getByText('Learn RTL')).toBeInTheDocument()
})

The queries — in order of priority

Pick the first one on the list that works. The order reflects how accessible the component is:

Priority Query Finds by Example
1 getByRole role + accessible name getByRole('button', { name: 'Save' })
2 getByLabelText a field's label getByLabelText('Email')
3 getByPlaceholderText the placeholder if there's no label
4 getByText the visible text paragraphs, messages
5 getByDisplayValue an input's value pre-filled forms
6 getByAltText / getByTitle alt / title images
last getByTestId data-testid only when nothing else works

A bonus: if you can't find an element with getByRole, most of the time your component has an accessibility problem. Tests push you toward better HTML.

The variants: get, query, find

Prefix If it doesn't find it Async When
getBy throws an error no the element must exist now
queryBy returns null no checking that it does not exist: expect(queryByText('Error')).toBeNull()
findBy throws after a timeout yes the element appears later (after a fetch, a setTimeout)

getAllBy... / queryAllBy... / findAllBy... for several elements.

user-event vs fireEvent

userEvent fireEvent
Simulates the full interaction (focus, keydown, input, keyup, click) a single DOM event
Realism high low
When the default special cases

What not to do

  • Testing internal state (component.state.count).
  • container.querySelector('.btn-primary') — classes are implementation details.
  • Huge snapshots that nobody reads.

Summary

  • RTL tests components like a user: you find by role, label, text.
  • Priority: getByRole → getByLabelText → … → getByTestId.
  • get = must exist, query = may be missing, find = will appear.

Official sources

Exercises

Was this page helpful?

One tap — no account needed.