#0022 AngularJS Unit Testing: Karma Jasmine Tutorial
Posted by Superadmin on November 10 2018 04:14:55

One of the most brilliant features of Angular.JS is the Testing aspect. When the developers at Google developed AngularJS, they kept testing in mind and made sure that the entire AngularJS framework was testable.

In AngularJS, testing is normally carried out using Karma (framework). Angular JS testing can be carried out without Karma, but the Karma framework has such a brilliant functionality for testing AngularJS code, that it makes sense to use this framework.

In this tutorial, you will learn-

Introduction & Installation of Karma framework

Karma is a testing automation tool created by the Angular JS team at Google. The first step for using Karma is to install Karma. Karma is installed via npm (which is a package manager used for easy installation of modules on a local machine).

Installation of Karma

The installation of Karma via npm is done in a two steps process.

Step 1) Execute the below line from within the command line

npm install karma karma-chrome-launcher karma-jasmine

Wherein

  1. npm is the command line utility for the node package manager used for installing custom modules on any machine.
  2. The install parameter instructs the npm command line utility that installation is required.
  3. There are 3 libraries being specified in the command line that are required to work with karma
    • karma is the core library which will be used for testing purposes.
    • karma-chrome-launcher is a separate library which enables karma commands to be recognized by the chrome browser.
    • karma-jasmine – This installs jasmine which is a dependent framework for Karma.

Step 2) The next step is to install the karma command line utility. This is required for executing karma line commands. The karma line utility will be used to initialize the karma environment for testing.

To install the command line utility execute the below line from within the command line

npm install karma-cli

wherein,

  1. karma-cli is used to install the command line interface for karma which will be used to write the karma commands in the command line interface.

Configuration of the Karma framework

The next step is to configure karma which can be done via the command

"karma –init"

After the above step is executed, karma will create a karma.conf.js file. The file will probably look like the snippet shown below

files: [
  'Your application Name'/AngularJS/AngularJS.js',
  'Your application Name'/AngularJS-mocks/AngularJS-mocks.js',
  'lib/app.js',
  'tests/*.js'
]

The above configuration files tell the karma runtime engine the following things

  1. 'Your application Name' – This will be replaced by the name of your application.
  2. 'Your application Name'/AngularJS/AngularJS.js' – This tells karma that your application depends on the core modules in AngularJS
  3. 'Your application Name'/AngularJS-mocks/AngularJS-mocks.js' – This tells karma to use the Unit Testing functionality for AngularJS from the Angular.JS-mocks.js file.
  4. All of the main application or business logic files are present in the lib folder of your application.
  5. The tests folder will contain all of the unit tests

To check if karma is working, create a file called Sample.js, put in the below code and place it in the test directory.

describe('Sample test', function() {
  it('Condition is true', function() {
    expect('AngularJS').toBe('AngularJS');
  });
});

The above code has the following aspects

  1. The describe function is used to give a description of the test. In our case, we are giving the description 'Sample test' to our test.
  2. The 'it' function is used to give a name to the test. In our case, we are giving the name of our test as 'Condition is true'. The name of the test needs to be meaningful.
  3. The combination of the 'expect' and 'toBe' keyword states on what is the expected and actual value of the test result. If the actual and expected value is the same, then the test will pass else it will fail.

When you execute the following line at the command prompt, it will execute the above test file

KARMA start

The below output is taken from the IDE Webstorm in which the above steps were carried out.

AngularJS Testing using Karma: Unit and End to End Testing

  1. The output comes in the Karma explorer within Webstorm. This window shows the execution of all tests which are defined in the karma framework.
  2. Here you can see that the description of the test executed is shown which is "Sample test."
  3. Next, you can see that the test itself which has a name of "Condition is true" is executed.
  4. Note that since all tests have the green "Ok" icon next to it which symbolizes that all tests passed.

Testing AngularJS Controllers

The karma testing framework also has the functionality to test Controllers end to end. This includes testing of the $scope object which is used within Controllers.

Let's look at an example of how we can achieve this.

In our example,

