Testing promises modules in controllers in AngularJS

We recently started including promises in our controllers to handle multiple requests at the same time, and it works in the application, but unit testing turned out to be more difficult and I will have difficulty with what it is, I'm missing. Below are two snippets which are very simplified as to what I am exactly trying to test.

Controller:

angular.module('testengine').controller('testController', [
  '$scope', 
  '$q', 
  'Api', 
  function($scope, $q, Api) {
    $scope.getTest = function (deferred) {

      // do stuff...

      Api.test.get(params, function(response) {
        // do stuff with response

        if (deferred) {
          deferred.resolve(); // if success
        }
      });

    };

    $scope.runTest = function () {

       // do stuff...

       var promises = [];
       var deferred = $q.defer();

       promises.push(deferred.promise);
       $scope.getTest(deferred);

       $q.all(promises).then(function () {
         $scope.navigate();
       }, function () {
         // do stuff with rejected
       });

    };

    $scope.navigate = function () {
      // do stuff
    };
  }]);

      

Test:

describe('Controller:', function () {

  var root, scope, controllerFactory, $q;

  function createController () {
    return controllerFactory('testController', {
      $scope: scope
    });
  }

  beforeEach(function () {
    module('testengine');
  });

  beforeEach(inject(function ($rootScope, $controller, _$q_) {
    root = $rootScope;
    scope = $rootScope.new();
    controllerFactory = $controller;
    $q = _$q_;
  });

  it('should run test', function () {
    createController();

    var deferred = $q.defer();
    spyOn(scope, 'getTest').andReturn(deferred.resolve());
    spyOn(scope, 'navigate');

    $scope.runTest();

    root.$apply();
    expect(scope.navigate).toHaveBeenCalled();
  });
});

      

According to all the examples and documentation I've read on promises and $ q this should work, but it doesn't, instead I get:

Expected spy navigate to have been called but it was never called.

      

I am guessing because this is not the same deferred object that I solve in my mocked spy, but how do I suppose he is mocking this? Should I bind the deferred object on the controller or scope or what?

The reason for the structure you see is because using getTest () (and some of them use not only this request, but others and hence promises as well). Also, getTest () is tested separately in another test, so I want to mock this function and any requests made in it.

Any help is greatly appreciated and if I did make some glaring mistakes I would be glad to know that I am still new to Angular.

+1


source to share


1 answer


Yes, you are not solving the correct promise. You need to intercept the function arguments.

spyOn(scope, 'getTest');
expect(scope.getTest).toHaveBeenCalled();
scope.getTest.mostRecentCall.args[0].resolve();

      



This is a nice quick Jasmine link: http://tobyho.com/2011/12/15/jasmine-spy-cheatsheet/

+1


source







All Articles