1
votes

I'm trying to test an angular controller which has a dependency on a service and the service method returns promise. I'm creating a jasmine spy object to mock the service and the method returning the promise. But for some reason my mock promise isn't returning the resolved result.

Here is my controller and service code.

(function(){
'use strict';
angular
    .module("supportPortal",[])
    .service('TipsService' ,['$http' ,TipsService])
    .controller('TipsCtrl', [ 'TipsService', TipsCtrl]);

function TipsService($http) {
    this.path = 'api/bondtipsfactor';
    this.tipsFactors = [];
    this.getMinMaxDates = getMinMaxDates;
    this.getData = getData;

    function getMinMaxDates() {

        var self = this;
        var promise = $http.get(self.path + '/minmaxdate').then(function (result) {
            return result.data;
        });
        return promise;
    }
}

function TipsCtrl(TipsService) {
/* jshint validthis:true */

 var vm = this,
 svc = TipsService;
 vm.title = 'TipsCtrl';
 vm.setMonths = setMonths;
 var today = new Date();
 vm.minMonth = 1;
 vm.minYear = today.getFullYear();
 vm.maxYear = today.getFullYear();
vm.maxMonth = today.getMonth() + 1;
vm.years = [];
vm.months = [];
vm.selectedYear = 2014;
vm.selectedMonth;
activate();
function activate() { 
    svc.getMinMaxDates().then(function (data) {
        console.log(data);
        var minDate = new Date(data.MinDate),
                maxDate = new Date(data.MaxDate);
        maxDate.setMonth(maxDate.getMonth() + 1);
    vm.minMonth = minDate.getMonth();
    vm.minYear = minDate.getFullYear();
    vm.maxMonth = maxDate.getMonth();
    vm.maxYear = maxDate.getFullYear();
    for (var i = vm.minYear; i <= vm.maxYear; i++) {
      vm.years[i - vm.minYear] = i;
    }
  });
}

function setMonths(year) {
    var startMonth = year === vm.minYear? vm.minMonth: 1,
            endMonth = year === vm.maxYear ? vm.maxMonth : 12;
    vm.month=[];
    for (var i = startMonth; i <= endMonth; i++) {
        vm.months[i - startMonth] = i;
    }
}
}
})();

and here is the test code

describe("TipsCtrlSpec", function () {
describe("TipsCtrl", function () {

    var ctrl, service, $q, $controller;
    beforeEach(angular.mock.module("supportPortal", function($provide) {
        service = jasmine.createSpyObj("TipsService", ['getMinMaxDates']);
        $provide.value("TipsService", service);
    }));

    beforeEach(inject(function (_$controller_, _$q_, _TipsService_) {
        service = _TipsService_;
        $q = _$q_;
        $controller = _$controller_;
    }));

    function createController(resolve)
    {
        var deferred = $q.defer();
        service.getMinMaxDates.and.returnValue(deferred.promise);
        ctrl = $controller("TipsCtrl", {
            TipsService: service
        });
        if (resolve) {
            deferred.resolve({
                MinDate: "01/01/2013",
                MaxDate: "01/01/2014"
            });
        } else {
            deferred.reject();
        }
    }

    it("activate sets min max dates", function () {
        createController(true);
        expect(ctrl).toBeDefined();
        expect(service.getMinMaxDates).toHaveBeenCalled();
        expect(ctrl.minYear).toBe(2013);
    })
});
});

Here is the live code

1

1 Answers

2
votes

When unit testing using ngMock you need to synchronously maintain the flow of the tests and manually trigger the digest cycle for promises to actually return.

You can for example do this by calling $rootScope.$digest():

it("activate sets min max dates", function() {
  createController(true);
  $rootScope.$digest();
  expect(ctrl).toBeDefined();
  expect(service.getMinMaxDates).toHaveBeenCalled();
  expect(ctrl.minYear).toBe(2013);
});

Demo: http://plnkr.co/edit/vWs1Dx0bjXsdrWCJKWh9?p=preview