How can the instance methods be mocked for a class that is being mocked with jest.mock
?
For example, a class Logger
is mocked:
import Person from "./Person";
import Logger from "./Logger";
jest.mock("./Logger");
describe("Person", () => {
it("calls Logger.method1() on instantiation", () => {
Logger.method1.mockImplementation(() => {}) // This fails as `method1` is an instance method but how can the instance method be mocked here?
new Person();
expect(Logger.method1).toHaveBeenCalled();
});
});
How can the instance methods be mocked for a class that is being mocked with jest.mock
?
For example, a class Logger
is mocked:
import Person from "./Person";
import Logger from "./Logger";
jest.mock("./Logger");
describe("Person", () => {
it("calls Logger.method1() on instantiation", () => {
Logger.method1.mockImplementation(() => {}) // This fails as `method1` is an instance method but how can the instance method be mocked here?
new Person();
expect(Logger.method1).toHaveBeenCalled();
});
});
Share
edited May 17, 2022 at 19:44
Som Shekhar Mukherjee
8,1682 gold badges15 silver badges32 bronze badges
asked May 17, 2022 at 19:05
surajs02surajs02
4712 gold badges8 silver badges20 bronze badges
4
-
have yout tried
import Logger from jest.mock("./Logger")
? – Some random IT boy Commented May 17, 2022 at 19:15 -
that gives the error
String literal expected
– surajs02 Commented May 17, 2022 at 19:16 -
Sorry, I meant
const Logger = jest.mock("./Logger")
– Some random IT boy Commented May 17, 2022 at 19:21 -
That makes sense but
Logger.method1
gives errorProperty 'method' does not exist on type '"./Logger"'
– surajs02 Commented May 17, 2022 at 19:23
1 Answer
Reset to default 5Automatic Mocking
Calling jest.mock
automatically mocks all the exports from the module being mocked unless a manual mock is specified using the __mocks__
directory.
So, this line jest.mock("./Logger")
has automatically replaced the Logger
constructor and all of it's methods with mock functions allowing us to test how these functions behave.
And the information related to the instances created by Logger
is saved in Logger.mock.instances
, so we can use this to test if the methods are being called properly.
import Person from "./Person";
import Logger from "./Logger";
jest.mock("./Logger");
describe("Person", () => {
it("calls method1 on instantiation", () => {
const p = new Person();
// Logger constructor should have been called
expect(Logger).toHaveBeenCalled();
const mockLoggerInstance = Logger.mock.instances[0];
const mockMethod1 = mockLoggerInstance.method1;
// method1 should have also been called
expect(mockMethod1).toHaveBeenCalled();
});
});
Using Module Factory Parameter
You can also explicitly provide a module factory by passing in a factory function as the second argument to jest.mock
. So, now the provided module factory would be used instead of Jest's automocking feature. Refer the docs for more information.
import Person from "./Person";
import Logger from "./Logger";
const mockMethod1 = jest.fn();
jest.mock("./Logger", () =>
jest.fn().mockImplementation(() => ({
method1: mockMethod1,
}))
);
describe("Person", () => {
it("calls method1 on instantiation", () => {
const p = new Person();
// Logger constructor should have been called
expect(Logger).toHaveBeenCalled();
// method1 should have also been called
expect(mockMethod1).toHaveBeenCalled();
});
});
Note: jest.mock()
calls are hoisted, so you cannot first define a variable and then use it inside a factory function unless the variable is prefixed with mock
. And because of this we can access mockMethod1
inside the factory.
Manual Mock
You can achieve a similar behavior to module factory function by creating a manual mock located at __mocks__/Logger.js
. And now this mock implementation can be used across test files by simply calling jest.mock
.
// __mocks__/Logger.js
const mockMethod1 = jest.fn();
const mockLogger = jest.fn(() => ({
method1: mockMethod1,
}));
Usage is similar to the module factory function but you now also have to import the mocked method in your test.
Note: You still need to use the original module path, don't include __mocks__
.
import Person from "./Person";
import Logger, { mockMethod1 } from "./Logger";
jest.mock("./Logger");
describe("Person", () => {
it("calls method1 on instantiation", () => {
const p = new Person();
// Logger constructor should have been called
expect(Logger).toHaveBeenCalled();
// method1 should have also been called
expect(mockMethod1).toHaveBeenCalled();
});
});