---
title: Mocking React components with Jest
teaser: 'Mocking in Jest can be tricky. Mocking React Components in Jest with ES modules
  can be even tricker. Yet, it''s still possible.

  '
tags: react,testing,javascript,typescript,nodejs
author: Edward Loveall
published_on: 2019-09-24
---

I recently had a troublesome React component.
It was a component that was using the browser's
[`fetch` API][fetch-api] to load
and insert SVG icons the page.
In and of itself that's fine.
Browsers have all the required components to use `fetch`.
However,
Node.js is not a browser
and it doesn't have `fetch`.
So what can we do?

[fetch-api]: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

One thing we could do is use some fetch-like polyfill.
There's
[node-fetch],
[fetch-mock],
[jest-fetch-mock],
[cross-fetch],
and many others that might help us do that.
However,
this not only involves modifying the [global] object to add `fetch`,
but also mocking every call to `fetch` so it returns the icons that we want.
Since most of the time I'm not testing the icons of a component,
it would be inappropriate to mock this for unit tests.

[node-fetch]: https://www.npmjs.com/package/node-fetch
[fetch-mock]: https://www.npmjs.com/package/cross-fetch
[jest-fetch-mock]: https://www.npmjs.com/package/cross-fetch
[cross-fetch]: https://www.npmjs.com/package/cross-fetch
[global]: https://nodejs.org/api/globals.html#globals_global

The way I solved this was to use [Jest mocks]
and mocked out the whole icon component,
so that it never calls `fetch`.
We stopped making [fetch happen],
but the solution wasn't intuitive.

[jest mocks]: https://jestjs.io/docs/en/manual-mocks
[fetch happen]: https://media.giphy.com/media/Qw4X3Fnt8MzvrCxmBLG/giphy.gif

## Mock ES Modules with Jest

First,
to mock a component, you use
`jest.mock("path/to/RealComponent")`.
You can specify an mock implementation inline like
`jest.mock("../src/Icon" () => { ... })`.

It needs to return a module,
which is an object with keys as the exports.
So if your component normally exports like so:

```typescript
export { A, B };
```

Then your Jest mock can supply both of those exported things:

```tsx
jest.mock("../src/Icon", () => {
  return {
    A: true,
    B: () => {
      return <></>;
    },
  };
});
```

## Mock ES Modules with default and named exports

What about `default` exports,
or both named _and_ `default` exports?
To mock a module with both,
you can use the `default` key,
but you _also_ must specify that it's an ES6 module with a special
`__esModule` key:

```typescript
export { A };
export default B;
```

```tsx
jest.mock("../src/Icon", () => {
  return {
    __esModule: true,
    A: true,
    default: () => {
      return <div></div>;
    },
  };
});
```

You can then put this in your test,
but it must be _outside_ of _any_ scope to work.
It can't be in a function,
a before block,
or anything else.
This is a pain to abstract
and use in other (all) tests.
So I used a mock file.

### Mock ES Modules with Jest file mocks

These mocks need to be in a `__mocks__` folder next to the component,
and also have the same file name.
For example,
your folder structure might look like:

```
src
├── Icon.tsx
├── __mocks__
│   └── Icon.tsx
```

and then you can reimplement the component:

```tsx
// src/__mocks__/Icon.tsx

import React from "react";
import { ReactElement } from "react";

const A = "abcdefg";
const B = (): ReactElement => {
  return <></>;
};

export { A };
export default B;
```

Finally, in your test,
you can mock the real component,
and Jest will magically find the mock next door:

```typescript
jest.mock("../src/Icon");
```

If you want all tests to benefit from this file, put this in your [Jest setup file](https://jestjs.io/docs/configuration#setupfilesafterenv-array),
or just pick on a test-by-test basis. Either way, mocking is a powerful tool in your toolset, and now you can mock components.

If you're looking for experienced React developers to help you build and test your application, thoughtbot is here. [Let's discuss your project](https://thoughtbot.com/hire-us).
