Snippets I Always Need to Look Up When Writing Tests with React Testing Library
Tags: react, reacttestinglibrary, typescript
Published: 2020-04-15 18:21:59

---
title: Snippets I Always Need to Look Up When Writing Tests with React Testing Library
published: true
description: Whenever I start a new project and need to write React Testing Library (RTL) unit tests, I end up having to look up or copy snippets of code to set up the tests. I thought it might be useful to share some of these here in one place, both for myself and for others who might want to look up these snippets quickly.
tags: react, reacttestinglibrary, typescript
---

Whenever I start a new project and need to write React Testing Library (RTL) unit tests, I end up having to look up or copy snippets of code to set up the tests. I thought it might be useful to share some of these here in one place, both for myself and for others who might want to look up these snippets quickly. Feel free to leave a comment if any of these don't work for you or if there is a better way to do something. I will update this post as I gather more snippets over time.

## Taking a snapshot
I normally don't use snapshots in my unit tests as they are [more trouble than they're worth](https://medium.com/@tomgold_48918/why-i-stopped-using-snapshot-testing-with-jest-3279fe41ffb2), but sometimes when debugging a unit test that is failing I want to see what the unit test is seeing, so I'll throw in a snapshot temporarily. I can never remember the exact code for taking a snapshot, and since I don't use them I can't refer to them in another part of the codebase. So here it is:

```javascript
it("renders", () => {
  const { asFragment } = render(<MyComponent />);
  expect(asFragment()).toMatchSnapshot();
});
```

## Mocking Axios API Calls
This is something I've had to learn how to do from several different sources as most articles will provide the basics using `get` for example, and skip over how to mock `post` requests. Or they will assume one call is being made instead of potentially many calls. Here's what I have figured out so far.

### Setup
```javascript
import axios from "axios";
...
jest.mock("axios");
const mockedAxios = axios as jest.Mocked<typeof axios>;
```

### CancelToken
I use CancelToken to cancel axios API calls when components unmount. The above code is modified to the following to support CancelToken:
```javascript
import axios from "axios";
...
jest.mock("axios");
const mockedAxios = axios as jest.Mocked<typeof axios>;
type Canceler = (message?: string) => void;

class CancelToken {
  public static source() {
    const cancel: Canceler = jest.fn();
    const token = new CancelToken();
    return {
      cancel,
      token
    };
  }
}

// @ts-ignore
mockedAxios.CancelToken = CancelToken;
```
Note that this works for me but does throw TypeScript errors as its not fully built out.

### Get
```javascript
it("renders", () => {
  const response1 = {
    data: [], // populate with mock data as desired
    status: 200
  }
  const response2 = {
    data: [], // populate with mock data as desired
    status: 200
  }
  mockedAxios.get.mockImplementation(url => {
    if (url === "/api/somePath") return Promise.resolve(response1);
    if (url === "/api/someOtherPath") return Promise.resolve(response2);
    // etc.
  });
  const { getByText } = render(<MyComponent />);
  ...
});
```

### Post
```javascript
it("renders", () => {
  const response1 = {
    data: [], // populate with mock data as desired
    status: 200
  }
  const response2 = {
    data: [], // populate with mock data as desired
    status: 200
  }
  mockedAxios.post.mockImplementation((url, payload) => {
    if (url === "/api/somePath" && payload.someProperty === "some value") {
      return Promise.resolve(response1);
    }
    if (url === "/api/somePath" && payload.someProperty === "some other value") {
      return Promise.resolve(response2);
    }
    // etc.
  });
  const { getByText } = render(<MyComponent />);
  ...
});
```

## Render with Theme (Styled Components)
I will normally create a `render-methods.tsx` file and add the different render methods I need and import them into my tests. One of these is rendering with the Styled Components theme.

```javascript
import React from "react";
import { render } from "@testing-library/react";
import { ThemeProvider } from "styled-components";

import theme from "../../theme"; // or wherever your theme file is

export function renderWithTheme(component: React.ReactNode) {
  return render(<ThemeProvider theme={theme}>{component}</ThemeProvider>);
}
```

## Render with Router (Reach Router) and Mocking `navigate`
In my `render-methods.tsx` file, I have a `renderWithRouter` method that also incorporates rendering with a Styled Components theme. If you're not using Styled Components or a theme, this portion can be removed of course (see the second code snippet).

```javascript
import React from "react";
import { render } from "@testing-library/react";
import { ThemeProvider } from "styled-components";
import {
  createHistory,
  createMemorySource,
  LocationProvider
} from "@reach/router";

import theme from "../../theme"; // or wherever your theme file is

export function renderWithRouter(
  component: React.ReactNode,
  { route = "/", history = createHistory(createMemorySource(route)) } = {}
) {
  return {
    ...render(
      <ThemeProvider theme={theme}>
        <LocationProvider history={history}>{component}</LocationProvider>
      </ThemeProvider>
    ),
    history
  };
}
```

Without theme:
```javascript
import React from "react";
import { render } from "@testing-library/react";
import {
  createHistory,
  createMemorySource,
  LocationProvider
} from "@reach/router";

export function renderWithRouter(
  component: React.ReactNode,
  { route = "/", history = createHistory(createMemorySource(route)) } = {}
) {
  return {
    ...render(
      <LocationProvider history={history}>{component}</LocationProvider>
    ),
    history
  };
}
```

In my test file, I mock `navigate` so it works properly and can be tested.

```javascript
import React from "react";
import { fireEvent, wait } from "@testing-library/react";
import { navigate } from "@reach/router";

jest.mock("@reach/router", () => {
  const RouterMocks = jest.requireActual("@reach/router");
  return {
    ...RouterMocks,
    navigate: jest.fn()
  };
});

it("navigates", () => {
  const { getByText } = render(<MyComponent />);
  fireEvent.click(getByText("Submit"));
  await wait(() => {
    expect(navigate).toHaveBeenCalledTimes(1);
    expect(navigate).toHaveBeenCalledWith("/pathOfNextPage");
  });
});
```

If you need to mock parameters in the route, you can add that to the jest mock as well:
```javascript
jest.mock("@reach/router", () => {
  const RouterMocks = jest.requireActual("@reach/router");
  return {
    ...RouterMocks,
    navigate: jest.fn(),
    useParams: () => ({
      someParameter: 'some-parameter-value'
    })
  };
});
```

## Dealing with Reach UI styles not found warning
If you're using Reach UI for components like `Tooltip` or `Dialog`, you may get a warning about styles not found. This is a work-around to get that warning to go away (this warning does not show up in the browser, just in unit tests).

```javascript
const { getComputedStyle } = window;
beforeAll(() => {
  window.getComputedStyle = jest.fn().mockReturnValue({
    getPropertyValue: jest.fn().mockReturnValue("1")
  });
});
afterAll(() => {
  window.getComputedStyle = getComputedStyle;
});
```

## Clicks with User Event
Since some components may use `onMouseDown` instead of `onClick`, using RTL's `fireEvent` to simulate clicks may not work. I use the `user-event` package instead which handles this case.

```javascript
import userEvent from "@testing-library/user-event";
...
it("clicks", () => {
  const { getByText } = render(<MyComponent />);
  userEvent.click(getByText("Submit"));
});
```

## Stubbing Date.now()
Sometimes you'll want to stub Date.now() to a fixed time when making time comparisons. There are a few different ways of doing this, but this is a simple method that I use in my tests.

```javascript
it("stubs a date", () => {
  const realDateNow = Date.now.bind(global.Date);
  const dateNowStub = jest.fn(() => 1577838600);
  global.Date.now = dateNowStub;

  // Write the unit test as usual

  global.Date.now = realDateNow; // reset the global.Date.now when you are done
```

## Handling TypeScript error regarding property 'value'
When using TypeScript with React Testing Library, I get the following error when trying to assert on an input field's value: `Property 'value' does not exist on type 'HTMLElement'`. This can be remedied by casting to `HTMLInputElement`. It's not particularly pretty having this all over your tests, but it works.

For example, this would throw the TypeScript error:
```javascript
expect(getByLabelText("Name").value).toBe("Lilliana");
```

This can be updated to the following to fix the TypeScript error:
```javascript
expect((getByLabelText("Name") as HTMLInputElement).value).toBe("Lilliana");
```