Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between jest.mock(module) and jest.fn()

I have tried couple different ways of defining the mock function and all of my tries failed. When I try to define it as follow:

jest.mock('../src/data/server', ()=> ({server: {report: jest.fn()}}));
expect(server.report.mock).toBeCalledWith(id, data, () => {...}, () => {...});

I get the this error:

expect(jest.fn())[.not].toBeCalledWith()
jest.fn() value must be a mock function or spy.
Received: undefined

If I define the mock as :

var spy = jest.mock('../src/data/server', ()=> ({server: {report: jest.fn()}}));
expect(spy).toBeCalledWith(id, data, () => {...}, () => {...});

it returns the following error:

    expect(jest.fn())[.not].toBeCalledWith()
    jest.fn() value must be a mock function or spy.
    Received:
      object: {"addMatchers": [Function anonymous], "autoMockOff": [Function anonymous], "autoMockOn": [Function anonymous], "clearAllMocks": [Function anonymous], "clearAllTimers": [Function anonymous], "deepUnmock": [Function anonymous], "disableAutomock": [Function anonymous], "doMock": [Function anonymous], "dontMock": [Function anonymous], "enableAutomock": [Function anonymous], "fn": [Function anonymous], "genMockFn": [Function bound getMockFunction], "genMockFromModule": [Function anonymous], "genMockFunction": [Function bound getMockFunction], "isMockFunction": [Function isMockFunction],
 "mock": [Function anonymous], "resetModuleRegistry": [Function anonymous], "resetModules": [Function anonymous], "runAllImmediates": [Function anonymous], "runAllTicks": [Function anonymous], "runAllTimers": [Function anonymous], "runOnlyPendingTimers": [Function anonymous], "runTimersToTime": [Function anonymous],"setMock": [Function anonymous], "unmock": [Function anonymous], "useFakeTimers": [Function anonymous], "useRealTimers": [Function anonymous]}

As my third try I defined the mock as:

const st = require.requireActual('../src/data/server', ()=> ({server: {report: jest.fn()}}));
st.report = jest.fn();
expect(st.report).toBeCalledWith(id, data,  () => {...}, () => {...});

And I get this error:

expect(jest.fn()).toBeCalledWith(expected)
Expected mock function to have been called with:
  ["1033083fe", {"address": "test address", "affiliation": "testaaa", 
  "city": "testcity", "copyright": true, "country": "testcountry", "email": "[email protected]", "message": "testmessage", 
  "name": "testname", "phone": "1234567890", "zipcode": "12345"}, [Function anonymous], [Function anonymous]]
But it was not called.

I wonder what is the problem and how these 3 ways of defining mock are different?

P.S. the code can be find here: Write a Unit test in Jest for a React form

like image 224
Birish Avatar asked Dec 11 '16 17:12

Birish


People also ask

What does Jest fn () do?

The jest. fn method allows us to create a new mock function directly. If you are mocking an object method, you can use jest.

What is the difference between Jest FN and Jest spyOn?

jest. fn() is a method to create a stub, it allowing you to track calls, define return values etc... jest. spyOn() came from jasmine, it allow you to convert an existing method on an object into a spy, that also allows you to track calls and re-define the original method implementation.

How do you call a mock function in Jest?

You can create a namespace that you export as the default object and call b using the namespace. This way, when you call jest. mock it will replace the b function on the namespace object. const f = require('./f'); jest.

What does mocking mean in Jest?

Mocking is a technique to isolate test subjects by replacing dependencies with objects that you can control and inspect. A dependency can be anything your subject depends on, but it is typically a module that the subject imports.


1 Answers

In the first example you say that when ever the module '../src/data/server' is imported in some other module it will be {server: {report: jest.fn()}}. In the next line you try to use server. The problem is that you never import the module that you mock. Maybe in the module that you test server is {server: {report: jest.fn()}}, but in you in test server is just undefined as you never import it. To fix this also have to import it.

import server from '../src/data/server'
jest.mock('../src/data/server', ()=> ({server: {report: jest.fn()}}));
expect(server.report.mock).toBeCalledWith(id, data, () => {...}, () => {...});

In the second example it seams like jest.mock just returns jest.

The last example fails cause you never call st.report.

Back to the main question. The difference between jest.mock and jest.fn

jest.mock replaces one module with either just jest.fn, when you call it with only the path parameter, or with the returning value of the function you can give it as the second parameter. So in your first example when ever in one of your files you wanna test or in the test itself, '../src/data/server' is imported it will be {server: {report: jest.fn()}}.

Which brings us the jest.fn(). This will return a spy. A spy is a function that can remember each call that was made on it, and with which parameters.

Lets say you have a module that you wanna test:

import server from './data/server'

server.report('test123')

To test that this call was made with the correct parameter you need to mock this dependency to './data/server' with something you can control.

import server from '../src/data/server'
import fileToTest from '../src/fileToTest'
jest.mock('../src/data/server', ()=> ({server: {report: jest.fn()}}));
expect(server.report.mock).toBeCalledWith('test123');

What happens here is that before all the import stuff starts jest replaces '../src/data/server' with your mock implementation, so when fileToTest is import the sever and call it, it actually call the spy function. Which you can then expect that it was called with the correct parameter.

Btw. what you try in your test, checking for function, will not work as the functions you pass when calling the spy and the function you pass into toBeCalledWith are not identical.

In this case I would check for each single parameter

expect(server.report.mock.calls[0][0]).toBe("1033083fe");
expect(server.report.mock.calls[0][0]).toEqual({"address": "test address", "affiliation": "testaaa", 
  "city": "testcity", "copyright": true, "country": "testcountry", "email": "[email protected]", "message": "testmessage", 
  "name": "testname", "phone": "1234567890", "zipcode": "12345"});
like image 172
Andreas Köberle Avatar answered Oct 05 '22 22:10

Andreas Köberle