How does one stub promise with sinon?
JavascriptJasmineSinonJavascript Problem Overview
I have a data service with following function
function getInsureds(searchCriteria) {
var deferred = $q.defer();
insuredsSearch.get(searchCriteria,
function (insureds) {
deferred.resolve(insureds);
},
function (response) {
deferred.reject(response);
});
return deferred.promise;
}
I want to test following function:
function search ()
{
dataService
.getInsureds(vm.searchCriteria)
.then(function (response) {
vm.searchCompleted = true;
if (response.insureds.length > 100) {
vm.searchResults = response.insureds.slice(0, 99);
} else {
vm.searchResults = response.insureds;
}
});
}
How would I stub the promise so that when I call getInsureds it would resolve the promise and return me the results immediately. I started like this (jasmine test), but I am stuck, as I don't know how to resolve the promise and pass in arguments needed.
it("search returns over 100 results searchResults should contain only 100 records ", function () {
var results103 = new Array();
for (var i = 0; i < 103; i++) {
results103.push(i);
}
var fakeSearchForm = { $valid: true };
var isSearchValidStub = sinon.stub(sut, "isSearchCriteriaValid").returns(true);
var deferred = $q.defer();
var promise = deferred.promise;
var dsStub = sinon.stub(inSearchDataSvc, "getInsureds").returns(promise);
var resolveStub = sinon.stub(deferred, "resolve");
//how do i call resolve and pass in results103
sut.performSearch(fakeSearchForm);
sinon.assert.calledOnce(isSearchValidStub);
sinon.assert.calledOnce(dsStub);
sinon.assert.called(resolveStub);
expect(sut.searchResults.length).toBe(100);
});
Javascript Solutions
Solution 1 - Javascript
At current sinon version v2.3.1, you can use stub.resolves(value)
and stub.rejects(value)
function
For example, you can stub myClass.myFunction with following code
sinon.stub(myClass, 'myFunction').resolves('the value you want to return');
or
sinon.stub(myClass, 'myFunction').rejects('the error information you want to return');
Solution 2 - Javascript
You just have to resolve the promise before you call the search function. This way your stub will return a resolved promise and then
will be called immediately. So instead of
var resolveStub = sinon.stub(deferred, "resolve");
you will resolve the deferred with your fake response data
deferred.resolve({insureds: results103})
Solution 3 - Javascript
Also you can do something like this:
import sinon from 'sinon';
const sandbox = sinon.sandbox.create();
const promiseResolved = () => sandbox.stub().returns(Promise.resolve('resolved'));
const promiseRejected = () => sandbox.stub().returns(Promise.reject('rejected'));
const x = (promise) => {
return promise()
.then((result) => console.log('result', result))
.catch((error) => console.log('error', error))
}
x(promiseResolved); // resolved
x(promiseRejected); // rejected
Solution 4 - Javascript
I had a similar situation and the accepted answer and comments were not working, but along with this question they helped me solve this in the following way. I hope it is helpful for somebody.
var Promise = require('bluebird');
var deferred = Promise.defer();
stub = sinon.stub(deferred, 'resolve').returns(deferred.promise);
deferred.resolve({data: data});
// or
deferred.reject(new Error('fake error'));
Solution 5 - Javascript
There's one more alternative I found. Much pain free than other methods.
You can use this npm package: sinon-stub-promise.
It abstracts much of the details, so that you don't have to invent the wheel again. Helped my write my tests after struggling to simulate a promise for long.
Hope it helps!