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-
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).
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
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,
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
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
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.
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
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
npm install Angular JS-mocks
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
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
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.
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.
beforeEach(inject(function(_$controller_) – This is used to inject the mock object in our test so that it behaves like the actual controller.
var $scope = {}; This is a mock object being created for the $scope object.
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
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.
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
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
beforeEach function – This function is used to load our Angular JS module called 'sampleApp' before the test run.
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.
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.
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.
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.
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.
<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
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
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/
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.
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