Test angular controller using Karma and Jasmine

In my last blog post, I talked about “Test angular service using Karma and Jasmine”. Today I am going to talk about “Test angular controller using Karma and Jasmine”.

Testing Controller

Lets create a controller test file users.js and do as follows:

describe("UserController", function () {
});

Let’s mock our angular module component.users using angular.mock in the following way:

describe("UserController", function () {
    beforeEach(angular.mock.module('component.users'));
});

To identify the controller users.js we need to add the dependency (inject) to our angular.mock.module in the following way: 

beforeEach(inject(function (_$controller_){
    $controller = _$controller_;
    UsersController = $controller('UsersController', {});
}));

Here we two undefined variable $controller and UsersController. Lets defined them: 

beforeEach(inject(function (_$controller_){
    var $controller, UsersController;
    $controller = _$controller_;

    UsersController = $controller('UsersController', {});
}));

Now lets start our first test case to check whether the controller is defined or not. To do so, follow this:

describe('UsersController', function () {
    var $controller, UsersController, userService;
    beforeEach(angular.mock.module('component.users'));

    beforeEach(inject(function (_$controller){
        $controller = _$controller_;

        UsersController = $controller('UsersController', {});
    }));

    it (' should be defined ', function () {
        expect(UsersController).toBeDefined();
    });
});

Now if we run the following command:

# karma start

it will display error with controller file name. To resolve this error lets create our controller file users.js:

(function (){
    'use strict';

    angular.module('component.users', []).controller('UsersController', usersController);
    usersController.$inject = []

    function usersController() {
        var vm = this;
    }

}());

This time, you will see test case passed:

Chrome 56.0.2924 (Mac OS X 10.12.0): Executed 1 of 1 SUCCESS (0.062 secs / 0.083 secs)
TOTAL: 1 SUCCESS

Testing Controller with Service Dependency

Let's add the dependency user-service.js (that we created in my last blog post) to the controller and write the test for that.

First modify users.spec.js file as follows:

describe('UsersController', function () {
    var $controller, UsersController, userService; // add this

    beforeEach(angular.mock.module('component.users'));
    beforeEach(angular.mock.module('component.users.service')); //add this

    beforeEach(inject(function (_$controller_, _UserService_) { // add this
        $controller = _$controller_;
        userService = _UserService_; // add this

        UsersController = $controller('UsersController', {'UserService': userService}); // add this
    }));

    it (' should be defined ', function () {
        expect(UsersController).toBeDefined();
    });
});

Now if you run # karma start you will see an error, like that

Error: [$injector:unpr] Unknown provider: UserServiceProvider <- UserService <- UsersController

To fix this error, modify users.js controller by adding the service dependency:

(function (){
    'use strict';

    angular.module('component.users', []).controller('UsersController', usersController);
    usersController.$inject = ['UserServic1e']

    function usersController(UserService) {
        var vm = this;
    }
}());

This time you not see any more error.
Now lets define a method userService.all() in service and try to access it in controller users.js.

Update the controller test file users.spec.js file:

describe('UsersController', function () {
    var $controller, UsersController, userService;

    beforeEach(angular.mock.module('component.users'));
    beforeEach(angular.mock.module('component.users.service'));

    beforeEach(inject(function (_$controller_, _UserService_){
        $controller = _$controller_;
        userService = _UserService_;

        UsersController = $controller('UsersController', {'UserService': userService});
    }));

    it (' should be defined ', function () {
        expect(UsersController).toBeDefined();
    });

    // add this Test Case
    it('should Initlialized with a call to UserService.all()', function (){
        expect(userService.all).toHaveBeenCalled();
    });
});

This time if you run # karma start, you will see an error like that:

screen-shot-2017-10-30-at-3-48-46-pm

To resolve this error we are going to use spyOn method of Jasmine. Click here to know more about spyOn,

describe('UsersController', function () {
    var $controller, UsersController, userService;

    beforeEach(angular.mock.module('component.users'));
    beforeEach(angular.mock.module('component.users.service'));

    beforeEach(inject(function (_$controller_, _UserService_){
        $controller = _$controller_;
        userService = _UserService_;

        spyOn(userService, 'all').and.callFake(function (){
            return [{ id: '1', name: 'Masud', role: 'Developer', location: 'CA', twitter: 'masudiiuc' }];
        });

        UsersController = $controller('UsersController', {'UserService': userService});
    }));

    it (' should be defined ', function () {
        expect(UsersController).toBeDefined();
    });

    it('should Initlialized with a call to UserService.all()', function (){
        expect(userService.all).toHaveBeenCalled();
        expect(userService.all()).toEqual(userList);
    });
});

Now if you run # karma start you will see the following error:
screen-shot-2017-10-30-at-3-57-49-pm

Let's define the method in our user-service.js file:

(function (){
    'use strict';
    angular.module('component.users.service', []).service('UserService', userService);

    function userService() {
        this.all = all;
        function all(){
            return [{ id: '1', name: 'Masud', role: 'Developer', location: 'CA', twitter: 'masudiiuc' }];
        }
    };
}());

Now if you run # karma start you will not see any error. Now add another Test Case like that:


it('should Initlialized with a call to UserService.all()', function (){ expect(userService.all).toHaveBeenCalled(); expect(userService.all()).toEqual( [{ id: '1', name: 'Masud', role: 'Developer', location: 'CA', twitter: 'masudiiuc' }] ); // add this });

That's it. Now enjoy Testing your angular application.

Help:
- Testing AngularJS with Jasmine and Karma
- Jasmine SpyOn

Continue......

If you want to explore my playground, follow this github repository: https://github.com/masudiiuc/angular-unit-test

Leave a Reply

Your email address will not be published. Required fields are marked *