react-testing-library Documentation

Simple and complete React DOM testing utilities that encourage good testing practices.

19,579 stars JavaScript JavaScript 1 file ยท ~32,689 tokens #javascript#reactjs#testing
RAW Doc

1. Project Overview & Quickstart (testing-library/react-testing-library)


Build Status
Code Coverage
version
downloads
MIT License
[
PRs Welcome
Code of Conduct
Discord

Watch on GitHub
Star on GitHub
Tweet

Table of Contents

The problem

You want to write maintainable tests for your React components. As a part of
this goal, you want your tests to avoid including implementation details of your
components and rather focus on making your tests give you the confidence for
which they are intended. As part of this, you want your testbase to be
maintainable in the long run so refactors of your components (changes to
implementation but not functionality) don't break your tests and slow you and
your team down.

The solution

The React Testing Library is a very lightweight solution for testing React
components. It provides light utility functions on top of react-dom and
react-dom/test-utils, in a way that encourages better testing practices. Its
primary guiding principle is:

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

Installation

This module is distributed via npm which is bundled with node and
should be installed as one of your project's devDependencies.
Starting from RTL version 16, you'll also need to install
@testing-library/dom:

text
npm install --save-dev @testing-library/react @testing-library/dom

or

for installation via yarn

text
yarn add --dev @testing-library/react @testing-library/dom

This library has peerDependencies listings for react, react-dom and
starting from RTL version 16 also @testing-library/dom.

React Testing Library versions 13+ require React v18. If your project uses an
older version of React, be sure to install version 12:

text
npm install --save-dev @testing-library/react@12


yarn add --dev @testing-library/react@12

You may also be interested in installing @testing-library/jest-dom so you can
use the custom jest matchers.

Docs

Suppressing unnecessary warnings on React DOM 16.8

There is a known compatibility issue with React DOM 16.8 where you will see the
following warning:

text
Warning: An update to ComponentName inside a test was not wrapped in act(...).

If you cannot upgrade to React DOM 16.9, you may suppress the warnings by adding
the following snippet to your test configuration
(learn more):

js
// this is just a little hack to silence a warning that we'll get until we
// upgrade to 16.9. See also: https://github.com/facebook/react/pull/14853
const originalError = console.error
beforeAll(() => {
  console.error = (...args) => {
    if (/Warning.*not wrapped in act/.test(args[0])) {
      return
    }
    originalError.call(console, ...args)
  }
})

afterAll(() => {
  console.error = originalError
})

Examples

Basic Example

jsx
// hidden-message.js
import * as React from 'react'

// NOTE: React Testing Library works well with React Hooks and classes.
// Your tests will be the same regardless of how you write your components.
function HiddenMessage({children}) {
  const [showMessage, setShowMessage] = React.useState(false)
  return (
    
      <label htmlFor="toggle">Show Message</label>
       setShowMessage(e.target.checked)}
        checked={showMessage}
      />
      {showMessage ? children : null}
    
  )
}

export default HiddenMessage
jsx
// __tests__/hidden-message.js
// these imports are something you'd normally configure Jest to import for you
// automatically. Learn more in the setup docs: https://testing-library.com/docs/react-testing-library/setup#cleanup
import '@testing-library/jest-dom'
// NOTE: jest-dom adds handy assertions to Jest and is recommended, but not required

import * as React from 'react'
import {render, fireEvent, screen} from '@testing-library/react'
import HiddenMessage from '../hidden-message'

test('shows the children when the checkbox is checked', () => {
  const testMessage = 'Test Message'
  render(<HiddenMessage>{testMessage}</HiddenMessage>)

  // query* functions will return the element or null if it cannot be found
  // get* functions will return the element or throw an error if it cannot be found
  expect(screen.queryByText(testMessage)).toBeNull()

  // the queries can accept a regex to make your selectors more resilient to content tweaks and changes.
  fireEvent.click(screen.getByLabelText(/show/i))

  // .toBeInTheDocument() is an assertion that comes from jest-dom
  // otherwise you could use .toBeDefined()
  expect(screen.getByText(testMessage)).toBeInTheDocument()
})

Complex Example

jsx
// login.js
import * as React from 'react'

function Login() {
  const [state, setState] = React.useReducer((s, a) => ({...s, ...a}), {
    resolved: false,
    loading: false,
    error: null,
  })

  function handleSubmit(event) {
    event.preventDefault()
    const {usernameInput, passwordInput} = event.target.elements

    setState({loading: true, resolved: false, error: null})

    window
      .fetch('/api/login', {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({
          username: usernameInput.value,
          password: passwordInput.value,
        }),
      })
      .then(r => r.json().then(data => (r.ok ? data : Promise.reject(data))))
      .then(
        user => {
          setState({loading: false, resolved: true, error: null})
          window.localStorage.setItem('token', user.token)
        },
        error => {
          setState({loading: false, resolved: false, error: error.message})
        },
      )
  }

  return (
    
      <form onSubmit={handleSubmit}>
        
          <label htmlFor="usernameInput">Username</label>
          
        
        
          <label htmlFor="passwordInput">Password</label>
          
        
        Submit{state.loading ? '...' : null}
      </form>
      {state.error ? {state.error} : null}
      {state.resolved ? (
        Congrats! You're signed in!
      ) : null}
    
  )
}

export default Login
text
/* Detailed source-code truncated for AI context efficiency. */

We recommend using Mock Service Worker library
to declaratively mock API communication in your tests instead of stubbing
window.fetch, or relying on third-party adapters.

More Examples

We're in the process of moving examples to the
docs site

You'll find runnable examples of testing with different libraries in
the react-testing-library-examples codesandbox.
Some included are:

Hooks

If you are interested in testing a custom hook, check out React Hooks Testing
Library
.

NOTE: it is not recommended to test single-use custom hooks in isolation from
the components where it's being used. It's better to test the component that's
using the hook rather than the hook itself. The React Hooks Testing Library
is intended to be used for reusable hooks/libraries.

Guiding Principles

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

We try to only expose methods and utilities that encourage you to write tests
that closely resemble how your React components are used.

Utilities are included in this project based on the following guiding
principles:

  1. If it relates to rendering components, it deals with DOM nodes rather than
    component instances, nor should it encourage dealing with component
    instances.
  2. It should be generally useful for testing individual React components or
    full React applications. While this library is focused on react-dom,
    utilities could be included even if they don't directly relate to
    react-dom.
  3. Utility implementations and APIs should be simple and flexible.

Most importantly, we want React Testing Library to be pretty light-weight,
simple, and easy to understand.

Docs

Read The Docs |
Edit the docs

Issues

Looking to contribute? Look for the Good First Issue label.

๐Ÿ› Bugs

Please file an issue for bugs, missing documentation, or unexpected behavior.

See Bugs

๐Ÿ’ก Feature Requests

Please file an issue to suggest new features. Vote on feature requests by adding
a ๐Ÿ‘. This helps maintainers prioritize what to work on.

See Feature Requests

โ“ Questions

For questions related to using the library, please visit a support community
instead of filing an issue on GitHub.

Contributors

Thanks goes to these people (emoji key):

