Photo by Ferenc Almasi on Unsplash

Mocking 3rd Party Components With Jest

Caleb LeNoir
The Startup
Published in
4 min readSep 3, 2020

--

React + Jest + Reacting Testing Library + 3rd Party Component Mocking

I recently ran into an issue where I was trying to test a component that contained a 3rd party component. The child component was more complex than a simple input (as third party components are), and I needed more control over the way it was mocked. I’m fairly new to Jest testing, and I could not find a suitable example for how to do this. So here is what I discovered.

Getting Started

My assumption is that you are already familiar with React and testing, so I’m not going to go into much detail about that. I am working on app created with create-react-app so everything for Jest is configured according to their defaults. Other than that, here is the version of React Testing Library we are working with:

"@testing-library/react" : "^10.4.1"

For this particular solution, I’m not sure any of the other packages matter.

3rd Party Component

The component I needed to create a mock for is a shared component we have on https://bit.dev. See here.

Our component index.d.ts looks like this:

import {Component} from "react";

interface IndustrySearchProps {
selectIndustry: (industryId: number, industryName: string) => void,
placeholder?: string,
industryId?: string,
industryName?: string,
reportError?: (error: string) => void,
industrySearch?: (term: string) => Promise<[object]>,
loadingElement?: JSX.Element,
className?: string,
headerText?: string
}

declare class IndustrySearch extends Component<IndustrySearchProps, any> {}

export default IndustrySearch;

The purpose of this component is to interface with a 3rd party API and return results back for selection. The only required prop is the selectIndustry function which has two parameters: industryId: number and industryName: string. We use this component in several places in our code base.

The Problem

I need to write a test for a parent component that includes the above IndustrySearch component. How do I do this? First, I tried ignoring the problem, hoping it would just work.

Nope. All kinds of errors relating to information the IndustrySearch component needed that it was not getting.

Solution #1 — the simple mock

I reached out to a co-worker about how to mock the component and got the following suggestion:

jest.mock("@bit/coterie.partner-ui.industry-search", () => () => <input />);

That seemed simple enough. I dropped it at the top of my spec.js file and Boom! Everything worked for my test. Problem solved. Tests passing. Go on a lunch break.

After Lunch Problems

As with all problems you solve prior to lunch, they quickly become unsolved when you return.

The mock worked well for the case where I did not need to interact with the component. But, that input is a required field in our form and it changes the state of the parent component when the user makes a selection. So, how to handle that?

Solution #2 — complex mockery

After much fumbling around, I came across the concept of Manual Mocks in the Jest documentation: https://jestjs.io/docs/en/manual-mocks

Essentially, you can create a __mocks__ folder inside of your src. Any components you create in here, will be substituted for their actual versions when Jest tests are run.

For instance, let’s say you want to mock axios. Simple. Create axios.js in src/__mocks__ . Here is what ours looks like:

const mockAxios = jest.genMockFromModule("axios");
mockAxios.create = jest.fn(() => mockAxios);

export default mockAxios;

Now, any components that import axios will receive this mocked version instead. Magic.

So, back to our IndustrySearch. How can I do the same for it? First, the name is weird: @bit/coterie.partner-ui.industry-search. How do I create a file for that? Lucky for me, my editor is more intelligent than I am. I went to create a new file in the __mocks__ folder with that name and it did the work for me, creating a directory called @bit with a file in it name coterie.partner-ui.industry-search.js.

Now we’re getting somewhere. I created a mock version of the component in the file:

import React from "react";

const IndustrySearch = ({ selectIndustry }) => {
const handleOnChange = () => {
selectIndustry(10001, "IndustryName");
};

return <input data-testid={"industry-search"} onChange={handleOnChange} />;
};

export default IndustrySearch;

And voilà! It does what I need. When I use React Testing Library to type in that input field, it calls handleOnChange which fires the call to selectIndustry with a default industry Id and name, updating the state of the parent component.

Every Jest test I now create for a component that imports @bit/coterie.partner-ui.industry-search will now pull from this mocked version instead, giving me the control I need.

Thanks for reading! Would love to hear any thoughts or feedback!

--

--