Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spying on a non-exported node.js function using jest not working as expected

Tags:

I am trying to mock a non-exported function via 'jest' and 're-wire'.

Here I am trying to mock 'iAmBatman' (no-pun-intended) but it is not exported.

So I use rewire, which does it job well. But jest.mock doesn't work as expected.

Am I missing something here or Is there an easy way to achieve the same ?

The error message given by jest is :

Cannot spy the property because it is not a function; undefined given instead

service.js

function iAmBatman() {
    return "Its not who I am underneath";
}

function makeACall() {
    service.someServiceCall(req => {
        iAmBatman();
    });
    return "response";
}

module.export = {
    makeACall : makeACall;
}

jest.js

const services = require('./service');
const rewire = require('rewire');
const app = rewire('./service');
const generateDeepVoice = app.__get__('iAmBatman'); 

const mockDeepVoice = jest.spyOn(services, generateDeepVoice);

mockDeepVoice.mockImplementation(_ => {
    return "But what I do that defines me";
});

describe(`....', () => {
    test('....', done => {
        services.makeACall(response, () => {

        });
    });
})
like image 293
Rajkumar Somasundaram Avatar asked Jun 04 '19 12:06

Rajkumar Somasundaram


People also ask

How do you spy a function in Jest?

To spy on an exported function in jest, you need to import all named exports and provide that object to the jest. spyOn function. That would look like this: import * as moduleApi from '@module/api'; // Somewhere in your test case or test suite jest.

What does Jest spy do?

Jest's spyOn method is used to spy on a method call on an object. It is also very beneficial in cases where the Jest mock module or mock function might not be the best tool for the job on hand. While writing unit tests you only test one particular unit of code, generally a function.

How do you mock a function?

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.

How do you mock an import Jest?

To mock an imported function with Jest we use the jest. mock() function. jest. mock() is called with one required argument - the import path of the module we're mocking.


1 Answers

It is not entirely clear what your goal is, but if you look at the documentation of jest.spyOn, you see that it takes a methodName as the second argument, not the method itself:

jest.spyOn(object, methodName)

This explains your error: you didn't give the function name, but the function itself. In this case, using jest.spyOn(services, 'iAmBatman') wouldn't work, since iAmBatman is not exported, and therefore services.iAmBatman is not defined.

Luckily, you don't need spyOn, as you can simply make a new mock function, and then inject that with rewire's __set__ as follows:

(note that I deleted the undefined service.someServiceCall in your first file, and fixed some typos and redundant imports)

// service.js

function iAmBatman() {
    return "Its not who I am underneath";
}

function makeACall() {
    return iAmBatman();
}

module.exports = {
    makeACall: makeACall
}
// service.test.js

const rewire = require('rewire');
const service = rewire('./service.js');

const mockDeepVoice = jest.fn(() => "But what I do that defines me")
service.__set__('iAmBatman', mockDeepVoice)

describe('service.js', () => {
    test('makeACall should call iAmBatman', () => {
        service.makeACall();
        expect(mockDeepVoice).toHaveBeenCalled();
    });
})

Another option would be to restructure your code with iAmBatman in a seperate module, and then mock the module import with Jest. See documentation of jest.mock.

like image 92
Rens Baardman Avatar answered Nov 15 '22 06:11

Rens Baardman