React Testing Library

Create React App inherently supports React Testing Library.Rather than dealing with instances of rendered React components, React Testing Library works with actual DOM nodes, to resemble the way your software is used.


RESETRUNFULL
//fetch.jsimport React, {useState, useReducer} from 'react'import axios from 'axios'const initialState = {
  error: null,
  greeting: null,}function greetingReducer(state, action) {
  switch (action.type) {
    case 'SUCCESS': {
      return {
        error: null,
        greeting: action.greeting,
      }
    }
    case 'ERROR': {
      return {
        error: action.error,
        greeting: null,
      }
    }
    default: {
      return state
    }
  }}export default function Fetch({url}) {
  const [{error, greeting}, dispatch] = useReducer(
    greetingReducer,
    initialState,
  )
  const [buttonClicked, setButtonClicked] = useState(false)
  const fetchGreeting = async url =>
    axios
      .get(url)
      .then(response => {
        const {data} = response
        const {greeting} = data
        dispatch({type: 'SUCCESS', greeting})
        setButtonClicked(true)
      })
      .catch(error => {
        dispatch({type: 'ERROR', error})
      })
  const buttonText = buttonClicked ? 'Ok' : 'Load Greeting'
  return (
    <div>
      <button onClick={() => fetchGreeting(url)} disabled={buttonClicked}>
        {buttonText}
      </button>
      {greeting && <h1>{greeting}</h1>}
      {error && <p role="alert">Oops, failed to fetch!</p>}
    </div>
  )}

// __tests__/fetch.test.jsimport React from 'react'import {rest} from 'msw'import {setupServer} from 'msw/node'import {render, fireEvent, waitFor, screen} from '@testing-library/react'import '@testing-library/jest-dom'import Fetch from '../fetch'const server = setupServer(
  rest.get('/greeting', (req, res, ctx) => {
    return res(ctx.json({greeting: 'hello there'}))
  }),)beforeAll(() => server.listen())afterEach(() => server.resetHandlers())afterAll(() => server.close())test('loads and displays greeting', async () => {
  render(<Fetch url="/greeting" />)
  fireEvent.click(screen.getByText('Load Greeting'))
  await waitFor(() => screen.getByRole('heading'))
  expect(screen.getByRole('heading')).toHaveTextContent('hello there')
  expect(screen.getByRole('button')).toBeDisabled()})test('handles server error', async () => {
  server.use(
    rest.get('/greeting', (req, res, ctx) => {
      return res(ctx.status(500))
    }),
  )
  render(<Fetch url="/greeting" />)
  fireEvent.click(screen.getByText('Load Greeting'))
  await waitFor(() => screen.getByRole('alert'))
  expect(screen.getByRole('alert')).toHaveTextContent('Oops, failed to fetch!')
  expect(screen.getByRole('button')).not.toBeDisabled()})

Other APIs Other APIs Other APIs {get | find | query} [All] By

{DisplayValue | Title | Role | TestId | [Label | Placeholder | Alt] Text}

No Match 1 Match 1+ Match Await?
getBy Throw Return Throw No
findBy Throw Return Throw Yes
queryBy Null Return Throw No
getAllBy Throw Array Array No
findAllBy Throw Array Array Yes
queryAllBy [] Array array No

RESETRUNFULL
// Matching a string:getByText('Hello World') // full string matchgetByText('llo Worl', {exact: false}) // substring matchgetByText('hello world', {exact: false}) // ignore case// Matching a regex:getByText(/World/) // substring matchgetByText(/world/i) // substring match, ignore casegetByText(/^hello world$/i) // full string match, ignore casegetByText(/Hello W?oRlD/i) // advanced regex// Matching with a custom function:getByText((content, element) => content.startsWith('Hello'))

waitForElementToBeRemoved (Promise) retries the function until it no longer returns a DOM node.

act is a wrapper around react-dom/test-utils act. React Testing Library wraps render and fireEvent in a call to act already so most cases should not require using it manually.

within takes a node and returns an object with all the queries bound to the node (used to return the queries from React Testing Library's render method). Eg.: within(node).getByText("hello")

configure changes global options. Eg.:configure({testIdAttribute: 'my-data-test-id'})

cleanup clears the DOM, used with afterEach to reset DOM between tests.

r ender renders into a container which is appended to document.body.(options: container, baseElement, hydrate, wrapper, queries)


RESETRUNFULL
import {render} from '@testing-library/react'import '@testing-library/jest-dom'test('renders a message', () => {
  const {container, getByText} = render(<Greeting />)
  expect(getByText('Hello, world!')).toBeInTheDocument()
  expect(container.firstChild).toMatchInlineSnapshot(`
    <h1>Hello, World!</h1>
  `)})

RESETRUNFULL
// Example, a function to traverse table contentsimport * as tableQueries from 'my-table-query-library'import {queries} from '@testing-library/react'const {getByRowColumn, getByText} = render(<MyTable />, {
  queries: {...queries, ...tableQueries},})

render Result : ...queries, container, baseElement, debug, rerender, unmount, asFragment


RESETRUNFULL
import {render} from '@testing-library/react'const {container, unmount} = render(<Login />)unmount()// your component has been unmounted and now: container.innerHTML === ''