How to enable promises in AngularJS, Jasmine 2.0 when $ scope does not exist to force a digest?

Promises don't seem to allow in Angular / Jasmine tests unless you hit $scope.$digest() . This is a dumb IMO, but it's ok, I work where necessary (controllers).

The situation I'm currently working in is a service that can take care of some areas of the application, but it returns some data from the server, but the promise does not seem to solve.

 app.service('myService', function($q) { return { getSomething: function() { var deferred = $q.defer(); deferred.resolve('test'); return deferred.promise; } } }); 



 describe('Method: getSomething', function() { // In this case the expect()s are never executed it('should get something', function(done) { var promise = myService.getSomething(); promise.then(function(resp) { expect(resp).toBe('test'); expect(1).toEqual(2); }); done(); }); // This throws an error because done() is never called. // Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL. it('should get something', function(done) { var promise = myService.getSomething(); promise.then(function(resp) { expect(resp).toBe('test'); expect(1).toEqual(2); done(); }); }); }); 

What is the correct way to test this functionality?

Edit: solution for reference. Obviously, you are forced to enter and digest $ rootScope, even if the service does not use it.

  it('should get something', function($rootScope, done) { var promise = myService.getSomething(); promise.then(function(resp) { expect(resp).toBe('test'); }); $rootScope.$digest(); done(); }); 
+44
angularjs karma-runner jasmine karma-jasmine
Jun 03 '14 at 17:07
source share
4 answers

You need to enter $rootScope in your test and run $digest .

+39
Jun 03 '14 at 17:11
source share

$ rootScope always exists, use it

 inject(function($rootScope){ myRootScope=$rootScope; }) .... myRootScope.$digest(); 
+11
Jun 03 '14 at 17:10
source share

So, I fight this day all the time. After reading this post, I also felt that there was something with the answer, it turns out. None of the above answers provide a clear explanation of where and why to use $rootScope.$digest . So this is what I came up with.

First, why? You must use $rootScope.$digest whenever you respond to a non-w500> event or callback. This will include pure DOM events, jQuery events, and other third-party Promise libraries other than $q , which are part of angular.

Secondly, where? In your code, not your test. There is no need to inject $rootScope into your test, it is only necessary in your actual angular service. That's where all of the above does not give a clear answer to the question, they show that $rootScope.$digest is called from the test.

I hope this helps the next person who comes for a long time, this is the same problem.

Update




I deleted this post yesterday when it was voted. Today I continued this problem trying to use the answers kindly provided above. So, I am waiting for my answer at the cost of reputation points, and therefore I cancel it.

This is what you need in event handlers that are not angular, and you are using $ q and trying to test Jasmine.

 something.on('ready', function(err) { $rootScope.$apply(function(){deferred.resolve()}); }); 

Note that in some cases it may have to be wrapped in $ timeout.

 something.on('ready', function(err) { $timeout(function(){ $rootScope.$apply(function(){deferred.resolve()}); }); }); 

One more note. In the original problem examples, you call done at the wrong time. You must call done inside the then (either catch or finally ) promise method after it is resolved. You invoke it before the promise is resolved, which leads to the completion of the it clause.

+3
Jun 15 '15 at 1:17
source share

From the angular documentation.

https://docs.angularjs.org/api/ng/service/ $ q

 it('should simulate promise', inject(function($q, $rootScope) { var deferred = $q.defer(); var promise = deferred.promise; var resolvedValue; promise.then(function(value) { resolvedValue = value; }); expect(resolvedValue).toBeUndefined(); // Simulate resolving of promise deferred.resolve(123); // Note that the 'then' function does not get called synchronously. // This is because we want the promise API to always be async, whether or not // it got called synchronously or asynchronously. expect(resolvedValue).toBeUndefined(); // Propagate promise resolution to 'then' functions using $apply(). $rootScope.$apply(); expect(resolvedValue).toEqual(123); })); 
+3
Sep 25 '15 at 17:28
source share



All Articles