We would first need to define a controller. This controller would carry out the below-mentioned steps

  1. Create an ID variable and assign the value 5 to it.
  2. Assign the ID variable to the $scope object.

Our test will test the existence of this controller and also test to see if the ID variable of the $scope object is set to 5.

First we need to ensure the following pre-requisite is in place

  1.  
    1. Install the Angular.JS-mocks library via npm. This can be done by executing the below line in the command prompt
npm install Angular JS-mocks
  1. Next is to modify the karma.conf.js file to ensure the right files are included for the test. The below segment just shows the files part of the karma.conf.js which needs to be modified
    files: ['lib/AngularJS.js','lib/AngularJS-mocks.js','lib/index.js','test/*.js']

Below is our Angular.JS code which will be stored as a file Index.js in the test folder of our application.

The below code just does the following things

  1. Create an Angular JS module called sampleApp
  2. Create a controller called AngularJSController
  3. Create a variable called ID, give it a value of 5 and assign it to the $scope object
var sampleApp = AngularJS.module('sampleApp',[]);
sampleApp.controller('AngularJSController', function($scope) {
    $scope.ID =5;
});

Once the above code is executed successfully, the next step would be to create a Test Case to ensure the code has been written and executed properly.

The code for our test will be as shown below.

The code will be in a separate file called ControllerTest.js, which will be placed in the test folder. The below code just does the following key things

  1. beforeEach function – This function is used to load our AngularJS.JS module called 'sampleApp' before the test run. Note that this is the name of the module in an index.js file.

  2. The $controller object is created as a mockup object for the controller ''Angular JSController'' which is defined in our index.js file. In any sort of Unit Testing, a mock object represents a dummy object which will actually be used for the testing. This mock object will actually simulate the behavior of our controller.

  3. beforeEach(inject(function(_$controller_) – This is used to inject the mock object in our test so that it behaves like the actual controller.

  4. var $scope = {}; This is a mock object being created for the $scope object.

  5. var controller = $controller('AngularJSController', { $scope: $scope }); - Here we are checking for the existence of a controller named 'Angular.JSController'. In here we are also assigning all variables from our $scope object in our controller in the Index.js file to the $scope object in our test file

  6. Finally, we are comparing the $scope.ID to 5

describe('AngularJSController', function() {
    beforeEach(module('sampleApp'));

    var $controller;

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

    describe('$scope.ID', function() {
        it('Check the scope object', function() {
            var $scope = {};
            var controller = $controller('AngularJSController', { $scope: $scope });
            expect($scope.ID).toEqual(5);
        });
    });
});

The above test will run in the karma browser and give the same pass result as was shown in the previous topic.

Testing AngularJS Directives

The karma testing framework also has the functionality to test custom directives. This includes the templateURL's which are used within custom directives.

Let's look at an example of how we can achieve this.

In our example, we will first define a custom directive which does the following things

  1. Create an AngularJS module called sampleApp
  2. Create a custom directive with the name – Guru99
  3. Create a function that returns a template with a header tag which displays the text "This is AngularJS Testing."
var sampleApp = AngularJS.module('sampleApp',[]);
sampleApp.directive('Guru99', function () {
    return {
        restrict: 'E',
        replace: true,
        template: '<h1>This is AngularJS Testing</h1>'
    };
});

Once the above code is executed successfully, the next step would be to create a test case to ensure the code has been written and executed properly. The code for our test will be as shown below

 

The code will be in a separate file called DirectiveTest.js, which will be placed in the test folder. The below code just does the following key things

  1. beforeEach function – This function is used to load our Angular JS module called 'sampleApp' before the test run.

  2. The $compile service is used to compile the directive. This service is mandatory and needs to be declared so that Angular.JS can use it to compile our custom directive.

  3. The $rootscope is the primary scope of any AngularJS.JS application. We have seen the $scope object of the controller in earlier chapters. Well, the $scope object is the child object of the $rootscope object. The reason this is declared here is because we are making a change to an actual HTML tag in the DOM via our custom directive. Hence, we need to use the $rootscope service which actually listens or knows when any change happens from within an HTML document.

  4. var element = $compile("<ng-Guru99></ng-Guru99>") – This is used to check whether our directive gets injected as it should. The name of our custom directive is Guru99, and we know from our custom directives chapter that when the directive is injected in our HTML, it will be injected as '<ng-Guru99></ng-Guru99>'. Hence this statement is used to make that check.

  5. expect(element.html()).toContain("This is AngularJS Testing") – This is used to instruct the expect function that it should find the element(in our case the div tag) to contain the innerHTML text of "This is AngularJS Testing".

describe('Unit testing directives', function() {
  var $compile,
      $rootScope;
   beforeEach(module('sampleApp'));

  beforeEach(inject(function(_$compile_, _$rootScope_){
    $compile = _$compile_;
    $rootScope = _$rootScope_;
 }));

 it('Check the directive', function() {
    // Compile a piece of HTML containing the directive
    var element = $compile("<ng-Guru99></ng-Guru99>")($rootScope);
    $rootScope.$digest();
    expect(element.html()).toContain("This is AngularJS Testing");
  });
});

The above test will run in the karma browser and give the same pass result as was shown in the previous topic.

End to End Testing AngularJS JS applications

The karma testing framework along with a framework called Protractor has the functionality of testing a web application end to end.

So it's not only testing of directives and controllers, but also testing of anything else which may appear on an HTML page.

Let's look at an example of how we can achieve this.

In our example below, we are going to have an AngularJS application which creates a data table using the ng-repeat directive.

  1. We are first creating a variable called "tutorial" and assigning it some key-value pairs in one step. Each key-value pair will be used as data when displaying the table. The tutorial variable is then assigned to the scope object so that it can be accessed from our view.
  2. For each row of data in the table, we are using the ng-repeat directive. This directive goes through each key-value pair in the tutorial scope object by using the variable ptutor.
  3. Finally, we are using the <td> tag along with the key value pairs (ptutor.Name and ptutor.Description) to display the table data.
<table >
             <tr ng-repeat="ptutor in tutorial">
                   <td>{{ ptutor.Name }}</td>
	               <td>{{ ptutor.Description }}</td>
             </tr>
   </table>
</div>
  <script type="text/javascript">
      var app = AngularJS.module('DemoApp', []);
        app.controller('DemoController', function($scope) {
           $scope.tutorial =[
                {Name: "Controllers" , Description : "Controllers in action"},
                {Name: "Models" , Description : "Models and binding data"},
	            {Name: "Directives" , Description : "Flexibility of Directives"}
			]   });

Once the above code is executed successfully, the next step would be to create a test case to ensure the code has been written and executed properly. The code for our test will be as shown below

Our test is actually going to test the ng-repeat directive and ensure that it contains 3 rows of data as it should from the above example.

First we need to ensure the following pre-requisite is in place

  1. Install the protractor library via npm. This can be done by executing the below line in the command prompt

    "npm install protractor"

The code for our test will be as shown below.

The code will be in a separate file called CompleteTest.js , which will be placed in the test folder. The below code just does the following key things

  1. The browser function is provided by the protractor library and assumes that our AngularJS application (with the code shown above) is running on our site URL - http://localhost:8080/Guru99/

  2. var list=element.all(by.repeater(ptutor in tutorial')); -

    This line of code is actually fetching the ng-repeat directive which is populated by the code 'ptutor in tutorial'. The element and by.repeater are special keywords provided by the protractor library that allows us to get details of the ng-repeat directive.

  3. expect(list.count()).toEqual(3); - Lastly, we are using the expect function to see that we are indeed getting 3 items being populated in our table as a result of the ng-repeat directive.

Describe('Unit testing end to end', function() {
  beforeEach(function() {
browser.get('http://localhost:8080/Guru99/');
})
   it('Check the ng directive', function() {
      var list=element.all(by.repeater(ptutor in tutorial'));
      expect(list.count()).toEqual(3);  }); });

The above test will run in the karma browser and give the same pass result as was shown in the previous topic.

Summary