Sinon.spy on a method is not invoked - javascript

The code I'm testing is fairly simple: it invokes a method in case a condition is verified. If not, it invokes another method contained within the first one as an attribute.
app.js:
function test (fn, isActivated) {
if (isActivated) {
return fn('foo')
}
return fn.subFn('bar')
}
var fn = function (p) { return p }
fn.subFn = function (p) { return 'sub-' + p }
var resFn = test(fn, true)
var resSubFn = test(fn, false)
document.write(resFn) // shows 'foo' as expected
document.write(resSubFn) // shows 'bar' as expected
I've set a spy on each method but the spy on the fn method does not seem to work while the spy on the contained method subFn works. See below:
app.test.js:
'use strict'
const chai = require('chai')
const sinon = require('sinon')
const trigger = require('../app').trigger
chai.should()
describe('test app', function () {
before(function () {
this.fn = function () {}
this.fn.subFn = function () {}
this.subFnSpy = sinon.spy(this.fn, 'subFn')
this.fnSpy = sinon.spy(this.fn)
})
describe('isActivated is true', function () {
before(function () {
trigger(this.fn, true)
})
it('should invoke fn', function () {
this.fnSpy.callCount.should.equal(1) // return false because callCount = 0
})
})
describe('isActivated is false', function () {
before(function () {
trigger(this.fn, false)
})
it('should invoke subFn', function () {
this.subFnSpy.callCount.should.equal(1) // return false because callCount = 0
})
})
})
Smelling something wrong with the spy on the fn function, I've tried with two separate methods. Both spies fail in this case:
app.js:
exports.trigger = function (fn, subFn, isActivated) {
if (isActivated) {
return fn('fn')
}
return subFn('bar')
}
app.test.js
'use strict'
const chai = require('chai')
const sinon = require('sinon')
const trigger = require('../app').trigger
chai.should()
describe('test app', function () {
before(function () {
this.fn = function () {}
this.subFn = function () {}
this.fnSpy = sinon.spy(this.fn)
this.subFnSpy = sinon.spy(this.subFn)
})
beforeEach(function () {
this.fnSpy.reset()
this.subFnSpy.reset()
})
describe('isActivated is true', function () {
before(function () {
trigger(this.fn, this.subFn, true)
})
it('should invoke fn if isActivated is true', function () {
this.fnSpy.callCount.should.equal(1) // return false
})
})
describe('isActivated is false', function () {
before(function () {
trigger(this.fn, this.subFn, false)
})
it('should invoke subFn if isActivated is true', function () {
this.subFnSpy.callCount.should.equal(1) // return false
})
})
})
Any suggestion of what I'm doing wrong?

I did not find the exact solution but a workaround quite close from one. So the problem seems to lie with the way this.fn is handled withtin sinon.spy, thus instead of doing:
this.fnSpy = sinon.spy(this.fn)
this.subFnSpy = sinon.spy(this.subFn)
We do the following:
this.fnSpy = sinon.spy(this, 'fn')
this.subFnSpy = sinon.spy(this.fn, 'subFn')
The is easd by the fact that I use this to store fn and subFn.

Related

jest.spyOn is not working when called from a side effect call

I have the following scenario:
const doSomething = () => {
const test = 1;
doAnotherThing();
return test + 1;
};
const doAnotherThing = () => {};
module.exports = {
doSomething,
doAnotherThing
};
And here is my test:
const MyModule = require('./myModule');
describe('MyModule', () => {
it('Should be able to spy another call', () => {
const spy = jest.spyOn(MyModule, 'doAnotherThing');
MyModule.doSomething();
expect(spy).toHaveBeenCalledTimes(1);
});
});
Question, is there a way for the call doAnotherThing() inside the doSomething() be spied by jest in some way, without using solutions like rewire?
Found the solution here: https://medium.com/welldone-software/jest-how-to-mock-a-function-call-inside-a-module-21c05c57a39f
Redefined my module to this and now it's working
const doSomething = () => {
const test = 1;
MyModule.doAnotherThing();
return test + 1;
};
const doAnotherThing = () => {};
const MyModule = {
doSomething: doSomething,
doAnotherThing: doAnotherThing
};
export default MyModule;

expect(jest.fn()).toHaveBeenCalled() fails even though the function has been called

