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.
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.
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.
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.
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')})
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!
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')
))
})
Try @testing-library/jest-dom
to add a few custom matchers.
// 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')})