$scope.$watch('hb.bulkPromise', function (promise) {
promise.then(function (resource) {
return resource.test();
}).then(function (data){
})
}
I have a structure in my angular directive with promise.
How can we write test for the above promise.
When unit testing Angular, all promises are triggered to complete when you call $scope.$digest(). The timing is then up to you. The basic steps go:
Prep your test variables and other structures
Call the code that sets up the promise.
Call $scope.$digest() to trigger the promise.
Test for your expected results.
Assuming you are using the jasmine testing framework.
I believe you will need to mock promises similar to what is done here about halfway down the page..
Related
I'm testing a $resource. If I have code like this:
$resource.do(stuff).$promise.then(function(data){
console.log(1);
});
console.log(2);
I get the print out:
2
1
But if I have code like this:
var callback = function(data){
console.log(1);
}
$resource.do(stuff,callback);
console.log(2);
I get the print out:
1
2
Why? I have found that with the second method, I do not need to call $rootScope.$apply() to get the correct output from my unit test (instead of console.log(2), I return a variable). Using the first method, I have to call $rootScope.$apply() in my unit test in order to get output. I thought that passing callbacks is the same as calling .then on a promise?
The callback is called as soon as the $resource finishes what it is doing. This doesn't have to be in the Angular digest cycle. The promise is resolved in the angular digest cycle. When you call $rootScope.$apply()
For more see: Resolving promises without a digest cycle
I'm trying to automate the testing of Angular services which happen to make calls to Parse.com through Parse SDK.
The problem I have got is that the promises dont get resolved unless I explicitely trigger a digest cycle, and the way my services are done, I have to do that in my services implementations which is not sustainable.
My service code is the following :
factory('myService', function($http, $q, $rootScope) {
var myService = {};
myService.simplePromiseTest = function() {
var p = $q.defer();
var query = new Parse.Query("AnyObjectInParse");
query.find().then(function(results){
p.resolve(results);
// *** I have to include that line for the jasmine test to run ***
$rootScope.$apply();
});
return p.promise;
}
}
return myService;
}
And here is my jasmine test
async.it('should resolve the promise', function(done) {
myService.simplePromiseTest().then(function(results) {
// this is never called if don't trigger the digest from the service code
done();
});
// This line is use less as when I get into that line, the promise is not resolved.
// $scope.$root.$digest();
});
So the situation is as following :
I have to wait for the call to parse to end before triggering a digest cycle
I can't find any other solution than to pollute my service's code with this code
I'd like to find a sustainable solution which doesn't require me to update my service's code to pass the test.
Thanks in advance I'm lost with that, I may be missing something obvious :-)
Call $rootScope.$apply(); in the test itself rather than in the promise implementation. Tests with done are asynchronous so it's ok to resolve it afterwards. Alternatively use Angular 1.3.
In general for testing promises I'd probably recommend mocha rather than Jasmine since it supports promise tests out of the box with return statements.
I have the following controller:
app.controller('SearchVideosController',
function SearchVideosController($scope, videoRepository) {
$scope.DoSearch(id, text) {
// Do some work...
videoRepository.getVideosForUserBasedOnSearchText(id,text)
.then(function(data){
// Do something with the data.
});
};
};
My videoRepository.getVideosForUserBasedOnSearchText() method uses $q and I want to create stub to ensure that the call is made.
I tried :
it("should have 3 searched videos", function(){
...
mockVideoRepository.getVideosForUserBasedOnSearchText.returns([]);
but get .then() is undefined.
Not sure how to handle the then() call.
You would need to get hold of $q service instance and use $q.when to create a promise wrapped value:-
mockVideoRepository.getVideosForUserBasedOnSearchText.returns($q.when([]));
Also remember you would need to manually perform a digest cycle in your test before the expecation to evaluate the result of the getVideosForUserBasedOnSearchText call. Only when a digest cycle is invoked promise will be resolved in your test. You can do it by getting hold of scope, and perform $digest or $apply. Example:- rootScope.$apply()
I am trying to stub a method using sinon, jasmine and $q.
I want that method to return my fake data.
The problem is that the defined then statement is never called and i can not figure out why.
This already is a simplified version but it still isn't working:
The stub is called
The console log Steven Stub is called gets called
None of the then callbacks are called
No error message
Here is my code
var p = {steven: function() {console.log('original steven');}},
pStub = sinon.stub(p, 'steven', function(){
console.log('Steven Stub is called');
var defer = $q.defer();
defer.resolve({item: 5});
return defer.promise;
});
var promise = p.steven();
promise.then(
function(data){console.log('Peter?');},
function(data) {console.log('ERROR?');},
function(data) {console.log('progress?');});
Any idea?
You need to call a digest in order to resolve a promise. In Angular 2.0 this will be fixed, (and Angular 1.2 is slightly better here than Angular 1.1) but in the meanwhile you have to call
$rootScope.$digest()
In order to cause the promises to resolve. This is because promises work via evalAsync. See this question to learn more about how the digest cycle interacts with $q promises lifecycle.
I'm testing a promise with angularjs jasmine, and sinonjs.
I'm puzzled by something regarding promises. Here is my code:
it('should return data with length 4 ', inject(function ($rootScope) {
var storageData;
mockDualStorage.getData.returns($.when(''));
// mockDualStorage.getData is called by getStorageData
// $rootScope.$digest() // not working here
dataGetter.getStorageData().then(function (data) {
console.log(1);
storageData = data;
});
$rootScope.$digest(); // only working here
console.log(2);
expect(storageData.length).toBe(4)// ok
}));
Couple of things are strange here.
If I put $rootScope.$digest() above the dataGetter.getStorageData() then function is never executed.
When the $rootScope.$digest() is below, then gets executed, and order of console.log is 1,2
Why won't then execute when $rootScope.$digest() is above? As I understand promise is already resolved?
After more carefully reading the documentation, found the answer right there.
Differences between Kris Kowal's Q and $q :
There are two main differences: $q is integrated with the $rootScope.Scope Scope model observation mechanism in angular, which means faster propagation of resolution or rejection into your models and avoiding unnecessary browser repaints, which would result in flickering UI.
AngularJS $q service documentation