Today I learned

Using React testing library

react-testing-library is a very light-weight tool for testing React components. Here's a few tips on how to get started with it.

Using test ID attributes

Consider adding data-testid attributes to your components. This makes them easy to target, and lets us refer to them without having to resort to XPath or CSS.

data-testid-example.js
const TextToolbar = () => (
  <div>
    {/* Notice the data-testid attributes! */}
    <button data-testid='button:bold'>Bold</button>    <button data-testid='button:italic'>Italic</button>    <button data-testid='button:underline'>Underline</button>  </div>
)

Using test ID attributes is advocated by many testing frameworks. I first came across it in Cypress, which recommends a very similar practice.

Smoke tests using test ID's

The react-testing-library API comes with getBy functions that will raise an error if they're not found. By having a test that only has .getBy calls, we effectively make a "smoke" test that will fail if the elements are missing.

getByTestId-example.js
import { render } from 'react-testing-library'

it('works', () => {
  const { getByTestId } = render(<TextToolbar />)

  // This test will fail if one of these elements aren't present.
  co.getByTestId('button:bold')  co.getByTestId('button:italic')  co.getByTestId('button:underline')})

Simulating events

The API comes with a fireEvent helper that lets you simulate any DOM event. Use it to simulate clicks (fireEvent.click(element)), key presses (fireEvent.keyPress(el), and anything else really!

simulating-events-example.js
import { render, fireEvent, act, cleanup } from 'react-testing-library'

// Calls cleanup() after every test
afterEach(cleanup)

it('works', () => {
  const { getByTestId } = render(<TextToolbar />)

  const button = getByTestId('button:insertImage')

  // Click the button.
  act(() => { fireEvent.click(button) })
  // Ensure that something happens
  await waitForElement(() => (
    getTestById('insertImageDialog')
  ))
})

Jest DOM

Try @testing-library/jest-dom to add a few custom matchers.

jest-dom-example.js
// See https://github.com/kentcdodds/react-testing-library#global-config
import 'jest-dom/extend-expect'
import React from 'react'
import { render, fireEvent, screen } from '@testing-library/react'
import HiddenMessage from '../hidden-message'

it('works', () => {
  const button = screen.getByLabelText(/Submit/)

  expect(button).toBeInTheDocument()  expect(button).toBeEnabled()  expect(button).toHaveStyle('color: red')})

You have just read Using React testing library, an unpublished draft. This is Today I Learned, a collection of random tidbits I've learned through my day-to-day web development work. I'm Rico Sta. Cruz, @rstacruz on GitHub (and Twitter!).

← More articles