Stubbing nested function calls in sinon - javascript

There are three seperate questions that are similar to this one but none of them resembles the case I have.
So I basically have a function which takes a function as a parameter
var myfunc ( func_outer ) {
return func_outer().func_inner();
}
In my unit tests I want to be able to make a stub of a myfunc2. Basically I need to be able to stub a stub which is a nested stub. I currently use this kind of a manual stub but I would rather do it using sinon stubs if there is a way.
const func_outer = () => {
return {
func_inner: () => {return mockResponse;}
}
};
Has anyone ever faced this situation. Is there an easy way to solve this issue?

From sinon documentation you can check the returns section
stub.returns(obj);
Makes the stub return the provided value.
You can try the following:
First you should make sure that you stub your inner function, and then make it return the value you want.
func_innerStub = sinon.stub().returns('mockResponse')
Then stub your outer function and make it return the object with your stubbed inner function.
func_outerStub = sinon.stub().returns({func_inner: func_innerStub})
You can follow this pattern with the myfunc function, as well and pass as a param the func_outerStub.

Related

How to mock functions/methods which updates same object?

I have 2 methods inside class
methodA()
methodB()
Code:
const myModule1 = require('./foo');
const myModule2 = require('./bar');
const obj = {
value: 100,
text: "Hello"
};
const updatedObj = {
value: 200,
text: "Hello"
}
// Inside beforeEach block
myModule.methodA.mockReturnValue(() => obj);
myModule2.methodB.mockReturnValue(() => updatedObj);
Now methodA is returning mock object but the class which I am testing is using methodB and methodA both. Now methodB is updating same mock object which methodA returns and updates obj.value to 200 from 100.
Below expect code is meaningless if I use updatedObj because in that case what is the point of testing.
expect(updatedObj.value).toEqual(200) ---> No point in testing like this
How can I do something like this:
expect(obj.value).toEqual(200) assuming I am mocking return value of methodB which updates same object which returns same mocked obj. How can I achieve this?
So basically I want to mock methodA and methodB both but how to use same object instead of using two different is that possible?
Your understanding is flawed. You do not test mocked objects. You assume that these work as intended. You want to test the code that uses those objects.
The things you do with mocks are:
check the result of the function that uses the mock object (i.e. do not consider the mock state, just provide mocks that return the correct value for that specific example)
You can verify the calls, so you can be sure that the calls to methodA were done with the correct parameters.
In other words you do not check that obj.value was mutated to 200, you check that methodA was called with the correct parameters (such that the real implementation would have modified the object to set the parameter to 200).
You can look at Jest documentation that shows how to fetch the calls to the mock functions and so you'll have to make assertions about the calls, not the actions that the real implementation of the function would have performed.
So if myModule.methodA is a mock function you will check:
expect(myModule.methodA.mock.calls).toEqual([[200]])
This will test that the code made one call to methodA with a parameter of 200.
Whether the real methodA would then have modified obj is an implementation detail that shouldn't really matter.
(You did not show the arguments of methodA or B, so obviously that will change depending on how it is called.
This said, be aware that unit testing try to isolate the different parts of the system, and to do this we use mocks. However it is also very useful to have integration tests. Basically just run methodA for real using in memory databases or webservers in place of the real stuff.
Basically checking that obj is changed with a value of 200 in this situation should be part of integration testing, not of the unit tests for the code that uses the mocked versions of methodA/B.

Aliases for jest.fn()?

I have two different libraries that I'm using to make mocks in Jest. The libraries have the same function called get. This is a problem for my current implementation since get is used by two different libraries is it possible to use an alias for mock functions (jest.fn()) or maybe some kind of workaround that doesn't ruin the integrity of the current implementation?
Here is my current implementation and I would I like to keep this way if possible:
let get: jest.Mock<{}>
jest.mock('rxjs/ajax', () => {
get = jest.fn()
return { ajax: { get } }
})
let get as cookieGet: jest.Mock<()> // Can I do something like this
jest.mock('js-cookie', () => {
get = jest.fn()
return { get }
})
I'm not too familiar with aliases in JS or they Jest handles things like this so any help is much appreciated.
It's unnecessary to use { get } shorthand property syntax for object literal if it results in name collisions.
Another problem is that a variable needs to have mock prefix in order to be used in the scope of jest.mock factory function. As the documentation states,
A limitation with the factory parameter is that, since calls to jest.mock() are hoisted to the top of the file, it's not possible to first define a variable and then use it in the factory. An exception is made for variables that start with the word 'mock'. It's up to you to guarantee that they will be initialized on time!
It can be:
import ... from 'rxjs/ajax';
import ... from 'js-cookie';
let mockRxAjaxGet: jest.Mock<{}>
jest.mock('rxjs/ajax', () => {
mockRxAjaxGet = jest.fn()
return { ajax: { get: mockRxAjaxGet } }
})
let mockJsCookieGet: jest.Mock<()>
jest.mock('js-cookie', () => {
mockJsCookieGet = jest.fn()
return { get: mockJsCookieGet }
})
The problem is that once jest.mock is hoisted above imports, it will be evaluated when let variables are in temporal dead zone and cannot be assigned.
So let should be preferably changed to var, which is hoisted. Or mocked function be imported as usual and used with get as jest.Mock<...> where a spy is expected. mocked helper can be used to enforce TypeScript type safety.

Should a function calling promise and not returning anything be considered an error?

I have a one method that looks like this:
doSomething(){
return somethingPromisy().then((blerp) => {
// do something with blerp
return blerp; // Modified, of course
});
};
Then I have another method that looks like this:
doSomethingElse(){
stepOne();
var x = stepTwo();
var y = stepThree(x);
doSomething.then((data) => {
stepFour(data + y);
});
};
I'm using mocha+chai+sinon to test this code, in particular, doSomethingElse, and then I want to make some assertions - but how can I guarantee that the promise will be resolved by the time I make assertions? I know one option would be to change it to:
doSomethingElse(){
/* ... */
return doSomething.then(...);
};
If I do this, then it's pretty easy to write my test because then it's:
return doSomethingElse().then(() => {
someFake.lastCall.args.should.deep.equal(expectedData);
});
In my test and everything is fine. But should I be returning the promise simply for the sake of returning the promise? I don't actually care about any kind of return value from doSomethingElse - I only care that when I'm testing that the function in doSomething.then was called, i.e. the doSomething promise has been resolved by the time I do my assertions.
So what's the "best" way to go about this?
You should be testing doSomething and doSomethingElse separately with doSomethingElse using a mock of doSomething, with a mocked then methd that can return your value for testing. You basically want to test them separately not at the same time. You're basically coupling doSomething and doSomethingElse in this case which makes testing harder. Testing should be easy, you aren't testing to see if promises work, so use a fake one to move on to testing logic!
I do not find a lack of return value to be an issue myself, there is a return value, you're just chaining it, not storing it.

Sinon Stub JavaScript Method Chain

I'm looking to use sinon stub to test the method chain below:
driver.manage().window().setSize()
I found a related question that explains how to access one method down the chain, however this does not seem to give me access to any additional methods.
t.context.webdriver = sinon.stub(new WebDriver)
sinon.stub(t.context.webdriver, "manage", () => {
return {
window: sinon.stub().returns();
};
})
which returns the error
Error: this._driver.manage(...).window(...).setSize is not a function
How to I stub multi-level method chains?
I'm not sure what your trying to to test, but the error is coming from the fact that the object your stub is returning doesn't have a window() function or a setSize(). Chains work because each part of the chain returns something with a method that matches the next call. So if you stuff something early in the chain, you need to makes sure what you return has those methods. Maybe that involves passing back the original return, or maybe you fake the whole chain.
Here's an example that at least won't throw:
const sinon = require('sinon')
// some fake object that maybe looks like what you have
let driver = {
manage(){ return this},
window() { return this},
setSize() {console.log("size set")}
}
// stubb manage and now you're resposible for the whole chain
sinon.stub(driver, "manage").callsFake(() => {
console.log("called")
return {
window(){
return { setSize: sinon.stub().returns() }
}
};
})
Of course, there are a lot of variations possible depending on what you're trying to test.

A stub that returns a stub

Let's say you have code that returns an object containing pre-programmed functions, which you use like this:
someFunction(/* pass in data */)
.post(/* some data */) //Returned post function is pre-programmed to send a POST request to the right URL
.then(function() {
//do something
});
How can I unit test this using sinon.js?
To direct what a function returns, you need to use a stub:
var mockService = sinon.stub();
mockService.returns(/* some return value */);
But let's say I want to verify that someFunction was called with the right arguments, in addition to verifying that the returned post function was called with the right arguments. I would need a stub to return a stub:
mockService.returns({
post: sinon.stub()
});
How can I access mockService.post to verify that the right arguments were passed, in this case?
Bonus Question: What's the name of this design pattern (returning a function with pre-programmed behavior)? I've seen it used before, but don't know the name of it.
Since no one answered, I worked around this like this:
var mockServicePost = sinon.stub();
var mockService = sinon.stub();
mockService.returns({
post: mockServicePost
});
But I am interested to know if there's a more elegant solution than this.

Categories