Jest: How to mock one specific function when using module.exports - javascript

I'm trying to mock one specific function when using module.exports. How could I test the inner function B?
In my worker.js
module.exports = function () {
this.funcA = funcA
this.funcB = funcB
}
funcA () {
funcB()
}
funcB() {...}
In my worker-test.js
const Worker = require('./worker')
test('test functionB', () => {...})
test('test functionA', () => {
const work = new Worker()
work.funcB = jest.fn() //mock funcB
work.funcA //run funcA
expect(work.funcB).toHaveBeenCalledTimes(1) //Error
})
I'm new to jest. Is there any good way to mock function in this case?

There isn't a way to mock funcB the way the code is currently written since funcA calls funcB directly.
The easiest way to fix it is to note that worker.js returns a constructor function and funcA and funcB are almost prototype methods...
...if you make them prototype methods then funcB can be mocked:
worker.js
class Worker {
funcA() {
this.funcB();
}
funcB() {
throw new Error('should not make it here');
}
}
module.exports = Worker;
worker.test.js
const Worker = require('./worker');
test('test functionB', () => { /* ... */ })
test('test functionA', () => {
const spy = jest.spyOn(Worker.prototype, 'funcB'); // <= spy on funcB
spy.mockImplementation(() => {}); // <= mock funcB
const work = new Worker();
work.funcA(); // <= call funcA
expect(spy).toHaveBeenCalledTimes(1); // Success!
spy.mockRestore(); // <= restore funcB
})

I know this is an old question but I thought I would chime in as I was searching for a way to do this as well and have discovered it is in fact possible.
Rather than calling the javascript function as above, you'll need to give it the scope of this to ensure that when you mock funcB, funcA calls the mocked version rather than just the function itself.
This means worker.js becomes
module.exports = function () {
this.funcA = funcA
this.funcB = funcB
}
funcA () {
this.funcB()
}
funcB() {/* Your impl */}
And worker.test.js can remain, as before:
const Worker = require('./worker')
test('test functionB', () => {...})
test('test functionA', () => {
// You could even just have: const work = require('./worker')
const work = new Worker()
work.funcB = jest.fn() //mock funcB
work.funcA() //run funcA
expect(work.funcB).toHaveBeenCalledTimes(1)
})

Related

How to only mock

jest unit test question here. If I am testing function A, and function A uses function B,
import { funcB } = require('./FileB');
const funcA = () => {
const someData = funcB();
}
Does this mean that, in my unit test file testing funcA, in order to mock funcB, do i HAVE to import the function to mock it? which means the file wouldn't use that function but simply there for mocking purposes or do I have to mock the entire module in which funcB lives on and mock the implementation of that single function?
my goal here is, I dont want every single test in my unit test file to have funcB mocked, I only want it mocked on some test but not all while testing funcA.
So if i have 4 test and 3 of them need it mocked but 2 need its actuall implementation, whats a best way to approach this?
One possible solution - use spyOn and mockRestore for following implementation:
export const funcB = () => {
console.log('original implementation of B')
return 42;
}
import { funcB } from './fileb';
export const funcA = () => {
const someData = funcB();
return someData;
}
import * as fileB from "../funcab/fileb";
import { funcA } from "../funcab/filea";
describe('testing 1...2...3...', () => {
const spy = jest.spyOn(fileB, 'funcB');
afterEach(() => {
spy.mockRestore();
})
it('will test with mocked funcB', () => {
spy.mockReturnValue(1);
expect(funcA()).toEqual(1);
});
it('will test without mocked funcB', () => {
expect(funcA()).toEqual(42);
})
})
Here is a post about Jest mock and spy — mockClear vs mockReset vs mockRestore. I hope you'll find it usefull.
Answer for comment - do you mean sth like this?
const mockFuncB = jest.fn();
jest.mock("../funcab/fileb", () => ({
funcB: () => mockFuncB(),
}));
then the test would look like:
it('will test with mocked funcB', () => {
mockFuncB.mockReturnValue(1);
expect(funcA()).toEqual(1);
});

Jest spy not working while testing a function within a function

I'm trying to test a function in a class-based entity and trying to spy on another function that is being called inside the one I'm testing. But even though the child function is being called once, Jest fails to spy on it and says it was called 0 times.
Let's say this is my class:
class Example {
function1() {
const data = this.function2();
return data;
}
function2() {
...some code
}
}
So to test function1, I'm doing this:
describe('ExampleComponent', () => {
beforeEach(() => {
client = new Example();
});
it('should call function2 once', async() => {
const callFunction1 = client.function1();
const function2Spy = jest.spyOn(client, 'function2');
expect(function2Spy).toHaveBeenCalledTimes(1);
});
});
What am I missing here?
You are calling function first then spying on another function.
Try spying before function call
describe('ExampleComponent', () => {
beforeEach(() => {
client = new Example();
});
it('should call function2 once', async() => {
const function2Spy = jest.spyOn(client, 'function2');
client.function1();
expect(function2Spy).toHaveBeenCalledTimes(1);
});
});

How to stub a "wrapper" function using Sinon?

