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

Some useful articles for nodeJS, Express, Angular and MongoDb

I was reading some blog post over the last weekend and found some good article on NodeJS, Express, Angular (not angular2) and MongoDB. I think it could be helpful for others:

All this articles are published on http://adrianmejia.com/ site.

MEAN Stack 01: Preapare development enviroment

This is going to be series of article on MEAN stack. Start with setting up development environment with the following the tools

Introduction to Vagrant

Vagrant is computer software that creates and configures virtual development environments. It can be seen as a higher-level wrapper around virtualization software such as VirtualBox, VMware, KVM and Linux Containers (LXC), and around configuration management software such as Ansible, Chef, Salt, and Puppet.

Windows

  • Install Vagrant
  • Create a vagrant script named vagrantfile
    Vagrant.configure("2") do |config|
      
      // this is the box name
      config.vm.box = "ubuntu/trusty64"
      
      // provision script from a separate file
      config.vm.provision :shell, path: "bootstrap.sh"
    
      //forward the apache port to host machine with a  different port
      config.vm.network :forwarded_port, guest: 80, host: 1001
    
      //forward the nodejs port to host machine with a different port
      config.vm.network :forwarded_port, guest: 8001, host: 8001
    
      //share folder between host and guest machine
      config.vm.synced_folder "/Users/vagrant/helloworld", "/vagrant"
    end
  • Run Vagrant Machine with Ubuntu 14.04
    # vagrant up
  • Adding SSH key access to vagrant machine (using PPK file)
    • Install Putty and Putty Gen
    • To generate PPK (Putty Private key), open puttygen
    • Select import private key from the menu
    • show the path of the private key generated by vagrant, default at 
      YOUR_BOX_LOCATION\.vagrant\machines\default\virtualbox\private_key
    • Click the save private key button and save the file in the same location where the default vagrant private key located.
  • SSH to Vagrant Machine (putty, puttygen)
    • Open putty program
    • add the host name in hostbox, default is: 127.0.0.1
    • add the port number, default is: 2222
    • name the settings: testVagrant
    • for authentication, from left sidebar look for auth options and select that. left side you will see the option to browse the path of the PPK file.
    • Now click open and it will ask for login user name. Default user is: vagrant
  • Running the Vagrant from host machine
    • Install Apache Web Server using Ubuntu package manager (APT- Advanced Packaging Tool)
      # Sudo apt-get update
      # sudo apt-get install apache2
    • Forward port from guest machine to host machine using Vagrantfile configuration
  • Setup Vagrant Provisional items
    • Add Apache web server in bootstrap.sh
      #!/usr/bin/env bash
      
      # install apache2 server
      apt-get update
      apt-get install -y apache2
      if ! [ -L /var/www ]; then
        rm -rf /var/www
        ln -fs /vagrant /var/www
      fi
    • Add node package into the server
      # install node package
      apt-get install -y g++
      curl -sL https://deb.nodesource.com/setup_0.12 | sh
      apt-get install -y nodejs
      su vagrant
      mkdir /home/vagrant/node_modules
      cd /var/www/
      ln -s /home/vagrant/node_modules/ node_modules
      npm install karma
    • Create and Run First node.js server
      var http = require('http');
      var server = http.createServer(function (request, response) {
          response.writeHead(200, {"content-Type": "text/plain"});
          response.end("Hello Node World\n");
      });
      
      server.listen(8001);
      console.log('Server running at http://127.0.0.1:8001');
  • Mac
    • Install Vagrant
    • Create a vagrant script

Series:

MEAN Stack 01: Prepare development environment

MEAN Stack 02: mongoDB installation with provision and starting with mongodb

MEAN Stack 03: How to work with mongoDB

MEAN Stack 04: Start with Express framework using nodejs