Skip to main content

Mocking

Mocking services and child components

Child components

component-with-child.js
import Child from "./child";

const ComponentWithChild = ({foo}) => {
return (<div>
<Child foo={foo}>Data sent to child</Child>
</div>)
}

export default ComponentWithChild

Since Jest will render the entire tree, the <Child/> component will also get rendered. In some cases, we don't want to render the structure of <Child/> and just the props or contents we pass into it. We can easily mock the <Child/> component and make it render whatever we pass into it for testing purposes.

component-with-child.test.js
import React from "react";
import {render, screen} from "test-utils";
import userEvent from "@testing-library/user-event";
import "@testing-library/jest-dom";

import ComponentWithChild from './component-with-child'
jest.mock("./child", ({foo, children}) => (
<div>
<div aria-label="foo">
{foo}
</div>
<p>
{children}
</p>
</div>
))

describe("component-with-child", () => {
test("should render foo and children", () => {
const bar = "bar"
render(<ComponentWithChild foo={bar} />);
expect(screen.getByRole('div', {name: "foo"})).toHaveTextContent(bar);
expect(screen.getByRole('p')).toHaveTextContent("Data sent to child");
})
})
render(<ComponentWithChild/>)
  <div>
<div>
<div aria-label="foo">
bar
</div>
<p>
Data sent to child
</p>
</div>
</div>

jest.mock takes in a string to intercept any imports matching that string. We are telling jest to pass in this new JSX component to anything using "./child" as an import.

Learn more about mocking best practices here

Services

How to mock and expect results from API services

component-service-mock.test.js
import React from "react";
import {render, screen} from "test-utils";
import userEvent from "@testing-library/user-event";
import "@testing-library/jest-dom";
import ComponentThatUsesApi from "./component";

jest.mock("@app/services/api/someApi");
const api = require("@app/services/api/someApi");

describe("component-that-uses-api", () => {
test("should render result passed into getResult", () => {
const result = "Hi Klipfolio!";
api.getResult.mockReturnValue(result);

render(<ComponentThatUsesApi />);

expect(api.getResult).toHaveLastBeenCalledWith(result);
expect(screen.getByRole('div', {name: "result"})).toHaveTextContent(result);
})
})
  1. We are telling jest to mock the entire file of the service someApi, now this could suffice but you wouldn't be able to expect and change results from the service functions

  2. So we require (not import) since we want to get the API service as the mocked version which has to happen after jest.mock

  3. This returns mock functions of all the exported functions in the service API.

  4. Read up on mock functions API here

Other ways to mock

Jest has a mockImplementation function that allows mocking a single value.

import React from "react";
import {render, screen} from "test-utils";
import userEvent from "@testing-library/user-event";
import "@testing-library/jest-dom";
import ComponentThatImportsFunction from "./component";
import Function from './function'

describe("ComponentThatImportsFunction", () => {
test("mocking of Function", () => {
const mock = Function.mockImplementation((someArg) => `klipfolio.com/${someArg}`);

render(<ComponentThatImportsFunction />);

expect(mock).toHaveBeenCalledOnce(result);
})
})

Automatic component mocks

Mocking your component for everyone else

├── jest.config.js
├── src
│   ├── main
│   │ └── js
│ │ └── components
│ │ └── AboutMetrics
│ │ ├── __mocks__
│ │ │ └── AboutMetrics.js
│ │ └── AboutMetrics.js
│   └── test
│   └── react-testing-library
│   ├── mocks
│   │   └── ...
│   ├── test
│ │ └── ...
│   └── utils
│   └── ...

Jest will automatically pick up files in __mocks__ directory beside any components. If a file here has the same name as the component you are trying to mock, it will be automatically mocked for anyone using this component. If you wish to not mock the component that is automatically mocked because of this you can use jest.unmock("@app/components/AboutMetics") in this case.