Testing Library
01 / 03

Core Concepts & Query API

Testing Library: Core Concepts & Query API

@testing-library is a family of packages for testing UI components. The philosophy: test the way users use your software — through accessible roles, visible text, and labels — not implementation details.

The Three Guiding Principles

  • Test what users see: query by role, label, and text — not by CSS class or internal state

  • Avoid implementation details: don't test which state variables changed or which methods were called

  • Accessible by default: queries that work for users also work for assistive technologies

Query Variants

Every query strategy comes in three variants:

  getBy*        Throws if 0 or 2+ elements found.  Use when asserting element EXISTS.
  queryBy*      Returns null if not found.           Use when asserting element ABSENT.
  findBy*       Returns Promise, retries on DOM changes. Use for ASYNC elements.

  + plural versions for multiple elements:
  getAllBy*   queryAllBy*   findAllBy*

Query Strategies — Priority Order

1. ByRole          — most preferred; queries ARIA roles (reflects accessibility tree)
2. ByLabelText     — for form controls with <label>, aria-label, aria-labelledby
3. ByPlaceholderText — form controls; role queries are better when available
4. ByText          — for non-interactive elements (headings, paragraphs, divs)
5. ByDisplayValue  — currently selected value in input/textarea/select
6. ByAltText       — img, area elements with alt attribute
7. ByTitle         — elements with title attribute
8. ByTestId        — last resort; add data-testid to element manually

Rule of thumb: if a screen reader would find it by role or label, use that query.
              If not, consider improving your component's accessibility first.

ByRole — Complete Reference

// Common ARIA roles and the HTML elements that map to them:

// Interactive
screen.getByRole('button')          // <button>, <input type="button/submit/reset">
screen.getByRole('link')            // <a href="...">
screen.getByRole('textbox')         // <input type="text">, <textarea>
screen.getByRole('checkbox')        // <input type="checkbox">
screen.getByRole('radio')           // <input type="radio">
screen.getByRole('combobox')        // <select>, or custom combobox with aria-haspopup
screen.getByRole('listbox')         // <select multiple>
screen.getByRole('option')          // <option>
screen.getByRole('switch')          // toggle with role="switch"
screen.getByRole('slider')          // <input type="range">
screen.getByRole('spinbutton')      // <input type="number">
screen.getByRole('searchbox')       // <input type="search">

// Structure
screen.getByRole('heading', { level: 1 })   // <h1> through <h6>
screen.getByRole('list')            // <ul>, <ol>
screen.getByRole('listitem')        // <li>
screen.getByRole('table')           // <table>
screen.getByRole('row')             // <tr>
screen.getByRole('cell')            // <td>
screen.getByRole('columnheader')    // <th>
screen.getByRole('img')             // <img> with alt text

// Landmark
screen.getByRole('navigation')      // <nav>
screen.getByRole('main')            // <main>
screen.getByRole('banner')          // <header>
screen.getByRole('contentinfo')     // <footer>
screen.getByRole('form')            // <form>
screen.getByRole('dialog')          // role="dialog" or <dialog>
screen.getByRole('alert')           // role="alert" — live region for errors
screen.getByRole('status')          // role="status" — live region for status

// Options
screen.getByRole('button', {
  name: /submit/i,          // accessible name (visible text, aria-label, aria-labelledby)
  hidden: true,             // include elements with display:none or visibility:hidden
  selected: true,           // for options
  checked: true,            // for checkboxes/radios
  pressed: true,            // for toggle buttons (aria-pressed)
  expanded: true,           // for expandable elements (aria-expanded)
  level: 2,                 // for headings
})

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free