I'm setting up a Lambda function (node.js) and for example's sake, we'll keep it minimal.
module.exports = (event, context, callback) {
console.log("hello world")
}
However, I've created a function to wrap the lambda function that allows me to perform some functions that are required before each Lambda executes (I have a collection of Lambda functions that are wired up using their Serverless Application Model (SAM)). It also allows me to consolidate some of the logging and error handling across each function.
// hook.js
const connect = fn => (event, context, callback) => {
someFunction()
.then(() => fn(event, context, callback))
.then(res => callback(null, res))
.catch(error => {
// logging
callback(error)
})
}
module.exports = { connect }
// index.js
const Hook = require("./hook")
exports.handler = Hook.connect((event, context, callback) => {
console.log("hello world")
})
The logic is working well and Lambda is processing it successfully. However, I'm trying to stub this Hook.connect function using SinonJS and in need of some guidance.
I simply want to stub it to return a resolved promise, that way we can proceed to handle the code within each Lambda function (fn(event, context, callback)).
const sinon = require("sinon")
const Hook = require("./hook")
const { handler } = require("./index")
const event = {} // for simplicity sake
const context = {} // for simplicity sake
const callback = {} // for simplicity sake
describe("Hello", () => {
let connectStub
beforeEach(() => {
connectStub = sinon.stub(Hook, "connect").callsFake()
afterEach(() => {
connectStub.restore()
})
it("works", () => {
const results = handler(event, context, callback)
// assert
})
})
I've tried a few different methods, from the basic, sinon.stub(Hook, "connect"), to the more complicated where I'm trying to stub private functions inside of the hook.js file using rewire.
Any help would be appreciated -- thank you in advance.
Here is a working test:
const sinon = require('sinon');
const Hook = require('./hook');
const event = {}; // for simplicity sake
const context = {}; // for simplicity sake
const callback = {}; // for simplicity sake
describe('Hello', () => {
let handler, connectStub;
before(() => {
connectStub = sinon.stub(Hook, 'connect');
connectStub.callsFake(fn => (...args) => fn(...args)); // create the mock...
delete require.cache[require.resolve('./index')]; // (in case it's already cached)
handler = require('./index').handler; // <= ...now require index.js
});
after(() => {
connectStub.restore(); // restore Hook.connect
delete require.cache[require.resolve('./index')]; // remove the modified index.js
});
it('works', () => {
const results = handler(event, context, callback); // it works!
// assert
});
});
Details
index.js calls Hook.connect to create its exported handler as soon as it runs, and it runs as soon as it is required...
...so the mock for Hook.connect needs to be in place before index.js is required:
Node.js caches modules, so this test also clears the Node.js cache before and after the test to ensure that index.js picks up the Hook.connect mock, and to ensure that the index.js with the mocked Hook.connect is removed from the cache in case the real index.js is needed later.

Unit test for asyn function inside sails controller where async function called independently

I have one sails controller where I am doing something like :
...
function asynFunc(){
/* some logic */
}
module.exports = {
myFunc: function () {
// Call async function and return
asynFunc();
return true;
}
};
Now I wanted to write unit test for asynFunc. I am able to write unit test of myFunc but not asynFunc (get data, validate data).
Please let me know :
How can i mock asyncFunc
How can i unit test asynFunc
Do you really need to test private function? If you have it private, seems you may test it when you test other methods?
If you really need to test it, you can do the following:
myModule.js
async function asyncFunc(){
/* some logic */
}
module.exports = {
myFunc: async function () {
// Call async function and return
await asyncFunc();
return true;
}
};
test.js
const rewire = require('rewire');
const myModule = rewire('./myModule');
describe('unit/myModule:', () => {
const revert = (obj) => {
obj.__revert__();
delete obj.__revert__;
};
it('asyncFunc', async () => {
const asyncFuncSpy = jasmine.createSpy();
asyncFuncSpy.__revert__ = myModule.__set__('asyncFunc', asyncFuncSpy);
const actual = await myModule.myFunc();
expect(actual).toBeThruthy();
expect(asyncFuncSpy).toHaveBeenCalled();
revert(asyncFuncSpy)
})
})
That's a Bad use of a controller in 99% of the cases! Wrap that function into a Service and unity test the Service.
// Controller
module.exports = {
myFunc: function () {
// Call async function and return
MyService.asynFunc();
return true;
}
};
// Service
module.exports = {
async : function asynFunc(){
/* some logic */
}
}

how can I spy on a function with jest

I have a function that calls another function
const getArtist = (id) => {
// builds params for other function
return otherFuntion(params);
}
I want to verify that when I call getArtist(someValue), otherFunction gets called with the right arguments.
How can I accomplish that with jest ?
describe('getArtist function', () => {
it('should call otherFunction with the right params', () => {
// how can I get a handle on the mock of otherFunction to see
// if it was called correctly ?
});
});
You could use proxyquire to mock out the imported function at compile time if it's a public function. If it's a private function then you definitely don't want to mock it out.
You should probably just test the return value of otherFuntion instead.
So you are really calling the function otherFuntion(params) so I would rather check if return of your getArtist functions gives the same results as otherFunction called with right params.
describe('getArtist function', () => {
it('should call otherFunction with the right params', () => {
expect(getArtist(id)).toBe(otherFunction(params));
});
});
Or create special function for generate params and test it separatly. Like prepareArtistParams and use it inside:
const getArtist = (id) => {
const params = prepareArtistParams(id);
return otherFuntion(params);
}
describe('otherFuntion function', () => {
it('should create right params', () => {
expect(prepareArtistParams(id)).toBe(params);
});
});

Categories

Resources