I'm trying to unit test a function that returns a promise. I'm having challenges verifying if
the mocked functions are called. Here's what I've done.,
// codetotest.js
const { SomeModule, isSomething, isSomethingElse } = require("some-module");
exports.somefunction = (param1, param2)=> {
const someModule = new SomeModule();
someModule.someMethod("aaa", isSomething);
someModule.someMethod("bbb", isSomethingElse);
return (someModule.someOtherMethod(param1)
.then(()=>{someModule.run(param2)}));
}
And this is the test file, the test says the mocked functions are not called, but I do see the console statement in the mock function is being displayed.
// codetotest.test.js
const { somefunction} = require("./codetotest.js");
const { SomeModule } = require("some-module");
jest.mock("some-module", () => {
return {
SomeModule: jest.fn().mockImplementation(() => {
return {
someMethod: jest.fn((param, fn) => { console.log("This prints!"); }),
someOtherMethod: jest.fn((param) => { return Promise.resolve(() => { }) }),
run: jest.fn((param) => { return Promise.resolve(() => { return []; }) })
}
})
};
});
afterEach(() => {
jest.resetAllMocks();
jest.restoreAllMocks();
});
describe("Test codetotest.js", () => {
it("somefunction() - success", async () => {
const someModule = new SomeModule();
let output = await somefunction("param1", "param2");
expect(SomeModule).toHaveBeenCalled();
expect(someModule.someMethod).toHaveBeenCalled(); // This fails
await expect(someModule.someOtherMethod.mock.results[0]).resolves;
expect(someModule.someOtherMethod).toHaveBeenCalled(); // This fails
await expect(someModule.run.mocks.results[0]).resolves;
expect(someModule.run).toHaveBeenCalled(); // This fails
});
});
Appreciate any help/pointers.
Thank you.
P.S: I'm still a beginner when it comes to nodeJs development and unit testing.
I spent quite some time on this and finally figured the instantiated mock class didn't return the mocked methods properly. This answer gave me a hint on where I was going wrong.
So accordingly, I had to change my test file as follows.,
// codetotest.test.js
const { somefunction} = require("./codetotest.js");
const { SomeModule } = require("some-module");
jest.mock("some-module", function() {
return {
SomeModule: jest.fn().mockImplementation(function() { // Arrow function cannot be used as constructor
// Because I was not using the 'this' operator, my constructor always returned empty
this.someMethod = jest.fn((param, fn) => { console.log("This prints!"); });
this.someOtherMethod = jest.fn((param) => { return Promise.resolve(() => { }) });
this.run = jest.fn((param) => { return Promise.resolve(() => { return []; }) });
return {
someMethod: this,someMethod,
someOtherMethod: this.someOtherMethod,
run: this.run
}
})
};
});
afterEach(() => {
jest.restoreAllMocks();
});
describe("Test codetotest.js", () => {
it("somefunction() - success", async () => {
await somefunction("param1", "param2");
expect(SomeModule).toHaveBeenCalled();
expect(SomeModule.mock.instances[0].someMethod).toHaveBeenCalled(); // This works
expect(SomeModule.mock.instances[0].someOtherMethod).toHaveBeenCalled(); // This works
expect(someModule.mock.instances[0].run).toHaveBeenCalled(); // This works
});
});

Testing nested function in Jest

I have in file.js code which I simplify this way:
function Apple(,data) {
this.attr1 = data.attr1,
this.attr2 = data.attr2,
this.doSomething(data.flag);
}
Apple.prototype = new function() {
this.function1 = function() {
// do something
}
this.doSomething = function(flag) {
// return value
}
}
I want to test function1(), for that, I want to mock first doSomething() to return a specific value, but I am failing because any call to Apple() function executes immediately doSomething():
describe('Apple', () => {
test('test function1()', () => {
Apple.doSomething = jest.fn().mockImplementation((2) => {
// do something;
});
let apple = new Apple(data); // the original doSomething() executes here instead of the mocked version
});
});
How can I achieve my goal ?
Try using spyOn:
const mockDoSomething = jest.spyOn(Apple.prototype, 'doSomething').mockReturnValueOnce((flag) => {
// mock do something;
})

How do I mock this method chain in Jest?

zoomOut(callback) {
// Zooms out the current screen
this.view.current.zoomOut(300).done(() => {
(hasCallback(callback)) && callback();
});
}
I'm trying to test the function above but I keep getting the following error:
TypeError: this.view.current.zoomOut(...).done is not a function
How can I mock this method chain in Jest?
Thanks to BudgieInWA, I was able to solve this problem by returning done.
For those who are testing a React component with Enzyme, here's how you can do it:
it('should call callback', () => {
const wrapper = shallow(<Zoom {...minProps}/>);
const instance = wrapper.instance();
const callback = jest.fn();
instance.view = {
current: {
zoomOut: jest.fn(() => {
return {
done: jest.fn((callback) => {
callback();
})
};
})
}
};
expect(callback).toHaveBeenCalledTimes(0);
instance.zoomOut(callback);
expect(callback).toHaveBeenCalledTimes(1);
});
You could try this:
const mockZoomOut = jest.fn(() => ({ done(cb) { cb(); } }));
const mockThis = {
view: {
current: {
zoomOut: mockZoomOut,
},
},
};
test('it does', () => {
const cb = jest.fn();
zoomOut.apply(mockThis, [cb]);
expect(mockZoomOut).toHaveBeenCalledTimes(1);
expect(cb).toHaveBeenCalledTimes(1);
});
See Jest Mock Functions and fn.apply.
If you are testing the behaviour of the class as a whole, then you could set up the instance that you are testing to have this.view.current.zoomOut be mockZoomOut somehow.

Sinon spy does not get called

The test is failing on the first expectation. Is there a way to inject a spy to a function so that I can check if the function was called with correct arguments?
var myObj = {}
myObj.prop = function propFn () {
return 'foo'
}
myObj.func = function (disp) {
return disp(this.prop())
}
let disp = sinon.spy()
sinon.stub(myObj, 'prop').callsFake(function fakeFn () {
return 'bar'
})
expect(disp.called).to.be.true
disp.should.have.been.calledWith('bar')
Thanks!
Please try as below,
describe('prop', () => {
const myObj = {};
myObj.prop = function propFn() {
return 'foo';
};
myObj.func = function (disp) {
return disp(this.prop());
};
it('should be called', () => {
sinon.stub(myObj, 'prop').returns('bar');
const disp = sinon.spy();
myObj.func(disp);
expect(disp.callCount).to.equal(1);
expect(myObj.prop.callCount).to.equal(1);
expect(disp.callCount).to.equal(1);
expect(disp.calledWith('bar')).to.equal(true);
});
});
result
prop
✓ should be called
1 passing (975ms)

Categories

Resources