Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jest mock function doesn't work while it was called in the other function

I believe something fundamentally wrong in my understanding for Javascript.

In file abc.js, I have code

export function returnBoolean() {
  return true;
}

export function output() {
  return returnBoolean();
}

In the test, I do

import * as abc from "../abc";

it("test", () => {
  abc.returnBoolean = jest.fn();
  abc.returnBoolean.mockReturnValue(false);
  expect(abc.returnBoolean()).toBe(false); // This is success
  expect(abc.output()).toBe(false); // This failed because return is true
});

I don't know why abc.output() return is true.

I am really confused. Any thought is really appreciated. Thanks!

like image 840
KunYu Tsai Avatar asked Aug 17 '18 17:08

KunYu Tsai


People also ask

How do you test a function has been called in Jest?

How to check if a function was called correctly with Jest? To check if a function was called correctly with Jest we use the expect() function with specific matcher methods to create an assertion. We can use the toHaveBeenCalledWith() matcher method to assert the arguments the mocked function has been called with.

Does Jest mock get hoisted?

Using with ES module imports​ But often you need to instruct Jest to use a mock before modules use it. For this reason, Jest will automatically hoist jest. mock calls to the top of the module (before any imports).

How do you mock a real function in Jest?

There are two ways to mock functions: Either by creating a mock function to use in test code, or writing a manual mock to override a module dependency.

Can I use Jest mock inside a test?

mock() doesn't work inside tests, only outside tests. Bookmark this question.


2 Answers

output() and returnBoolean() are both in the same file and output() calls returnBoolean() directly.

Mocking the module export for returnBoolean() doesn't have any effect on output() since it is not using the module, it is calling returnBoolean() directly.

Like felixmosh said, moving returnBoolean() to a different module is one way to be able to mock the call to returnBoolean() within output().

The other way is to simply import the module back into itself and use the module to call returnBoolean() within output() like this:

// import the module back into itself
import * as abc from './abc';

export function returnBoolean() {
  return true;
}

export function output() {
  return abc.returnBoolean(); // use the module to call returnBoolean()
}

With this approach your unit test should work.

like image 162
Brian Adams Avatar answered Sep 23 '22 21:09

Brian Adams


Think about it, whenever you import abc module, all the function inside that module are declared, therefore, output function get "bounded" to the original returnBoolean.

Your mock won't apply on the original function.

You have 2 choices:

  1. If the returnBoolean can be on a separate module, you will able to use jest's mocking mechnisem.
  2. If you able to change the interface of output method so it will be able to get the returnBoolean from outside of the module. Then you will be able to pass to it, jest.fn() and make your expectation on it.
like image 28
felixmosh Avatar answered Sep 25 '22 21:09

felixmosh