Kent C. Dodds๐Ÿ’ป ๐Ÿ“– ๐Ÿš‡ โš ๏ธ Ryan Castner๐Ÿ“– Daniel Sandiego๐Ÿ’ป Paweล‚ Mikoล‚ajczyk๐Ÿ’ป Alejandro ร‘รกรฑez Ortiz๐Ÿ“– Matt Parrish๐Ÿ› ๐Ÿ’ป ๐Ÿ“– โš ๏ธ Justin Hall๐Ÿ“ฆ
Anto Aravinth๐Ÿ’ป โš ๏ธ ๐Ÿ“– Jonah Moses๐Ÿ“– ลukasz Gandecki๐Ÿ’ป โš ๏ธ ๐Ÿ“– Ivan Babak๐Ÿ› ๐Ÿค” Jesse Day๐Ÿ’ป Ernesto Garcรญa๐Ÿ’ฌ ๐Ÿ’ป ๐Ÿ“– Josef Maxx Blake๐Ÿ’ป ๐Ÿ“– โš ๏ธ
Michal Baranowski๐Ÿ“ โœ… Arthur Puthin๐Ÿ“– Thomas Chia๐Ÿ’ป ๐Ÿ“– Thiago Galvani๐Ÿ“– Christianโš ๏ธ Alex Krolick๐Ÿ’ฌ ๐Ÿ“– ๐Ÿ’ก ๐Ÿค” Johann Hubert Sonntagbauer๐Ÿ’ป ๐Ÿ“– โš ๏ธ
Maddi Joyce๐Ÿ’ป Ryan Vice๐Ÿ“– Ian Wilson๐Ÿ“ โœ… Daniel๐Ÿ› ๐Ÿ’ป Giorgio Polvara๐Ÿ› ๐Ÿค” John Gozde๐Ÿ’ป Sam Horton๐Ÿ“– ๐Ÿ’ก ๐Ÿค”
Richard Kotze (mobile)๐Ÿ“– Brahian E. Soto Mercedes๐Ÿ“– Benoit de La Forest๐Ÿ“– Salah๐Ÿ’ป โš ๏ธ Adam Gordon๐Ÿ› ๐Ÿ’ป Matija Marohniฤ‡๐Ÿ“– Justice Mba๐Ÿ“–
Mark Pollmann๐Ÿ“– Ehtesham Kafeel๐Ÿ’ป ๐Ÿ“– Julio Pavรณn๐Ÿ’ป Duncan L๐Ÿ“– ๐Ÿ’ก Tiago Almeida๐Ÿ“– Robert Smith๐Ÿ› Zach Green๐Ÿ“–
dadamssg๐Ÿ“– Yazan Aabed๐Ÿ“ Tim๐Ÿ› ๐Ÿ’ป ๐Ÿ“– โš ๏ธ Divyanshu Maithaniโœ… ๐Ÿ“น Deepak Groverโœ… ๐Ÿ“น Eyal Cohen๐Ÿ“– Peter Makowski๐Ÿ“–
Michiel Nuyts๐Ÿ“– Joe Ng'ethe๐Ÿ’ป ๐Ÿ“– Kate๐Ÿ“– Sean๐Ÿ“– James Long๐Ÿค” ๐Ÿ“ฆ Herb Hagely๐Ÿ’ก Alex Wendte๐Ÿ’ก
Monica Powell๐Ÿ“– Vitaly Sivkov๐Ÿ’ป Weyert de Boer๐Ÿค” ๐Ÿ‘€ ๐ŸŽจ EstebanMarin๐Ÿ“– Victor Martins๐Ÿ“– Royston Shufflebotham๐Ÿ› ๐Ÿ“– ๐Ÿ’ก chrbala๐Ÿ’ป
Donavon West๐Ÿ’ป ๐Ÿ“– ๐Ÿค” โš ๏ธ Richard Maisano๐Ÿ’ป Marco Biedermann๐Ÿ’ป ๐Ÿšง โš ๏ธ Alex Zherdev๐Ÿ› ๐Ÿ’ป Andrรฉ Matulionis dos Santos๐Ÿ’ป ๐Ÿ’ก โš ๏ธ Daniel K.๐Ÿ› ๐Ÿ’ป ๐Ÿค” โš ๏ธ ๐Ÿ‘€ mohamedmagdy17593๐Ÿ’ป
Loren โ˜บ๏ธ๐Ÿ“– MarkFalconbridge๐Ÿ› ๐Ÿ’ป Vinicius๐Ÿ“– ๐Ÿ’ก Peter Schyma๐Ÿ’ป Ian Schmitz๐Ÿ“– Joel Marcotte๐Ÿ› โš ๏ธ ๐Ÿ’ป Alejandro Dustet๐Ÿ›
Brandon Carroll๐Ÿ“– Lucas Machado๐Ÿ“– Pascal Duez๐Ÿ“ฆ Minh Nguyen๐Ÿ’ป LiaoJimmy๐Ÿ“– Sunil Pai๐Ÿ’ป โš ๏ธ Dan Abramov๐Ÿ‘€
Christian Murphy๐Ÿš‡ Ivakhnenko Dmitry๐Ÿ’ป James George๐Ÿ“– Joรฃo Fernandes๐Ÿ“– Alejandro Perea๐Ÿ‘€ Nick McCurdy๐Ÿ‘€ ๐Ÿ’ฌ ๐Ÿš‡ Sebastian Silbermann๐Ÿ‘€
Adriร  Fontcuberta๐Ÿ‘€ ๐Ÿ“– John Reilly๐Ÿ‘€ Michaรซl De Boey๐Ÿ‘€ ๐Ÿ’ป Tim Yates๐Ÿ‘€ Brian Donovan๐Ÿ’ป Noam Gabriel Jacobson๐Ÿ“– Ronald van der Kooijโš ๏ธ ๐Ÿ’ป
Aayush Rajvanshi๐Ÿ“– Ely Alamillo๐Ÿ’ป โš ๏ธ Daniel Afonso๐Ÿ’ป โš ๏ธ Laurens Bosscher๐Ÿ’ป Sakito Mukai๐Ÿ“– Tรผrker Teke๐Ÿ“– Zach Brogan๐Ÿ’ป โš ๏ธ
Ryota Murakami๐Ÿ“– Michael Hottman๐Ÿค” Steven Fitzpatrick๐Ÿ› Juan Je Garcรญa๐Ÿ“– Championrunner๐Ÿ“– Sam Tsai๐Ÿ’ป โš ๏ธ ๐Ÿ“– Christian Rackerseder๐Ÿ’ป
Andrei Picus๐Ÿ› ๐Ÿ‘€ Artem Zakharchenko๐Ÿ“– Michael๐Ÿ“– Braden Lee๐Ÿ“– Kamran Ayub๐Ÿ’ป โš ๏ธ Matan Borenkraout๐Ÿ’ป Ryan Bigg๐Ÿšง
Anton Halim๐Ÿ“– Artem Malko๐Ÿ’ป Gerrit Alex๐Ÿ’ป Karthick Raja๐Ÿ’ป Abdelrahman Ashraf๐Ÿ’ป Lidor Avitan๐Ÿ“– Jordan Harband๐Ÿ‘€ ๐Ÿค”
Marco Moretti๐Ÿ’ป sanchit121๐Ÿ› ๐Ÿ’ป Solufa๐Ÿ› ๐Ÿ’ป Ari Perkkiรถโš ๏ธ Johannes Ewald๐Ÿ’ป Angus J. Pope๐Ÿ“– Dominik Lesch๐Ÿ“–
Marcos Gรณmez๐Ÿ“– Akash Shyam๐Ÿ› Fabian Meumertzheim๐Ÿ’ป ๐Ÿ› Sebastian Malton๐Ÿ› ๐Ÿ’ป Martin Bรถttcher๐Ÿ’ป Dominik Dorfmeister๐Ÿ’ป Stephen Sauceda๐Ÿ“–
Colin Diesh๐Ÿ“– Yusuke Iinuma๐Ÿ’ป Jeff Way๐Ÿ’ป Bernardo Belchior๐Ÿ’ป ๐Ÿ“–

This project follows the all-contributors specification.
Contributions of any kind welcome!

LICENSE

MIT

2. Official Technical Reference & Guides (testing-library/testing-library-docs)

File: README.md

testing-library-docs

