react-testing-library

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

README

React Testing Library

  <img
    height="80"
    width="80"
    alt="goat"
    src="https://raw.githubusercontent.com/testing-library/react-testing-library/main/other/goat.png"
  />

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


[Read The Docs](https://testing-library.com/react) |



[![Build Status][build-badge]][build] [![Code Coverage][coverage-badge]][coverage] [![version][version-badge]][package] [![downloads][downloads-badge]][npmtrends] [![MIT License][license-badge]][license] [![All Contributors][all-contributors-badge]](#contributors) [![PRs Welcome][prs-badge]][prs] [![Code of Conduct][coc-badge]][coc] [![Discord][discord-badge]][discord]
[![Watch on GitHub][github-watch-badge]][github-watch] [![Star on GitHub][github-star-badge]][github-star] [![Tweet][twitter-badge]][twitter]


    <img
      width="500"
      alt="TestingJavaScript.com Learn the smart, efficient way to test any JavaScript application."
      src="https://raw.githubusercontent.com/testing-library/react-testing-library/main/other/testingjavascript.jpg"
    />

Table of Contents





  - 🐛 Bugs



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.][guiding-principle]


Installation


This module is distributed via [npm][npm] which is bundled with [node][node] and
should be installed as one of your project's devDependencies:

  1. ```
  2. npm install --save-dev @testing-library/react
  3. ```

or

for installation via [yarn][yarn]

  1. ```
  2. yarn add --dev @testing-library/react
  3. ```

This library has peerDependencies listings for react and react-dom.

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

  1. ```
  2. npm install --save-dev @testing-library/react@12


  3. yarn add --dev @testing-library/react@12
  4. ```

You may also be interested in installing @testing-library/jest-dom so you can

[Docs](https://testing-library.com/react)


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:

  1. ```
  2. Warning: An update to ComponentName inside a test was not wrapped in act(...).
  3. ```

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

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

  13. afterAll(() => {
  14.   console.error = originalError
  15. })
  16. ```

Examples


Basic Example


  1. ``` js
  2. // hidden-message.js
  3. import * as React from 'react'

  4. // NOTE: React Testing Library works well with React Hooks and classes.
  5. // Your tests will be the same regardless of how you write your components.
  6. function HiddenMessage({children}) {
  7.   const [showMessage, setShowMessage] = React.useState(false)
  8.   return (
  9.     <div>
  10.       <label htmlFor="toggle">Show Message</label>
  11.       <input
  12.         id="toggle"
  13.         type="checkbox"
  14.         onChange={e => setShowMessage(e.target.checked)}
  15.         checked={showMessage}
  16.       />
  17.       {showMessage ? children : null}
  18.     </div>
  19.   )
  20. }

  21. export default HiddenMessage
  22. ```

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

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

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

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

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

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

Complex Example


  1. ``` js
  2. // login.js
  3. import * as React from 'react'

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

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

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

  14.     window
  15.       .fetch('/api/login', {
  16.         method: 'POST',
  17.         headers: {'Content-Type': 'application/json'},
  18.         body: JSON.stringify({
  19.           username: usernameInput.value,
  20.           password: passwordInput.value,
  21.         }),
  22.       })
  23.       .then(r => r.json().then(data => (r.ok ? data : Promise.reject(data))))
  24.       .then(
  25.         user => {
  26.           setState({loading: false, resolved: true, error: null})
  27.           window.localStorage.setItem('token', user.token)
  28.         },
  29.         error => {
  30.           setState({loading: false, resolved: false, error: error.message})
  31.         },
  32.       )
  33.   }

  34.   return (
  35.     <div>
  36.       <form onSubmit={handleSubmit}>
  37.         <div>
  38.           <label htmlFor="usernameInput">Username</label>
  39.           <input id="usernameInput" />
  40.         </div>
  41.         <div>
  42.           <label htmlFor="passwordInput">Password</label>
  43.           <input id="passwordInput" type="password" />
  44.         </div>
  45.         <button type="submit">Submit{state.loading ? '...' : null}</button>
  46.       </form>
  47.       {state.error ? <div role="alert">{state.error}</div> : null}
  48.       {state.resolved ? (
  49.         <div role="alert">Congrats! You're signed in!</div>
  50.       ) : null}
  51.     </div>
  52.   )
  53. }

  54. export default Login
  55. ```

  1. ``` js
  2. // __tests__/login.js
  3. // again, these first two imports are something you'd normally handle in
  4. // your testing framework configuration rather than importing them in every file.
  5. import '@testing-library/jest-dom'
  6. import * as React from 'react'
  7. // import API mocking utilities from Mock Service Worker.
  8. import {rest} from 'msw'
  9. import {setupServer} from 'msw/node'
  10. // import testing utilities
  11. import {render, fireEvent, screen} from '@testing-library/react'
  12. import Login from '../login'

  13. const fakeUserResponse = {token: 'fake_user_token'}
  14. const server = setupServer(
  15.   rest.post('/api/login', (req, res, ctx) => {
  16.     return res(ctx.json(fakeUserResponse))
  17.   }),
  18. )

  19. beforeAll(() => server.listen())
  20. afterEach(() => {
  21.   server.resetHandlers()
  22.   window.localStorage.removeItem('token')
  23. })
  24. afterAll(() => server.close())

  25. test('allows the user to login successfully', async () => {
  26.   render(<Login />)

  27.   // fill out the form
  28.   fireEvent.change(screen.getByLabelText(/username/i), {
  29.     target: {value: 'chuck'},
  30.   })
  31.   fireEvent.change(screen.getByLabelText(/password/i), {
  32.     target: {value: 'norris'},
  33.   })

  34.   fireEvent.click(screen.getByText(/submit/i))

  35.   // just like a manual tester, we'll instruct our test to wait for the alert
  36.   // to show up before continuing with our assertions.
  37.   const alert = await screen.findByRole('alert')

  38.   // .toHaveTextContent() comes from jest-dom's assertions
  39.   // otherwise you could use expect(alert.textContent).toMatch(/congrats/i)
  40.   // but jest-dom will give you better error messages which is why it's recommended
  41.   expect(alert).toHaveTextContent(/congrats/i)
  42.   expect(window.localStorage.getItem('token')).toEqual(fakeUserResponse.token)
  43. })

  44. test('handles server exceptions', async () => {
  45.   // mock the server error response for this test suite only.
  46.   server.use(
  47.     rest.post('/api/login', (req, res, ctx) => {
  48.       return res(ctx.status(500), ctx.json({message: 'Internal server error'}))
  49.     }),
  50.   )

  51.   render(<Login />)

  52.   // fill out the form
  53.   fireEvent.change(screen.getByLabelText(/username/i), {
  54.     target: {value: 'chuck'},
  55.   })
  56.   fireEvent.change(screen.getByLabelText(/password/i), {
  57.     target: {value: 'norris'},
  58.   })

  59.   fireEvent.click(screen.getByText(/submit/i))

  60.   // wait for the error message
  61.   const alert = await screen.findByRole('alert')

  62.   expect(alert).toHaveTextContent(/internal server error/i)
  63.   expect(window.localStorage.getItem('token')).toBeNull()
  64. })
  65. ```

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


You'll find runnable examples of testing with different libraries in
[the react-testing-library-examples codesandbox](https://codesandbox.io/s/github/kentcdodds/react-testing-library-examples).
Some included are:

- [react-redux](https://codesandbox.io/s/github/kentcdodds/react-testing-library-examples/tree/main/?fontsize=14&module=%2Fsrc%2F__tests__%2Freact-redux.js&previewwindow=tests)
- [react-router](https://codesandbox.io/s/github/kentcdodds/react-testing-library-examples/tree/main/?fontsize=14&module=%2Fsrc%2F__tests__%2Freact-router.js&previewwindow=tests)
- [react-context](https://codesandbox.io/s/github/kentcdodds/react-testing-library-examples/tree/main/?fontsize=14&module=%2Fsrc%2F__tests__%2Freact-context.js&previewwindow=tests)

You can also find React Testing Library examples at

Hooks


If you are interested in testing a custom hook, check out [React Hooks Testing
Library][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.][guiding-principle]


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](https://testing-library.com/react) |

Issues


Looking to contribute? Look for the [Good First Issue][good-first-issue] label.

🐛 Bugs


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

[See Bugs][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][requests]

❓ Questions


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

- [Discord][discord]
- [Stack Overflow][stackoverflow]

Contributors


Thanks goes to these people ([emoji key][emojis]):




Kent C. Dodds
Kent C. Dodds

💻 📖 🚇 ⚠️
Ryan Castner
Ryan Castner

📖
Daniel Sandiego
Daniel Sandiego

💻
Paweł Mikołajczyk
Paweł Mikołajczyk

💻
Alejandro Ñáñez Ortiz
Alejandro Ñáñez Ortiz

📖
Matt Parrish
Matt Parrish

🐛 💻 📖 ⚠️
Justin Hall
Justin Hall

📦
Anto Aravinth
Anto Aravinth

💻 ⚠️ 📖
Jonah Moses
Jonah Moses

📖
Łukasz Gandecki
Łukasz Gandecki

💻 ⚠️ 📖
Ivan Babak
Ivan Babak

🐛 🤔
Jesse Day
Jesse Day

💻
Ernesto García
Ernesto García

💬 💻 📖
Josef Maxx Blake
Josef Maxx Blake

💻 📖 ⚠️
Michal Baranowski
Michal Baranowski

📝
Arthur Puthin
Arthur Puthin

📖
Thomas Chia
Thomas Chia

💻 📖
Thiago Galvani
Thiago Galvani

📖
Christian
Christian

⚠️
Alex Krolick
Alex Krolick

💬 📖 💡 🤔
Johann Hubert Sonntagbauer
Johann Hubert Sonntagbauer

💻 📖 ⚠️
Maddi Joyce
Maddi Joyce

💻
Ryan Vice
Ryan Vice

📖
Ian Wilson
Ian Wilson

📝
Daniel
Daniel

🐛 💻
Giorgio Polvara
Giorgio Polvara

🐛 🤔
John Gozde
John Gozde

💻
Sam Horton
Sam Horton

📖 💡 🤔
Richard Kotze (mobile)
Richard Kotze (mobile)

📖
Brahian E. Soto Mercedes
Brahian E. Soto Mercedes

📖
Benoit de La Forest
Benoit de La Forest

📖
Salah
Salah

💻 ⚠️
Adam Gordon
Adam Gordon

🐛 💻
Matija Marohnić
Matija Marohnić

📖
Justice Mba
Justice Mba

📖
Mark Pollmann
Mark Pollmann

📖
Ehtesham Kafeel
Ehtesham Kafeel

💻 📖
Julio Pavón
Julio Pavón

💻
Duncan L
Duncan L

📖 💡
Tiago Almeida
Tiago Almeida

📖
Robert Smith
Robert Smith

🐛
Zach Green
Zach Green

📖
dadamssg
dadamssg

📖
Yazan Aabed
Yazan Aabed

📝
Tim
Tim

🐛 💻 📖 ⚠️
Divyanshu Maithani
Divyanshu Maithani

📹
Deepak Grover
Deepak Grover

📹
Eyal Cohen
Eyal Cohen

📖
Peter Makowski
Peter Makowski

📖
Michiel Nuyts
Michiel Nuyts

📖
Joe Ng'ethe
Joe Ng'ethe

💻 📖
Kate
Kate

📖
Sean
Sean

📖
James Long
James Long

🤔 📦
Herb Hagely
Herb Hagely

💡
Alex Wendte
Alex Wendte

💡
Monica Powell
Monica Powell

📖
Vitaly Sivkov
Vitaly Sivkov

💻
Weyert de Boer
Weyert de Boer

🤔 👀 🎨
EstebanMarin
EstebanMarin

📖
Victor Martins
Victor Martins

📖
Royston Shufflebotham
Royston Shufflebotham

🐛 📖 💡
chrbala
chrbala

💻
Donavon West
Donavon West

💻 📖 🤔 ⚠️
Richard Maisano
Richard Maisano

💻
Marco Biedermann
Marco Biedermann

💻 🚧 ⚠️
Alex Zherdev
Alex Zherdev

🐛 💻
André Matulionis dos Santos
André Matulionis dos Santos

💻 💡 ⚠️
Daniel K.
Daniel K.

🐛 💻 🤔 ⚠️ 👀
mohamedmagdy17593
mohamedmagdy17593

💻
Loren ☺️
Loren ☺️

📖
MarkFalconbridge
MarkFalconbridge

🐛 💻
Vinicius
Vinicius

📖 💡
Peter Schyma
Peter Schyma

💻
Ian Schmitz
Ian Schmitz

📖
Joel Marcotte
Joel Marcotte

🐛 ⚠️ 💻
Alejandro Dustet
Alejandro Dustet

🐛
Brandon Carroll
Brandon Carroll

📖
Lucas Machado
Lucas Machado

📖
Pascal Duez
Pascal Duez

📦
Minh Nguyen
Minh Nguyen

💻
LiaoJimmy
LiaoJimmy

📖
Sunil Pai
Sunil Pai

💻 ⚠️
Dan Abramov
Dan Abramov

👀
Christian Murphy
Christian Murphy

🚇
Ivakhnenko Dmitry
Ivakhnenko Dmitry

💻
James George
James George

📖
João Fernandes
João Fernandes

📖
Alejandro Perea
Alejandro Perea

👀
Nick McCurdy
Nick McCurdy

👀 💬 🚇
Sebastian Silbermann
Sebastian Silbermann

👀
Adrià Fontcuberta
Adrià Fontcuberta

👀 📖
John Reilly
John Reilly

👀
Michaël De Boey
Michaël De Boey

👀 💻
Tim Yates
Tim Yates

👀
Brian Donovan
Brian Donovan

💻
Noam Gabriel Jacobson
Noam Gabriel Jacobson

📖
Ronald van der Kooij
Ronald van der Kooij

⚠️ 💻
Aayush Rajvanshi
Aayush Rajvanshi

📖
Ely Alamillo
Ely Alamillo

💻 ⚠️
Daniel Afonso
Daniel Afonso

💻 ⚠️
Laurens Bosscher
Laurens Bosscher

💻
Sakito Mukai
Sakito Mukai

📖
Türker Teke
Türker Teke

📖
Zach Brogan
Zach Brogan

💻 ⚠️
Ryota Murakami
Ryota Murakami

📖
Michael Hottman
Michael Hottman

🤔
Steven Fitzpatrick
Steven Fitzpatrick

🐛
Juan Je García
Juan Je García

📖
Championrunner
Championrunner

📖
Sam Tsai
Sam Tsai

💻 ⚠️ 📖
Christian Rackerseder
Christian Rackerseder

💻
Andrei Picus
Andrei Picus

🐛 👀
Artem Zakharchenko
Artem Zakharchenko

📖
Michael
Michael

📖
Braden Lee
Braden Lee