glend
glend

Reputation: 1622

mocking a function thats already imported in the source

here is the basic setup

component.js

import {functionIWantToMock, val} from "somewhere/on/my/hdd"

export function Component() {
    return (<>
        <div>{val}</div>
        <div>{functionIWantToMock()}</div>
    </>)
}

component.test.js

import { Component } from "./component";
import { render, screen } from "@testing-library/react";

it("should change the result of the function", () => {
    // Change behaviour of functionIWantToMock
    functionIWantToMock = () => {
        return "empty"
    }
    render(<Component/>);
    // This is not a proper assertion
    expect(screen.getByRole("img")).toBeVisible()
})

I've looked at manual mocking, spying and jest.fn() but none of those will work, i think, because the call is happening within the component and so I can't mock it globally.

What is the correct way to mock functionIWantToMock so that i can change its behaviour in the component for the test?

Upvotes: 1

Views: 49

Answers (1)

helloitsjoe
helloitsjoe

Reputation: 6529

You can either use module mocking or dependency injection for this.

Module mocking

The Jest docs have an example of mocking a module, you would need to do this:

component.test.js

import { Component } from "./component";
import { render, screen } from "@testing-library/react";

// This gives you a handle to the function so you can mock
// the return value, make expectations on it, etc
import { functionIWantToMock } from "somewhere/on/my/hdd";

// This mocks all exports from the module
jest.mock("somewhere/on/my/hdd");

it("should change the result of the function", () => {
    // Change behaviour of functionIWantToMock
    functionIWantToMock.mockReturnValue("empty");
    render(<Component/>);
    expect(functionIWantToMock).toBeCalled()
})

I recommend adding clearMocks: true to your Jest config to avoid leaking state between tests.

Dependency Injection

Your other option is to pass the function into the component:

component.js

import {functionIWantToMock as defaultFn, val} from "somewhere/on/my/hdd"

// Using the import as the default function helps you avoid
// passing the function where this component is used.
export function Component({functionIWantToMock = defaultFn}) {
    return (<>
        <div>{val}</div>
        <div>{functionIWantToMock()}</div>
    </>)
}

component.test.js

import { Component } from "./component";
import { render, screen } from "@testing-library/react";

it("should change the result of the function", () => {
    const mockFn = jest.fn(() => {
        return "empty"
    })
    render(<Component functionIWantToMock={mockFn} />);
    expect(mockFn).toBeCalled()
})

Upvotes: 1

Related Questions