Home » JavaScript » Angular.js » Learning Angular: Testing $q promise resolves with Sinon and Jasmine

About Juri Strumpflohner

Juri Strumpflohner
Juri Strumpflohner mainly operates in the web sector developing rich applications with HTML5 and JavaScript. Beside having a Java background and developing Android applications he currently works as a software architect in the e-government sector. When he’s not coding or blogging about his newest discoveries, he is practicing Yoseikan Budo where he owns a 2nd DAN.

Learning Angular: Testing $q promise resolves with Sinon and Jasmine

This article shows a brief example on how to properly mock and resolve a $q promise from within a Jasmine unit test.

This article is part of my “Learning NG” series, presenting some of my adventures while learning Angular. Check out the series intro and other articles. Note, I’m an Angular newbie, so I’m more than happy for any kind of feedback and improvement suggestions from more experienced people than me.

Problem

I have a service, let’s call it consumerService which uses another service personService to make an asynchronous call. In the case of a successful response, it calls a method on a 3rd service, called helloWorldService. What I’d like to test is the fact that the helloWorldService gets called upon a successful call of the personService.

Roughly, the code looks like this:

app.factory('consumerService', function(personService, helloWorldService){
  var service = {
    doSomething: doSomething
  };
  return service;

  function doSomething(){
    personService.get()
      .then(function(){
        // I want to test this one here
        helloWorldService.sayHello();
      })
  }

});

To test it, I need to stub the personService.get() function s.t. it positively resolves the promise it returns.

Solution

For stubbing, we can use Sinon.js. The first param is the object on which to operate upon, then the name of the function to stub and as the 3rd param I pass in the function that gets called instead of the original one.

sandbox.stub(personService, 'get', function(){
    var deferred = $q.defer();

    // immediately resolve it
    deferred.resolve();

    return deferred.promise;
  });

As you can see, the stubbed function creates a new deferred, using Angular’s $q service and immediately resolves it.

Note, in this particular test we’re not interested in a specific return value, otherwise you’d have to pass that desired value to the .resolve(...) function.

Then we also stub the helloWorldService.sayHello function to be able to listen to the number of invocations.

...
sandbox.stub(helloWorldService, 'sayHello');

Then invoke the SUT (subject under test):

...
consumerService.doSomething();

Finally, the expectations:

$scope.$apply();
expect(helloWorldService.sayHello.calledOnce).toBeTruthy();

What does that $scope.$apply() do there?? That’s the important piece actually. If you don’t call it, your promise won’t get resolved. The Angular documentation emphasizes this: https://docs.angularjs.org/api/ng/service/$q.

So, all wrapped up (highlighting the important pieces):

var sandbox;
var $scope;
...

describe('using the person service', function() {

  beforeEach(inject(function($rootScope, _consumerService_, _personService_, _helloWorldService_) {
      sandbox = sinon.sandbox.create();
      $scope = $rootScope.$new();
      ...
    }));

    afterEach(function(){
      sandbox.restore();
    });

    ...

    it('should properly resolve the promise', inject(function($q) {
      sandbox.stub(personService, 'get', function(){
        var deferred = $q.defer();

        // immediately resolve it
        deferred.resolve();

        return deferred.promise;
      });
      sandbox.stub(helloWorldService, 'sayHello');

      consumerService.doSomething();

      // THIS IS THE IMPORTANT CALL HERE
      $scope.$apply();

      expect(helloWorldService.sayHello.calledOnce).toBeTruthy();
    }));
});

You can try it live in the Plunkr below.

(0 rating, 0 votes)
You need to be a registered member to rate this.
Start the discussion Views Tweet it!
Do you want to know how to develop your skillset to become a Web Rockstar?
Subscribe to our newsletter to start Rocking right now!
To get you started we give you our best selling eBooks for FREE!
1. Building web apps with Node.js
2. HTML5 Programming Cookbook
3. CSS Programming Cookbook
4. AngularJS Programming Cookbook
5. jQuery Programming Cookbook
6. Bootstrap Programming Cookbook
and many more ....
I agree to the Terms and Privacy Policy
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments