Skip to content

React Testing Library

Philosophy

  • test the way your user would
  • don't test internals

What RTL does

  • what happens in a test
    • render a component
    • then tear it down
    • do something once it's rendered
  • RTL removes boilerplate
    • has nice practices
    • isolation of tests

Mocking non JS files

Jest doesn't understand

  • setupFilesAfterEnv
  • ['@testing-library/jest-dom/extend-expect', path.join(__dirname, 'src/test/setup')]
  • create React app: setupTests.js

moduleDirectories: [path.join(__dirname, 'src')]

  • unless you use Webpack aliases

Swap @testing-library/react with your own test utils

render

render result

  • queries

you don't need to use the result of render

Wrapper

test-utils.js
function render({ theme = "light", ...options } = {}) {
    const Wrapper = ({ children }) => (
        <ThemeProvider initialTheme="light">{children}</ThemeProvider>
    );
    return render(ui, { wrapper: Wrapper, ...options });
}

export * from "@testing-library/react";
export { render }; // use our own render

Getting DOM elements

screen

use screen instead of using queries from render

  • more resilient to changes

Which query to use

  • getByRole all the time if possible

Testing Playground

screen.debug

screen.getByRole("button", { name: /submit/i });

Only use query* to check for non-existence

expect(screen.queryByRole("alert")).not.toBeInTheDocument();

find* uses waitFor under the hood

  • use it for something that might not be available right away
const submitButton = await screen.findByRole("button", { name: /submit/i });

Mocking

const handleSubmit = jest.fn()

expect(handleSubmit).toHaveBeenCalledTimes(1)

Generate test data

faker

import faker from 'faker'
const buildLoginForm = (overrides) => {
    username: faker.internet.userName(),
    password: faker.internet.password(),
    ...overrides,
}

const {username, password} = buildLoginForm()

test-data-bot

import {build, fake} from @jackfranklin/test-data-bot

const buildLoginForm = build({
    fields: {
    username: fake(f => f.internet.userName()),
    password: fake(f => f.internet.password()),
})

const {username, password} = buildLoginForm()

test-data-bot can create sequences

Mocking Browser APIs

Snapshot tesing

with asFragment()

const { asFragment } = render(<MyComp />)
const firstRender = asFragment()
expect(firstRender).toMatchSnapshot()


// snapshot the difference between the first and second render
userEvent.click(screen.getByText(/text/))
expect(firstRender).toMatchDiffSnapshot(asFragment())

Last update: 2023-04-24