mercredi 27 avril 2016

Getting started with Ionic/Angular unit testing controllers with jasmine

I have been trying to write unit tests for angular controller in Ionic framework with jasmine and karma. Here is my controller.

angular.module('starter').controller('LoginCtrl', ['$scope', 'AuthService', '$ionicPopup', '$state', function LoginCtrl($scope, AuthService, $ionicPopup, $state) {
  $scope.user = {
    name: '',
    password: ''
  };

  $scope.login = function() {
    AuthService.login($scope.user).then(function(msg) {
      $state.go('inside');
    }, function(errMsg) {
      var alertPopup = $ionicPopup.alert({
        title: 'Login failed!',
        template: errMsg
      });
    });
  };
}]);


angular.module('starter').controller('RegisterCtrl', ['$scope', 'AuthService', '$ionicPopup', '$state', function RegisterCtrl($scope, AuthService, $ionicPopup, $state) {
  $scope.user = {
    name: '',
    password: ''
  };

  $scope.signup = function() {
    AuthService.register($scope.user).then(function(msg) {
      $state.go('outside.login');
      var alertPopup = $ionicPopup.alert({
        title: 'Register success!',
        template: msg
      });
    }, function(errMsg) {
      var alertPopup = $ionicPopup.alert({
        title: 'Register failed!',
        template: errMsg
      });
    });
  };
}]);

angular.module('starter').controller('InsideCtrl', ['$scope', 'AuthService', 'API_ENDPOINT', '$http', '$state', function InsideCtrl($scope, AuthService, API_ENDPOINT, $http, $state) {
  $scope.destroySession = function() {
    AuthService.logout();
  };

  $scope.getInfo = function() {
    $http.get(API_ENDPOINT.url + '/memberinfo').then(function(result) {
      $scope.memberinfo = result.data.msg;
    });
  };

  $scope.logout = function() {
    AuthService.logout();
    $state.go('outside.login');
  };
}]);

angular.module('starter').controller('AppCtrl', ['$scope', '$state', '$ionicPopup', 'AuthService', 'AUTH_EVENTS', function AppCtrl($scope, $state, $ionicPopup, AuthService, AUTH_EVENTS) {
  $scope.$on(AUTH_EVENTS.notAuthenticated, function(event) {
    AuthService.logout();
    $state.go('outside.login');
    var alertPopup = $ionicPopup.alert({
      title: 'Session Lost!',
      template: 'Sorry, You have to login again.'
    });
  });
}]);

})(reader || (reader = {}));

I want to have this 3 test suits:

  1. Should call login on $AuthService Service
  2. If login successful, should change state to inside
  3. If login unsuccessful, should show a popup error message

I em try to write som test but i thin that i am not injecting the controller properly. Here is the code for my tests:

describe('LoginCtrl', function() {

    var $controller,
        LoginCtrl,
        controller,
        deferredLogin,
        $scope,
        AuthServiceMock,
        stateMock,
        ionicPopupMock;

    // load the module for our app
    beforeEach(angular.mock.module('starter'));

    // disable template caching
    beforeEach(angular.mock.module(function($provide, $urlRouterProvider) {
        $provide.value('$ionicTemplateCache', function(){} );
        $urlRouterProvider.deferIntercept();
    }));

    // instantiate the controller and mocks for every test
    beforeEach(angular.mock.inject(function(_$controller_, $q, $rootScope) {
        deferredLogin = $q.authToken();

    $scope = $rootScope.$new();

        // mock dinnerService
        AuthServiceMock = {
            login: jasmine.createSpy('login spy')
                          .and.returnValue(deferredLogin.promise)
        };

        // mock $state
        stateMock = jasmine.createSpyObj('$state spy', ['go']);

        // mock $ionicPopup
        ionicPopupMock = jasmine.createSpyObj('$ionicPopup spy', ['alert']);

        // instantiate LoginController
        $controller = _$controller_;

    }));



    describe('login function', function() {

        // call doLogin on the controller for every test
        beforeEach(inject(function(_$rootScope_) {

            $rootScope = _$rootScope_;

            var user = {
                name: 'Boris',
                password: 'Boris'
            };

            $scope.login(user);


        }));

        it('should call login on $AuthService Service', function() {
          LoginCtrl = $controller('LoginCtrl', {
            '$scope': $scope,
            '$state': stateMock,
            '$ionicPopup': ionicPopupMock,
            '$AuthService': AuthServiceMock
          });
            console.log(LoginCtrl);
            expect(LoginCtrl).toBeDefined();
        });

        describe('when the login is executed,', function() {
            xit('if successful, should change state to inside', function() {

                deferredLogin.resolve();
                $rootScope.$digest();

                expect(stateMock.go).toHaveBeenCalledWith('inside');
            });

            xit('if unsuccessful, should show a popup', function() {

                deferredLogin.reject();
                $rootScope.$digest();

                expect(ionicPopupMock.alert).toHaveBeenCalled();
            });
        });
    });
});

Here is my Karma file settings

   files: [
  'www/lib/ionic/js/ionic.bundle.js',
  'www/js/*.js',
  'www/lib/angular-mocks/angular-mocks.js',
  'www/spec/*.js'
],

Aucun commentaire:

Enregistrer un commentaire