mardi 12 avril 2016

Jasmine unit testing mocking service that returns promises

I keep getting an undefined error running one of my unit tests and it seems to be related to jasmine.createSpyObj.

When I run my tests using grunt from the command line they work but when I try running them in maven using ghostdriver I run into this issue and I cannot finish my build. I think there may be something odd with the way I am doing the unit test, can anyone help me?

Angular app:

    'use strict';

    var calculatorApp = angular.module('calculatorApp', [
  'config',
  'ngRoute',  
  'calculatorControllers', 
  'calculatorServices'
   ] );

calculatorApp.config(['$routeProvider',
  function($routeProvider) {
    $routeProvider.
      when('/calculator', {
        templateUrl: 'partials/calculator.html',
        controller: 'CalculatorCtrl'
      }).
      when('/about', {
        templateUrl: 'partials/about.html',
        controller: 'AboutCtrl'
      }).
      otherwise({
        redirectTo: '/calculator'
      });
  }]);

Angular service:

'use strict';

/* Calculator Services */

var calculatorServices = angular.module('calculatorServices', ['ngResource']);

calculatorServices.factory('CalculatorService', ['$http', 'API_URL', function($http, API_URL) { 
    this.add =  function(val1, val2) {  

        return $http({
            method: 'GET',
            url: API_URL+'calculator/add',
             params: {
                val1: val1,
                val2: val2  
             }
        }).then(function successCallback(response) {            
            return response.data.result;        
        }, function errorCallback(response) {
            alert('Error: ', response);         
        }); 
    };

    return { add: this.add };
  }]);

Angular Controller:

'use strict';

/* Controllers */

var calculatorControllers = angular.module('calculatorControllers', []);

calculatorControllers.controller('BodyController', ['$scope',
   function($scope) {
       $scope.toggleNavBarActive = function($event) {            
          $($event.currentTarget).parent().find('.active').removeClass('active');
          $($event.currentTarget).addClass('active');
       };
}]);

calculatorControllers.controller('CalculatorCtrl', ['$scope', 'CalculatorService',
  function($scope, CalculatorService) { 
    $scope.result = ' awaiting calculation';
    $scope.sum = {};   

    $scope.add = function(val1, val2) {         
        var promise = CalculatorService.add(val1, val2);  
        promise.then(function(response) {
            $scope.result = response;
        });     
    };   
}]);

calculatorControllers.controller('AboutCtrl', ['$scope', '$routeParams',
  function($scope, $routeParams) {

}]);

Here is my test:

'use strict';

/* jasmine specs for controllers go here */
describe('CalculatorCtrl', function() {
     var $scope, ctrl, $httpBackend, calculatorServiceMock, q;

    beforeEach(function () {      
        module('calculatorApp'); // <= initialize module that should be tested


        // $rootScope - injected to create a new $scope instance.
        // $controller - injected to create an instance of our controller.
        // $q - injected so we can create promises for our mocks.
        // _$timeout_ - injected to we can flush unresolved promises.
        inject(function($rootScope, $controller, _$q_, _$httpBackend_) {
          // create a scope object for us to use.
          q = _$q_;
          $scope = $rootScope.$new();
          $httpBackend = _$httpBackend_;
          $httpBackend.whenGET('partials/calculator.html').respond(200, '');

          // set up the returns for our calculatorServiceMock   
          calculatorServiceMock = jasmine.createSpyObj('CalculatorService', ['add']);

          ctrl = $controller('CalculatorCtrl', {             
                $scope: $scope,
                CalculatorService: calculatorServiceMock,
          });                                                                                     
        });
      });  

    it("creates spies for each requested function", function () {
        expect(jasmine).toBeDefined();
        expect(calculatorServiceMock).toBeDefined();
        expect(calculatorServiceMock.add).toBeDefined();                
    });

    it('should start with q, scope, http_backend defined', function() {         
        //just assert. $scope was set up in beforeEach() (above)
        expect(q).toBeDefined();
        expect($scope).toBeDefined();       
        expect(ctrl).toBeDefined(); 
        expect($httpBackend).toBeDefined();
    });

     it('should start with result and sum populated', function() {          
            //just assert. $scope was set up in beforeEach() (above)            
            expect($scope.add).toBeDefined();
            expect( $scope.result).toEqual(' awaiting calculation');
            expect($scope.sum).toEqual({});        
     });

     it('should make call via function add()', function() {                         
            calculatorServiceMock.add.and.returnValue(q.when(5));

            $scope.add(3,2);    
            $httpBackend.flush();           
            expect(calculatorServiceMock.add).toHaveBeenCalled();          
            expect($scope.result).toEqual(5); 
     });
});

And running the tests gives this output:

-------------------------------------------------------
 J A S M I N E   S P E C S
-------------------------------------------------------
[INFO] 
CalculatorCtrl
  creates spies for each requested function
  should start with q, scope, http_backend defined
  should start with result and sum populated
  should make call via function add() <<< FAILURE!
    * TypeError: undefined is not an object (evaluating 'calculatorServiceMock.add.and.returnValue') in http://localhost:61568/spec/controllersSpec.js (line 54)

service
  check the existence of calculator service
  should return data when calling add

1 failure:

  1.) CalculatorCtrl it should make call via function add() <<< FAILURE!
    * TypeError: undefined is not an object (evaluating 'calculatorServiceMock.add.and.returnValue') in http://localhost:61568/spec/controllersSpec.js (line 54)

Results: 6 specs, 1 failures

Can anyone help me with this? The tests actually pass in the console if I kick them off with grunt so I am not sure what could be causing the problem but perhaps there is another or better way to write the test?

I am using the same version of the ghost driver when running the tests in the console as I am when running the tests from maven so I am really stuck on this.

Aucun commentaire:

Enregistrer un commentaire