[
Code of Conduct

Documentation site for
React Testing Library,
DOM Testing Library,
Angular Testing Library,
and related projects

https://testing-library.com

Build Status:

Netlify Status

This website was created with Docusaurus.

What's In This Document

Get Started in 5 Minutes

  1. Make sure all the dependencies for the website are installed:
sh
# Install dependencies
$ npm install
  1. Run your dev server:
sh
# Start the site
$ npm start

Editing Content

Editing an existing docs page

Edit docs by navigating to docs/ and editing the corresponding document:

docs/doc-to-be-edited.mdx

markdown
---
id: page-needs-edit
title: This Doc Needs To Be Edited
---

Edit me...

For more information about docs, click here

Editing an existing blog post

Edit blog posts by navigating to blog and editing the corresponding post:

blog/post-to-be-edited.mdx

markdown
---
id: post-needs-edit
title: This Blog Post Needs To Be Edited
---

Edit me...

For more information about blog posts, click
here

Adding Content

Adding a new docs page to an existing sidebar

  1. Create the doc as a new markdown file in /docs, example
    docs/newly-created-doc.mdx:
md
---
id: newly-created-doc
title: This Doc Needs To Be Edited
---

My new content here..

Note: Ensure the file name and the id value do not include non-url safe
characters i.e. '*'.

  1. Refer to that doc's ID in an existing sidebar in sidebar.json:
javascript
// Add newly-created-doc to the Getting Started category of docs
{
  "docs": {
    "Getting Started": [
      "quick-start",
      "newly-created-doc" // new doc here
    ],
    ...
  },
  ...
}

For more information about adding new docs, click
here

Contributors

Thanks goes to these wonderful people
(emoji key):

Kent C. Dodds๐Ÿšง Alex Krolick๐Ÿšง Sidak Singh Aulakh๐Ÿ’ป Brandon Carroll๐Ÿ’ป David๐Ÿ“– Ryan James๐Ÿ“– Brandon Johnson๐Ÿ“–
Edward Coleridge Smith๐Ÿ“– Adriร  Fontcuberta๐Ÿ“– ๐Ÿ‘€ Tim Deschryver๐Ÿ“– ๐Ÿ’ป Ben Monro๐Ÿ“– Scott Sauber๐Ÿ“ Shota Tamura๐Ÿ–‹ ๐Ÿ“– Giorgio Polvara๐Ÿ“–
michalak111๐Ÿ“– โš ๏ธ Huyen Nguyen๐Ÿ“– Kieren Hughes๐Ÿ“– Sean McPherson๐Ÿ“– Michael Lasky๐Ÿ“– Thomas Lombart๐Ÿ“– Patrick K Long๐Ÿ“–
Pedro Filho๐Ÿ“– Tanguy Antoine๐Ÿ“– Kevin Anderson๐Ÿ“– Dustin Myers๐Ÿ“– Vojta Holik๐ŸŽจ Steve Schwarz๐Ÿ“– Aayush Rajvanshi๐Ÿ“–
Eugie Limpin๐Ÿ“– Kevin๐Ÿ“– Jennifer Shehane๐Ÿ“– Steve Taggart๐Ÿ“– Stephen Sugden๐Ÿ“– Blai Samitier๐Ÿ“– Vernon Kesner๐Ÿ“–
Will Douglas๐Ÿ“– Head๐Ÿ“– Lee๐Ÿ“– Mario Beltrรกn Alarcรณn๐Ÿ“– jameslevine๐Ÿ“– Rahim Alwer๐Ÿ“– Chenjia๐Ÿ“–
Olivier Le Thanh Duong๐Ÿ“– Jakub Jastrzฤ™bski๐Ÿ“– Ivan Galiatin๐Ÿ“– Hendrik Rรถhm๐Ÿ“– Sam Kauffman๐Ÿ“– Turadg Aleahmad๐Ÿ“– mark g romano๐Ÿ“–
Arturo Romero๐Ÿ“– Dustin Masters๐Ÿ“– Darren Lester๐Ÿ“– Iswara Chaitanya๐Ÿ“– Nataliia Pylypenko๐Ÿ“– Hu Chen๐Ÿ“– Josh๐Ÿ“–
numb86๐Ÿ“– Nicholas Boll๐Ÿ“– Billy Matthews๐Ÿ“ข ๐Ÿ“– Dale French๐Ÿ“– aw-davidson๐Ÿ“– Benjamin Blackwood๐Ÿ“– Ben๐Ÿ“–
Daniel Afonso๐Ÿ“– Noman Gul๐Ÿ“– Rafael Souza๐Ÿ“– Pavel Pustovalov๐Ÿ“– Dyma๐Ÿ“– Matan Borenkraout๐Ÿ“– ๐Ÿ’ป timrobinson33๐Ÿ“–
Manuel Duguรฉ๐Ÿ“– karthik20๐Ÿ“– Pob Ch๐Ÿ“– Mohammad Kermani๐Ÿ“– Adeel Imran๐Ÿ“– Varun Dey๐Ÿ“– Pablo R. Dinella๐Ÿ“–
Jamie๐Ÿ“– Cory House๐Ÿ“– Jack Zhao๐Ÿ“– Ryan Kennel๐Ÿ“– Jesus Hernandez๐Ÿ“– Aaron Pettengill๐Ÿ“– Izhaki๐Ÿ“–
Robin Wieruchโœ… Alexander Sokolov๐Ÿ“– Sascha Tandel๐Ÿ“– Gyuwon Yi๐Ÿ“– Boris Serdiuk๐Ÿ“– balavishnuvj๐Ÿ“– Sharmila Jesupaul๐Ÿ“–
Batuhan Wilhelm๐Ÿ“– Dennis Kaffer๐Ÿ“– Cam Jackson๐Ÿ“– Jared Luxenberg๐Ÿ“– Yakir Narkis๐Ÿ“– Rahul Bhooteshwar๐Ÿ“– Maja Wichrowska๐Ÿ“–
Kermani๐Ÿ“– ๐Ÿ‘€ Vasily Malykhin๐Ÿ“– Brian Alexis๐Ÿ“– Kalpesh Singh๐Ÿ“– Gerrit Alex๐Ÿ“– Winter LaMon๐Ÿ“– Juliano Penna๐Ÿ“–
Paul Coroneos๐Ÿ“– Sebastian Silbermann๐Ÿ“– ๐Ÿ‘€ Paul Salaets๐Ÿ“– Michaรซl De Boey๐Ÿ“– Washington Soares๐Ÿ“– Jami Suomalainen๐Ÿ“– Oriol Puig๐Ÿ“–
hedgecox๐Ÿ“– Sherman Hui๐Ÿ“– Jesu Castillo๐Ÿ“– Core HTML5 Canvas, the book๐Ÿ“– John Sterling๐Ÿ“– Velu S Gautam๐Ÿ“– Richard Oliver Bray๐Ÿ“–
Yanlin Jiang๐Ÿ“– Lidor Avitan๐Ÿ“– Isaiah Thomason๐Ÿ“– Denis Barushev๐Ÿ“– Domas๐Ÿ“– Anton Niklasson๐Ÿ“– Nikolai Yakuschenko๐Ÿ“–
Jan Schrรถder๐Ÿ“– Nick McCurdy๐Ÿ“– ๐Ÿ‘€ ๐Ÿ’ป Sudhanshu๐Ÿ“– Aleksandr Chernov๐Ÿ“– Mathias๐Ÿ“– davidseow๐Ÿ“– Tony Hallett๐Ÿ“–
prsdta๐Ÿ“– tal-joffe๐Ÿ“– Mayank Jethva๐Ÿ“– Elad Israeli๐Ÿ“– Francis Chartrand๐Ÿ“– Preston Carman๐Ÿ“– Olivier Wilkinson๐Ÿ“–
Amit Miran๐Ÿ“– Paul Melero๐Ÿ“– jonathan schatz๐Ÿ“– Ricky Sullivan Himself๐Ÿ“– Armin๐Ÿ“– Dale Baldwin๐Ÿ“– AdriSolid๐Ÿ“–
Naruth Kongurai๐Ÿ“– Erfan Mirzapour๐Ÿ“– Shem Mahluf๐Ÿ’ป ๐Ÿš‡ ๐Ÿ“– Phil Gibbins๐Ÿ“– Liad Shiran๐Ÿ“– Eduardo Simรณn Picรณn๐Ÿ“– Sanjeev Sharma๐Ÿ“–
dror-heller๐Ÿ“– Aleksei Arro๐Ÿ“– Carlo Beltrame๐Ÿ“– ggorlen๐Ÿ“– mattstobbs๐Ÿ“– Zach๐Ÿ“– Angus J. Pope๐Ÿ“–
Dylan Piercey๐Ÿ“– Ruhollah๐Ÿ“– Michael Gwynne๐Ÿ“– Dominik Broj๐Ÿ“– Stephen Wade๐Ÿ“– Luiz Baldi๐Ÿ“– Thomas Ingram๐Ÿ“–
David Johnston๐Ÿ“– Rupert McKay๐Ÿ“– Sebastiรกn Maciel๐Ÿ“– Sidharth Vinod๐Ÿ“– Honza Kalfus๐Ÿ“– Christopher Laidler๐Ÿ“– Nik Savchenko๐Ÿ“–
Steven Frieson๐Ÿ“– Andrew Rosรกrio๐Ÿ“– Daniel RB๐Ÿ“– HonkingGoose๐Ÿ“– Daniel Kolev๐Ÿ“– Arryangga Aliev Pratamaputra๐Ÿ“– Andrew Hansen๐Ÿ“–
JOAO GABRIEL SANTOS NEVES๐Ÿ“– Luke Ingalls๐Ÿ“– Aleksey Levenstein๐Ÿ“– Tomas Zaicevas๐Ÿ“– Sriram Thiagarajan๐Ÿ“– Esteban Borai๐Ÿ“– Arti Villa๐Ÿ“–
Jake Boone๐Ÿ“– Dennis273๐Ÿ“– Mosh Feu๐Ÿ“– Notas Hellout๐Ÿ“– Max Smolens๐Ÿ“– Nima Ebrazeh๐Ÿ“– Philipp Fritsche๐Ÿ‘€
Clรฉment Plantier๐Ÿ“– pppp606๐Ÿ“– Bilou๐Ÿ“– David Hewson๐Ÿ“– Alex Kim๐Ÿ“– PaquitoSoft๐Ÿ“– Mรกrcio Gabriel๐Ÿ“–
Krychaxp๐Ÿ“– momokolo๐Ÿ“– AndyG๐Ÿ“– Jason Butz๐Ÿš‡ Oleg๐Ÿ“– Dany Paredes๐Ÿ“– Abel๐Ÿ“–
Patrick Brady๐Ÿ“– Grant Eaton๐Ÿ“– Aaron Dunphy๐Ÿ“– Tom Mrazauskas๐Ÿ“– Supermaryy๐Ÿ“– Ben Newton๐Ÿ“– Matija Marohniฤ‡๐Ÿ“–
Thaddeus Jiang๐Ÿ“– Robin Drexler๐Ÿ“– Thomas McKee๐Ÿ“– satanTime๐Ÿ“– polinamochan๐Ÿ“– Shai Rose๐Ÿ“– AldinRekic๐ŸŽจ
Son Nguyen๐Ÿ“– Lirlev48๐Ÿ“– Tarjei Huse๐Ÿ“– Obie Munoz๐Ÿ“– Bert B๐Ÿ“– Alireza Heydari๐Ÿ“– Gleb Radutsky๐Ÿ“–
giovanniPepi๐Ÿ“– Maciej Jastrzebski๐Ÿ“– Sergio Moreno๐Ÿ’ป David Nixon๐Ÿ“– Anton Khitrenovich๐Ÿ“– Kostas Minaidis๐Ÿ“– Than Hutchins๐Ÿ“–
Jordan Edmunds๐Ÿ“– mouse๐Ÿ“– Roberto Molina๐Ÿ“– Louis Young๐Ÿ“– Lukas Elmer๐Ÿ“– Brent Guffens๐Ÿ“– Esteban๐Ÿ“–
Tibor Barsi๐Ÿ“– Tomoya Kashifuku๐Ÿ“– Leo๐Ÿ“– Erik Metz๐Ÿ“– Vaibhav Tyagi๐Ÿ“– Aleksei Drokin๐Ÿ“– Torsten Knauf๐Ÿ“–
John Harlow๐Ÿ“– Morgan Hunter๐Ÿ“– Louis Moselhi๐Ÿ“– Ryan McGill๐Ÿ“– Renan Andrade๐Ÿ“– Vasilii Boldurean๐Ÿ“– Josias Schneider๐Ÿ“–
Denis LE๐Ÿ“– Nicolas Frizzarin๐Ÿ“– Santosh Yadav๐Ÿ“– Ilรช Caian๐Ÿ“– Alex Khomenko๐Ÿ“– Luรญs Campos๐Ÿ“– Alexandr Zhidovlenko๐Ÿ“–
lyannel๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ Yanick Champoux๐Ÿ“– Ali๐Ÿ“– Milan Jaritz๐Ÿ“– Rokas Brazdลพionis๐Ÿ“– Laforge Thomas๐Ÿ“– Steph Nathai๐Ÿ’ป ๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ
Frieder Bluemle๐Ÿ“– Gromit (์ „๋ฏผ์žฌ)๐Ÿ“– Cesar S๐Ÿ“– Corbin Crutchley๐Ÿ“– Roman Batsenko๐Ÿ“– snjro๐Ÿ“– taro๐Ÿ“–
Andreas Nordahl๐Ÿ“– neaumusic๐Ÿ“– Joyel Johny๐Ÿ’ป bsheps๐Ÿ“– Kyle Nazario๐Ÿ“– Giuliano Crivelli๐Ÿ“– mrkv๐Ÿ“–
smk267๐Ÿš‡ Dylan Gordon๐Ÿ“– Michael Cousins๐Ÿ“– ๐Ÿ‘€ Artem Zakharchenko๐Ÿ“– Vadim Shvetsov๐Ÿ“– Domantas Petrauskas๐Ÿ“– Efim๐Ÿ“–
denisx๐Ÿ’ป Giovanni Gualiato๐Ÿ“– Saud Baig๐Ÿ“– Ren Adachi๐Ÿ“– Ty Mick๐Ÿ“– Enmanuel Durรกn๐Ÿ“– Galeel Bhasha Satthar๐Ÿ“–
Ian Lรฉtourneau๐Ÿ“– brianlu2610๐Ÿ’ป Erin๐Ÿ“– Nan Chen๐Ÿ“– Alexander Burdiss๐Ÿ“– Peter Hentges๐Ÿ“– neknalb๐Ÿ“–
fetsorn๐Ÿ“– Uaena_Alex_John๐Ÿ“– zakingslayerv22๐Ÿ“– time1043๐Ÿ“– Brandon Zylstra๐Ÿ“– Matt Morse๐Ÿ“–

This project follows the
all-contributors
specification. Contributions of any kind welcome!


File: docs/queries/about.mdx


id: about title: About Queries

import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'

Overview

Queries are the methods that Testing Library gives you to find elements on the
page. There are several types of queries ("get", "find",
"query"); the difference between them is whether the query will throw an error
if no element is found or if it will return a Promise and retry. Depending on
what page content you are selecting, different queries may be more or less
appropriate. See the priority guide for recommendations on how to
make use of semantic queries to test your page in the most accessible way.

After selecting an element, you can use the
Events API or
user-event to fire events and simulate user interactions
with the page, or use Jest and jest-dom to make
assertions about the element.

There are Testing Library helper methods that work with queries. As elements
appear and disappear in response to actions,
Async APIs like
waitFor or
findBy queries can be used
to await the changes in the DOM. To find only elements that are children of a
specific element, you can use within. If
necessary, there are also a few options you can
configure, like the timeout for
retries and the default testID attribute.

Example

jsx
import {render, screen} from '@testing-library/react' // (or /dom, /vue, ...)

test('should show login form', () => {
  render(<Login />)
  const input = screen.getByLabelText('Username')
  // Events and assertions...
})

Types of Queries

  • Single Elements
    • getBy...: Returns the matching node for a query, and throw a descriptive
      error if no elements match or if more than one match is found (use
      getAllBy instead if more than one element is expected).
    • queryBy...: Returns the matching node for a query, and return null if no
      elements match. This is useful for asserting an element that is not present.
      Throws an error if more than one match is found (use queryAllBy instead if
      this is OK).
    • findBy...: Returns a Promise which resolves when an element is found which
      matches the given query. The promise is rejected if no element is found or
      if more than one element is found after a default timeout of 1000ms. If you
      need to find more than one element, use findAllBy.
  • Multiple Elements
    • getAllBy...: Returns an array of all matching nodes for a query, and
      throws an error if no elements match.
    • queryAllBy...: Returns an array of all matching nodes for a query, and
      return an empty array ([]) if no elements match.
    • findAllBy...: Returns a promise which resolves to an array of elements
      when any elements are found which match the given query. The promise is
      rejected if no elements are found after a default timeout of 1000ms.
      • findBy methods are a combination of getBy* queries and
        waitFor. They accept the
        waitFor options as the last argument (i.e.
        await screen.findByText('text', queryOptions, waitForOptions))

Summary Table

Type of Query 0 Matches 1 Match >1 Matches Retry (Async/Await)
Single Element
getBy... Throw error Return element Throw error No
queryBy... Return null Return element Throw error No
findBy... Throw error Return element Throw error Yes
Multiple Elements
getAllBy... Throw error Return array Return array No
queryAllBy... Return [] Return array Return array No
findAllBy... Throw error Return array Return array Yes

Priority

Based on the Guiding Principles, your test should
resemble how users interact with your code (component, page, etc.) as much as
possible. With this in mind, we recommend this order of priority:

  1. Queries Accessible to Everyone Queries that reflect the experience of
    visual/mouse users as well as those that use assistive technology.
    1. getByRole: This can be used to query every element that is exposed in
      the
      accessibility tree.
      With the name option you can filter the returned elements by their
      accessible name. This should be your
      top preference for just about everything. There's not much you can't get
      with this (if you can't, it's possible your UI is inaccessible). Most
      often, this will be used with the name option like so:
      getByRole('button', {name: /submit/i}). Check the
      list of roles.
    2. getByLabelText: This method is really good for form fields. When
      navigating through a website form, users find elements using label text.
      This method emulates that behavior, so it should be your top preference.
    3. getByPlaceholderText:
      A placeholder is not a substitute for a label.
      But if that's all you have, then it's better than alternatives.
    4. getByText: Outside of forms, text content is the main way users find
      elements. This method can be used to find non-interactive elements (like
      divs, spans, and paragraphs).
    5. getByDisplayValue: The current value of a form element can be useful
      when navigating a page with filled-in values.
  2. Semantic Queries HTML5 and ARIA compliant selectors. Note that the user
    experience of interacting with these attributes varies greatly across
    browsers and assistive technology.
    1. getByAltText: If your element is one which supports alt text (img,
      area, input, and any custom element), then you can use this to find
      that element.
    2. getByTitle: The title attribute is not consistently read by
      screenreaders, and is not visible by default for sighted users
  3. Test IDs
    1. getByTestId: The user cannot see (or hear) these, so this is only
      recommended for cases where you can't match by role or text or it doesn't
      make sense (e.g. the text is dynamic).

Using Queries

The base queries from DOM Testing Library require you to pass a container as
the first argument. Most framework-implementations of Testing Library provide a
pre-bound version of these queries when you render your components with them
which means you do not have to provide a container. In addition, if you just
want to query document.body then you can use the screen export as
demonstrated below (using screen is recommended).

The primary argument to a query can be a string, regular expression, or
function. There are also options to adjust how node text is parsed. See
TextMatch for documentation on what can be passed to a query.

Given the following DOM elements (which can be rendered by React, Vue, Angular,
or plain HTML code):

js
<label for="username-input">Username</label>

You can use a query to find an element (byLabelText, in this case):

js
import {screen, getByLabelText} from '@testing-library/dom'

// With screen:
const inputNode1 = screen.getByLabelText('Username')

// Without screen, you need to provide a container:
const container = document.querySelector('#app')
const inputNode2 = getByLabelText(container, 'Username')

`queryOptions`

You can pass a queryOptions object with the query type. See the docs for each
query type to see available options, e.g. byRole API.

`screen`

All of the queries exported by DOM Testing Library accept a container as the
first argument. Because querying the entire document.body is very common, DOM
Testing Library also exports a screen object which has every query that is
pre-bound to document.body (using the
within functionality). Wrappers such as
React Testing Library re-export screen so you can use it the same way.

Here's how you use it:

<Tabs
defaultValue="native"
values={[
{ label: 'Native', value: 'native', },
{ label: 'React', value: 'react', },
{ label: 'Angular', value: 'angular', },
{ label: 'Cypress', value: 'cypress', },
]
}>

js
import {screen} from '@testing-library/dom'

document.body.innerHTML = `
  <label for="example">Example</label>
  
`

const exampleInput = screen.getByLabelText('Example')
jsx
import {render, screen} from '@testing-library/react'

render(
  
    <label htmlFor="example">Example</label>
    
  ,
)

const exampleInput = screen.getByLabelText('Example')
ts
import {render, screen} from '@testing-library/angular'

await render(`
  
    <label for="example">Example</label>
    
  
`)

const exampleInput = screen.getByLabelText('Example')
js
cy.findByLabelText('Example').should('exist')

Note

You need a global DOM environment to use screen. If you're using jest, with
the
testEnvironment
set to jsdom, a global DOM environment will be available for you.

If you're loading your test with a script tag, make sure it comes after the
body. An example can be seen
here.

`TextMatch`

Most of the query APIs take a TextMatch as an argument, which means the
argument can be either a string, regex, or a function of signature
(content?: string, element?: Element | null) => boolean which returns true
for a match and false for a mismatch.

TextMatch Examples

Given the following HTML:

html
Hello World

Will find the div:

javascript
// Matching a string:
screen.getByText('Hello World') // full string match
screen.getByText('llo Worl', {exact: false}) // substring match
screen.getByText('hello world', {exact: false}) // ignore case

// Matching a regex:
screen.getByText(/World/) // substring match
screen.getByText(/world/i) // substring match, ignore case
screen.getByText(/^hello world$/i) // full string match, ignore case
screen.getByText(/Hello W?oRlD/i) // substring match, ignore case, searches for "hello world" or "hello orld"

// Matching with a custom function:
screen.getByText((content, element) => content.startsWith('Hello'))

Will not find the div:

javascript
// full string does not match
screen.getByText('Goodbye World')

// case-sensitive regex with different case
screen.getByText(/hello world/)

// function looking for a span when it's actually a div:
screen.getByText((content, element) => {
  return element.tagName.toLowerCase() === 'span' && content.startsWith('Hello')
})

Precision

Queries that take a TextMatch also accept an object as the final argument that
can contain options that affect the precision of string matching:

  • exact: Defaults to true; matches full strings, case-sensitive. When false,
    matches substrings and is not case-sensitive.
    • it has no effect when used together with regex or function arguments.
    • in most cases, using a regex instead of a string combined with { exact: false }
      gives you more control over fuzzy matching so it should be preferred.
  • normalizer: An optional function which overrides normalization behavior. See
    Normalization.

Normalization

Before running any matching logic against text in the DOM, DOM Testing Library
automatically normalizes that text. By default, normalization consists of
trimming whitespace from the start and end of text, and collapsing multiple
adjacent whitespace characters within the string into a single space
.

If you want to prevent that normalization, or provide alternative normalization
(e.g. to remove Unicode control characters), you can provide a normalizer
function in the options object. This function will be given a string and is
expected to return a normalized version of that string.

Note

Specifying a value for normalizer replaces the built-in normalization, but
you can call getDefaultNormalizer to obtain a built-in normalizer, either to
adjust that normalization or to call it from your own normalizer.

getDefaultNormalizer takes an options object which allows the selection of
behaviour:

  • trim: Defaults to true. Trims leading and trailing whitespace
  • collapseWhitespace: Defaults to true. Collapses inner whitespace
    (newlines, tabs, repeated spaces) into a single space.

Normalization Examples

To perform a match against text without trimming:

javascript
screen.getByText('text', {
  normalizer: getDefaultNormalizer({trim: false}),
})

To override normalization to remove some Unicode characters whilst keeping some
(but not all) of the built-in normalization behavior:

javascript
screen.getByText('text', {
  normalizer: str =>
    getDefaultNormalizer({trim: false})(str).replace(/[\u200E-\u200F]*/g, ''),
})

Manual Queries

On top of the queries provided by the testing library, you can use the regular
querySelector DOM API
to query elements. Note that using this as an escape hatch to query by class or
id is not recommended because they are invisible to the user. Use a testid if
you have to, to make your intention to fall back to non-semantic queries clear
and establish a stable API contract in the HTML.

jsx
// @testing-library/react
const {container} = render(<MyComponent />)
const foo = container.querySelector('[data-foo="bar"]')

Browser extension

Do you still have problems knowing how to use Testing Library queries?

There is a very cool Browser extension for Chrome named
Testing Playground,
and it helps you find the best queries to select elements. It allows you to
inspect the element hierarchies in the Browser's Developer Tools, and provides
you with suggestions on how to select them, while encouraging good testing
practices.

Playground

If you want to get more familiar with these queries, you can try them out on
testing-playground.com. Testing Playground is
an interactive sandbox where you can run different queries against your own
html, and get visual feedback matching the rules mentioned above.


File: docs/queries/byalttext.mdx


id: byalttext title: ByAltText

import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'

getByAltText, queryByAltText, getAllByAltText, queryAllByAltText,
findByAltText, findAllByAltText

API

typescript
getByAltText(
  // If you're using `screen`, then skip the container argument:
  container: HTMLElement,
  text: TextMatch,
  options?: {
    exact?: boolean = true,
    normalizer?: NormalizerFn,
  }): HTMLElement

This will return the element (normally an ) that has the given `alt` text. Note that it only supports elements which accept an `alt` attribute or [custom elements](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements) (since we don't know if a custom element implements `alt` or not): [](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img),
``,
and <area>
(intentionally excluding
<applet>
as it's deprecated).

html

<Tabs
defaultValue="native"
values={[
{ label: 'Native', value: 'native', },
{ label: 'React', value: 'react', },
{ label: 'Angular', value: 'angular', },
{ label: 'Cypress', value: 'cypress', },
]
}>

js
import {screen} from '@testing-library/dom'

const incrediblesPosterImg = screen.getByAltText(/incredibles.*? poster/i)
jsx
import {render, screen} from '@testing-library/react'

render(<MyComponent />)
const incrediblesPosterImg = screen.getByAltText(/incredibles.*? poster/i)
ts
import {render, screen} from '@testing-library/angular'

await render(MyComponent)
const incrediblesPosterImg = screen.getByAltText(/incredibles.*? poster/i)
js
cy.findByAltText(/incredibles.*? poster/i).should('exist')

Options

TextMatch options


File: docs/queries/bydisplayvalue.mdx


id: bydisplayvalue title: ByDisplayValue

import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'

getByDisplayValue, queryByDisplayValue, getAllByDisplayValue,
queryAllByDisplayValue, findByDisplayValue, findAllByDisplayValue

API

typescript
getByDisplayValue(
  // If you're using `screen`, then skip the container argument:
  container: HTMLElement,
  value: TextMatch,
  options?: {
    exact?: boolean = true,
    normalizer?: NormalizerFn,
  }): HTMLElement

Returns the input, textarea, or select element that has the matching
display value.

`input` tags

html
js
document.getElementById('lastName').value = 'Norris'

<Tabs
defaultValue="native"
values={[
{ label: 'Native', value: 'native', },
{ label: 'React', value: 'react', },
{ label: 'Angular', value: 'angular', },
{ label: 'Cypress', value: 'cypress', },
]
}>

js
import {screen} from '@testing-library/dom'

const lastNameInput = screen.getByDisplayValue('Norris')
jsx
import {render, screen} from '@testing-library/react'

render(<MyComponent />)
const lastNameInput = screen.getByDisplayValue('Norris')
ts
import {render, screen} from '@testing-library/angular'

await render(MyComponent)
const lastNameInput = screen.getByDisplayValue('Norris')
js
cy.findByDisplayValue('Norris').should('exist')

`textarea` tags

html
<textarea id="messageTextArea" />
js
document.getElementById('messageTextArea').value = 'Hello World'

<Tabs
defaultValue="native"
values={[
{ label: 'Native', value: 'native', },
{ label: 'React', value: 'react', },
{ label: 'Angular', value: 'angular', },
{ label: 'Cypress', value: 'cypress', },
]
}>

js
import {screen} from '@testing-library/dom'

const messageTextArea = screen.getByDisplayValue('Hello World')
jsx
import {render, screen} from '@testing-library/react'

render(<MyComponent />)
const messageTextArea = screen.getByDisplayValue('Hello World')
ts
import {render, screen} from '@testing-library/angular'

await render(MyComponent)
const messageTextArea = screen.getByDisplayValue('Hello World')
js
cy.findByDisplayValue('Hello World').should('exist')

`select` tags

In case of select, this will search for a <select> whose selected <option>
matches the given TextMatch.

html
<select>
  <option value="">State</option>
  <option value="AL">Alabama</option>
  <option selected value="AK">Alaska</option>
  <option value="AZ">Arizona</option>
</select>

<Tabs
defaultValue="native"
values={[
{ label: 'Native', value: 'native', },
{ label: 'React', value: 'react', },
{ label: 'Angular', value: 'angular', },
{ label: 'Cypress', value: 'cypress', },
]
}>

js
import {screen} from '@testing-library/dom'

const selectElement = screen.getByDisplayValue('Alaska')
jsx
import {render, screen} from '@testing-library/react'

render(<MyComponent />)
const selectElement = screen.getByDisplayValue('Alaska')
ts
import {render, screen} from '@testing-library/angular'

await render(MyComponent)
const selectElement = screen.getByDisplayValue('Alaska')
js
cy.findByDisplayValue('Alaska').should('exist')

Options

TextMatch options


File: docs/queries/bylabeltext.mdx


id: bylabeltext title: ByLabelText

import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'

getByLabelText, queryByLabelText, getAllByLabelText, queryAllByLabelText,
findByLabelText, findAllByLabelText

API

typescript
getByLabelText(
  // If you're using `screen`, then skip the container argument:
  container: HTMLElement,
  text: TextMatch,
  options?: {
    selector?: string = '*',
    exact?: boolean = true,
    normalizer?: NormalizerFn,
  }): HTMLElement

This will search for the label that matches the given
TextMatch, then find the element associated
with that label.

The example below will find the input node for the following DOM structures:

js
// for/htmlFor relationship between label and form element id
<label for="username-input">Username</label>


// The aria-labelledby attribute with form elements
<label id="username-label">Username</label>


// Wrapper labels
<label>Username </label>

// Wrapper labels where the label text is in another child element
<label>
  Username
  
</label>

// aria-label attributes
// Take care because this is not a label that users can see on the page,
// so the purpose of your input must be obvious to visual users.

<Tabs
defaultValue="native"
values={[
{ label: 'Native', value: 'native', },
{ label: 'React', value: 'react', },
{ label: 'Angular', value: 'angular', },
{ label: 'Cypress', value: 'cypress', },
]
}>

js
import {screen} from '@testing-library/dom'

const inputNode = screen.getByLabelText('Username')
jsx
import {render, screen} from '@testing-library/react'

render(<Login />)

const inputNode = screen.getByLabelText('Username')
ts
import {render, screen} from '@testing-library/angular'

await render(Login)

const inputNode = screen.getByLabelText('Username')
js
cy.findByLabelText('Username').should('exist')

Options

`name`

The example above does NOT find the input node for label text broken up by
elements. You can use getByRole('textbox', { name: 'Username' }) instead which
is robust against switching to aria-label or aria-labelledby.

`selector`

If it is important that you query a specific element (e.g. an ``) you can
provide a selector in the options:

js
// Multiple elements labelled via aria-labelledby
<label id="username">Username</label>

Please enter your username

// Multiple labels with the same text
<label>
  Username
  
</label>
<label>
  Username
  <textarea></textarea>
</label>
js
const inputNode = screen.getByLabelText('Username', {selector: 'input'})

Note

getByLabelText will not work in the case where a for attribute on a
<label> element matches an id attribute on a non-form element.

js
// This case is not valid
// for/htmlFor between label and an element that is not a form element
<section id="photos-section">
  <label for="photos-section">Photos</label>
</section>

File: docs/queries/byplaceholdertext.mdx


id: byplaceholdertext title: ByPlaceholderText

import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'

getByPlaceholderText, queryByPlaceholderText, getAllByPlaceholderText,
queryAllByPlaceholderText, findByPlaceholderText, findAllByPlaceholderText

API

typescript
getByPlaceholderText(
  // If you're using `screen`, then skip the container argument:
  container: HTMLElement,
  text: TextMatch,
  options?: {
    exact?: boolean = true,
    normalizer?: NormalizerFn,
  }): HTMLElement

This will search for all elements with a placeholder attribute and find one that
matches the given TextMatch.

html

<Tabs
defaultValue="native"
values={[
{ label: 'Native', value: 'native', },
{ label: 'React', value: 'react', },
{ label: 'Angular', value: 'angular', },
{ label: 'Cypress', value: 'cypress', },
]
}>

js
import {screen} from '@testing-library/dom'

const inputNode = screen.getByPlaceholderText('Username')
jsx
import {render, screen} from '@testing-library/react'

render(<MyComponent />)
const inputNode = screen.getByPlaceholderText('Username')
ts
import {render, screen} from '@testing-library/angular'

await render(MyComponent)
const inputNode = screen.getByPlaceholderText('Username')
js
cy.findByPlaceholderText('Username').should('exist')

Note

A placeholder is not a good substitute for a label so you should generally use
getByLabelText instead.

Options

TextMatch options


File: docs/queries/byrole.mdx


id: byrole title: ByRole

import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'

getByRole, queryByRole, getAllByRole, queryAllByRole, findByRole,
findAllByRole

API

typescript
getByRole(
  // If you're using `screen`, then skip the container argument:
  container: HTMLElement,
  role: string,
  options?: {
    hidden?: boolean = false,
    name?: TextMatch,
    description?: TextMatch,
    selected?: boolean,
    busy?: boolean,
    checked?: boolean,
    pressed?: boolean,
    suggest?: boolean,
    current?: boolean | string,
    expanded?: boolean,
    queryFallbacks?: boolean,
    level?: number,
    value?: {
      min?: number,
      max?: number,
      now?: number,
      text?: TextMatch,
    }
  }): HTMLElement

Queries for elements with the given role (and it also accepts a
TextMatch). Default roles are taken into
consideration e.g. `` has the button role without explicitly setting
the role attribute. Here you can see
a table of HTML elements with their default and desired roles.

Please note that setting a role and/or aria-* attribute that matches the
implicit ARIA semantics is unnecessary and is not recommended as these
properties are already set by the browser, and we must not use the role and
aria-* attributes in a manner that conflicts with the semantics described. For
example, a button element can't have the role attribute of heading,
because the button element has default characteristics that conflict with the
heading role.

Roles are matched literally by string equality, without inheriting from the
ARIA role hierarchy. As a result, querying a superclass role like checkbox
will not include elements with a subclass role like switch.

You can query the returned element(s) by their
accessible name or description. The
accessible name is for simple cases equal to e.g. the label of a form element,
or the text content of a button, or the value of the aria-label attribute. It
can be used to query a specific element if multiple elements with the same role
are present on the rendered content. For an in-depth guide check out
"What is an accessible name?" from TPGi.
If you only query for a single element with getByText('The name') it's
oftentimes better to use getByRole(expectedRole, { name: 'The name' }). The
accessible name query does not replace other queries such as *ByAlt or
*ByTitle. While the accessible name can be equal to these attributes, it does
not replace the functionality of these attributes. For example
`` will be returned for
getByRole('img', { name: 'fancy image' }). However, the image will not display
its description if fancy.jpg could not be loaded. Whether you want to assert
this functionality in your test or not is up to you.

:::tip input type password

Unfortunately, the spec defines that `` has no implicit
role. This means that in order to query this type of element we must fallback to
a less powerful query such as ByLabelText.

:::

Options

`hidden`

If you set hidden to true elements that are normally excluded from the
accessibility tree are considered for the query as well. The default behavior
follows https://www.w3.org/TR/wai-aria-1.2/#tree_exclusion with the exception of
role="none" and role="presentation" which are considered in the query in any
case. For example in

html
<main aria-hidden="true">
    Open dialog
  </main>
  
    Close dialog

getByRole('button') would only return the Close dialog-button. To make
assertions about the Open dialog-button you would need to use
getAllByRole('button', { hidden: true }).

The default value for hidden can
be configured.

`selected`

You can filter the returned elements by their selected state by setting
selected: true or selected: false.

For example in

html
Native
    React
    Cypress

you can get the "Native"-tab by calling getByRole('tab', { selected: true }).
To learn more about the selected state and which elements can have this state
see ARIA aria-selected.

`busy`

You can filter the returned elements by their busy state by setting busy: true
or busy: false.

For example in

html
<section>
    Login failed
    Error: Loading message...
  </section>

you can get the "Login failed" alert by calling
getByRole('alert', { busy: false }). To learn more about the busy state see
ARIA aria-busy and
MDN aria-busy attribute.

`checked`

You can filter the returned elements by their checked state by setting
checked: true or checked: false.

For example in

html
<section>
    Sugar
    Gummy bears
    Whipped cream
  </section>

you can get the "Sugar" option by calling
getByRole('checkbox', { checked: true }). To learn more about the checked
state and which elements can have this state see
ARIA aria-checked.

Note

Checkboxes have a "mixed" state, which is considered neither checked nor
unchecked (details here).

`current`

You can filter the returned elements by their current state by setting
current: boolean | string. Note that no aria-current attribute will match
current: false since false is the default value for aria-current.

For example in

html
<nav>
    [๐Ÿ‘](current/page)
    [๐Ÿ‘Ž](another/page)
  </nav>

you can get the "๐Ÿ‘" link by calling getByRole('link', { current: 'page' })
and the "๐Ÿ‘Ž" by calling getByRole('link', { current: false }). To learn more
about the current state see
ARIA aria-current.

`pressed`

Buttons can have a pressed state. You can filter the returned elements by their
pressed state by setting pressed: true or pressed: false.

For example in

html
<section>
    ๐Ÿ‘
    ๐Ÿ‘Ž
  </section>

you can get the "๐Ÿ‘" button by calling getByRole('button', { pressed: true }).
To learn more about the pressed state see
ARIA aria-pressed.

`suggest`

You can disable the ability to
throw suggestions
for a specific query by setting this value to false.
Setting this value to true will throw suggestions for the specific query.

`expanded`

You can filter the returned elements by their expanded state by setting
expanded: true or expanded: false.

For example in

html
<nav>
    
      <li>
        <a aria-expanded="false" aria-haspopup="true" href="..."
          >Expandable Menu Item</a
        >
        
          <li>[Submenu Item 1](#)</li>
          <li>[Submenu Item 1](#)</li>
        
      </li>
      <li>[Regular Menu Item](#)</li>
    
  </nav>

you can get the "Expandable Menu Item" link by calling
getByRole('link', { expanded: false }). To learn more about the expanded state
and which elements can have this state see
ARIA aria-expanded.

html
...

<Tabs
defaultValue="native"
values={[
{ label: 'Native', value: 'native', },
{ label: 'React', value: 'react', },
{ label: 'Angular', value: 'angular', },
{ label: 'Cypress', value: 'cypress', },
]
}>

js
import {screen} from '@testing-library/dom'

const dialogContainer = screen.getByRole('dialog')
jsx
import {render, screen} from '@testing-library/react'

render(<MyComponent />)
const dialogContainer = screen.getByRole('dialog')
ts
import {render, screen} from '@testing-library/angular'

await render(MyComponent)
const dialogContainer = screen.getByRole('dialog')
js
cy.findByRole('dialog').should('exist')

`queryFallbacks`

By default, it's assumed that the first role of each element is supported, so
only the first role can be queried. If you need to query an element by any of
its fallback roles instead, you can use queryFallbacks: true.

For example, getByRole('switch') would always match
`` because it's the first role, while
getByRole('checkbox') would not. However,
getByRole('checkbox', { queryFallbacks: true }) would enable all fallback
roles and therefore match the same element.

An element doesn't have multiple roles in a given environment. It has a single
one. Multiple roles in the attribute are evaluated from left to right until
the environment finds the first role it understands. This is useful when new
roles get introduced and you want to start supporting those as well as older
environments that don't understand that role (yet).

`level`

An element with the heading role can be queried by any heading level
getByRole('heading') or by a specific heading level using the level option
getByRole('heading', { level: 2 }).

The level option queries the element(s) with the heading role matching the
indicated level determined by the semantic HTML heading elements <h1>-<h6> or
matching the aria-level attribute.

Given the example below,

html
<section>
    <h1>Heading Level One</h1>
    <h2>First Heading Level Two</h2>
    <h3>Heading Level Three</h3>
    Second Heading Level Two
  </section>

you can query the Heading Level Three heading using
getByRole('heading', { level: 3 }).

js
getByRole('heading', {level: 1})
// <h1>Heading Level One</h1>

getAllByRole('heading', {level: 2})
// [
//   <h2>First Heading Level Two</h2>,
//   Second Heading Level Two
// ]

While it is possible to explicitly set role="heading" and aria-level
attribute on an element, it is strongly encouraged to use the semantic HTML
headings <h1>-<h6>.

To learn more about the aria-level property, see
ARIA aria-level.

The level option is only applicable to the heading role. An error will
be thrown when used with any other role.

`value`

A range widget can be queried by any value getByRole('spinbutton') or by a
specific value using the level option
getByRole('spinbutton', { value: { now: 5, min: 0, max: 10, text: 'medium' } }).

Note that you don't have to specify all properties in value. A subset is
sufficient e.g.
getByRole('spinbutton', { value: { now: 5, text: 'medium' } }).

Given the example below,

html
<section>
    
      Volume
    
    
      Pitch
    
  </section>

you can query specific spinbutton(s) with the following queries,

js
getByRole('spinbutton', {value: {now: 5}})
// Volume

getAllByRole('spinbutton', {value: {min: 0}})
// [
//   Volume,
//   Pitch
// ]

Every specified property in value must match. For example, if you query for
{value: {min: 0, now: 3}} aria-valuemin must be equal to 0 AND >
aria-valuenow must be equal to 3

The value option is only applicable to certain roles (check the linked MDN
pages below for applicable roles). An error will be thrown when used with any
other role.

To learn more about the aria-value* properties, see
MDN aria-valuemin,
MDN aria-valuemax,
MDN aria-valuenow,
MDN aria-valuetext.

`description`

You can filter the returned elements by their
accessible description
for those cases where you have several elements with the same role and they
don't have an accessible name but they do have a description. This would
be the case for elements with
alertdialog role, where the
aria-describedby attribute is used to describe the element's content.

For example in

html
<li role="alertdialog" aria-describedby="notification-id-1">
      Close
      You have unread emails
    </li>
    <li role="alertdialog" aria-describedby="notification-id-2">
      Close
      Your session is about to expire
    </li>

You can query a specific element like this

js
getByRole('alertdialog', {description: 'Your session is about to expire'})

Performance

getByRole is the most preferred query to use as it most closely resembles the
user experience, however the calculations it must perform to provide this
confidence can be expensive (particularly with large DOM trees).

Where test performance is a concern it may be desirable to trade some of this
confidence for improved performance.

getByRole performance can be improved by setting the option
hidden to true and thereby avoid expensive visibility checks.
Note that in doing so inaccessible elements will now be included in the result.

Another option may be to substitute getByRole for simpler getByLabelText and
getByText queries which can be significantly faster though less robust
alternatives.


File: docs/queries/bytext.mdx


id: bytext title: ByText

import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'

getByText, queryByText, getAllByText, queryAllByText, findByText,
findAllByText

API

typescript
getByText(
  // If you're using `screen`, then skip the container argument:
  container: HTMLElement,
  text: TextMatch,
  options?: {
    selector?: string = '*',
    exact?: boolean = true,
    ignore?: string|boolean = 'script, style',
    normalizer?: NormalizerFn,
  }): HTMLElement

This will search for all elements that have a text node with textContent
matching the given TextMatch.

html
[About โ„น๏ธ](/about)

<Tabs
defaultValue="native"
values={[
{ label: 'Native', value: 'native', },
{ label: 'React', value: 'react', },
{ label: 'Angular', value: 'angular', },
{ label: 'Cypress', value: 'cypress', },
]
}>

js
import {screen} from '@testing-library/dom'

const aboutAnchorNode = screen.getByText(/about/i)
jsx
import {render, screen} from '@testing-library/react'

render(<MyComponent />)
const aboutAnchorNode = screen.getByText(/about/i)
ts
import {render, screen} from '@testing-library/angular'

await render(MyComponent)
const aboutAnchorNode = screen.getByText(/about/i)
js
cy.findByText(/about/i).should('exist')

It also works with inputs whose type attribute is either submit or
button:

js

Options

TextMatch options, plus the following:

`selector`

Note

See getByLabelText for more details on
how and when to use the selector option

`ignore`

The ignore option accepts a query selector. If the
node.matches
returns true for that selector, the node will be ignored. This defaults to
'script, style' because generally you don't want to select these tags, but if
your content is in an inline script file, then the script tag could be returned.

If you'd rather disable this behavior, set ignore to false.


File: docs/queries/bytitle.mdx


id: bytitle title: ByTitle

import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'

getByTitle, queryByTitle, getAllByTitle, queryAllByTitle, findByTitle,
findAllByTitle

API

typescript
getByTitle(
  // If you're using `screen`, then skip the container argument:
  container: HTMLElement,
  title: TextMatch,
  options?: {
    exact?: boolean = true,
    normalizer?: NormalizerFn,
  }): HTMLElement

Returns the element that has the matching title attribute.

Will also find a title element within an SVG.

html
<svg>
  <title>Close</title>
  <g></g>
</svg>

<Tabs
defaultValue="native"
values={[
{ label: 'Native', value: 'native', },
{ label: 'React', value: 'react', },
{ label: 'Angular', value: 'angular', },
{ label: 'Cypress', value: 'cypress', },
]
}>

js
import {screen} from '@testing-library/dom'

const deleteElement = screen.getByTitle('Delete')
const closeElement = screen.getByTitle('Close')
jsx
import {render, screen} from '@testing-library/react'

render(<MyComponent />)
const deleteElement = screen.getByTitle('Delete')
const closeElement = screen.getByTitle('Close')
ts
import {render, screen} from '@testing-library/angular'

await render(MyComponent)
const deleteElement = screen.getByTitle('Delete')
const closeElement = screen.getByTitle('Close')
js
cy.findByTitle('Delete').should('exist')
cy.findByTitle('Close').should('exist')

Options

TextMatch options


File: docs/user-event/api-clipboard.mdx


id: clipboard title: Clipboard

Note that the
Clipboard API is
usually not available outside of secure context.
To enable testing of workflows involving the clipboard,
userEvent.setup() replaces window.navigator.clipboard with a
stub.

copy()

ts
copy(): Promise<DataTransfer|undefined>

Copy the current selection.

If writeToClipboard is true, this will also
write the data to the Clipboard.

cut()

ts
cut(): Promise<DataTransfer|undefined>

Cut the current selection.

If writeToClipboard is true, this will also
write the data to the Clipboard.

When performed in editable context, it removes the selected content from the
document.

paste()

ts
paste(clipboardData?: DataTransfer|string): Promise<void>

Paste data into the document.

When called without clipboardData, the content to be pasted is read from the
Clipboard.

When performed in editable context, the pasted content is inserted into the
document.