In angularjs, while testing a service, I want to check if the returned object is an Promise.
Right now I am doing the following -
obj.testMethod()
.should.be.instanceOf($q.defer());
In angularjs, while testing a service, I want to check if the returned object is an Promise.
Right now I am doing the following -
obj.testMethod()
.should.be.instanceOf($q.defer());
Testing if an object is a promise is simple:
return !!obj.then && typeof obj.then === 'function';
That's it. If an object has the then
method, it's a promise.
It looks like angular's $q doesn't have anything to differentiate it from other kind of promises.
Looking at line 248 in the source for $q (https://github.com/angular/angular.js/blob/master/src/ng/q.js#L248) there isn't really a check you can do thats definite. This would be your best bet
var deferred = method();
if(angular.isObject(deferred) &&
angular.isObject(deferred.promise) &&
deferred.promise.then instanceof Function &&
deferred.promise["catch"] instanceof Function &&
deferred.promise["finally"] instanceof Function){
//This is a simple Promise
}
If the promise was actually a function where you could use new Promise()
then you would be able to use promise instanceof Promise
, however it's an object so it doesn't have any special identifiers, the only things you can test are their properties.
EDIT:
To test for a "HttpPromise
" then you can add on checks for error
and success
which are defined in the $http
service (https://github.com/angular/angular.js/blob/master/src/ng/http.js#L726):
var promise = $http(...);
if(angular.isObject(promise) &&
promise.then instanceof Function &&
promise["catch"] instanceof Function &&
promise["finally"] instanceof Function &&
promise.error instanceof Function &&
promise.success instanceof Function){
//This is a HttpPromise
}
EXTRA:
If you notice $http doesn't actually return deferred
, it returns the straight promise, if you follow the calls it's actually returns $q.when(...)
with a couple of functions added to it. You can see that $q.when
doesn't return deferred
, rather it returns $q.deferred().promise
, so in turn $http(...)
would never be $q.deferred()
Also, if you were to run the test you had posted I would expect you to get this error:
TypeError: Expecting a function in instanceof check, but got #<Object>
You could mock $http
and have it return some object you create. Then you can check whether your service returns that object.
I was working with callbacks, I needed a CTA on click event to fire a function and determine what type of callback was fired, here is some simple examples.
let fn = function () { alert('A simple function') };
let cta = fn();
console.log(cta instanceof Promise);
// logs false
New Promise Example
let fn = function () {
return new Promise(function (accept, reject) {
accept();
// reject();
});
};
let cta = fn();
if(cta instanceof Promise) {
cta.then(function () {
alert('I was a promise');
});
}
Axios Example 1
let fn = function () {
return axios.get('/user');
}
let cta = fn();
if(cta instanceof Promise) {
cta.then(function () {
alert('I was a promise from axios');
});
}
// Triggers alert('I was a promise from axios');
Axios Example 2
let fn = function () {
return axios.get('/user').then(response => {
console.log('user response', response.data);
});
}
let cta = fn();
if(cta instanceof Promise) {
cta.finally(function () {
alert('I was a final promise from axios');
});
}
// Triggers alert('I was a final promise from axios');