PU$]-[KAR's

… Every drop has ability to survive .


Leave a comment

Jasmine unit test for ‘Directive’

Hey,

Today, we will go through unit tests for directive using ‘Jasmine’. We have to keep one thing in mind that Jasmine unit test is not ‘E2E’ testing framework. So we have to test our application module wise i.e. testing directives and services, controllers separately. To begin jasmine tests for directive we will consider a simple and very famous directive- ‘custom validation directive’.

Directive code:

var INTEGER_REGEXP = /^\-?\d*$/;
app.directive('integer', function() {
return {
require: 'ngModel',
link: function(scope, elm, attrs, ctrl) {
ctrl.$parsers.unshift(function(viewValue) {
if (INTEGER_REGEXP.test(viewValue)) {
ctrl.$setValidity('integer', true);
return viewValue;
} else {
ctrl.$setValidity('integer', false);
return undefined;
}});}};});

This directive is simply responsible to check weather input is of type integer or not.

To test this directive we have to use a bit different technique that the previous. First we have to create a html on the fly which consumes this directive and then we have to assign the input value to this html. Once the value gets assigned, this custom validation will get fired.

The following code will describe the unit testing for this directive.

Unit test:

describe('directives', function() {
var $scope, form;
beforeEach(module('testDirective'));
beforeEach(inject(function($compile, $rootScope) {
$scope = $rootScope;
var element = angular.element("< form name="form">< input ng-model="model.integerInput" name="integerInput" integer />' +'</form>");
$scope.model = { integerInput: null }
$compile(element)($scope);
form = $scope.form;
}));
describe('integer', function() {
it('should pass with integer', function() {
form.integerInput.$setViewValue('3');
$scope.$digest();
expect($scope.model.integerInput).toEqual('3');
expect(form.integerInput.$valid).toBe(true);
});
it('should not pass with string', function() {
form.integerInput.$setViewValue('a');
$scope.$digest();
expect($scope.model.integerInput).toBeUndefined();
expect(form.integerInput.$valid).toBe(false);
}); });});

Explaination:

As discussed earlier, here is one important thing to note that while creating unit test we have created a html on the fly which consumes our directive. So to convert this html string to ‘DOM’ we used $comiple().
Keep it in mind that we have warped ‘input’ control inside ‘form’ element because angularJS does not fire the validation until and unless form gets dirty so it is recommended that we should wrap it inside ‘form’.
‘$setViewValue’ is used to set the value to input control. Please don’t use DOM manipulation to set value to the input control. The reason behind this is by setting this value using ‘DOM’ handling ‘form’ will never come to know that something has been changed on the ‘form’ so eventually form will not be considered as ‘dirty’ and validation will not get fired and test will get failed. So proper way to use ‘$setViewValue’.
Finally trigger the digest cycle to let the test know the run-time changes.

And now test is set ready to ‘Go Green’…

Advertisements


Leave a comment

Restangular Service with Jasmine unit test

Wel-Comeback

Unit testing AngularJS service with Restangular is one of the common coding issue and that too with testing inside the ‘promises’ as well. So today we will look at how to write and test a service inside ‘promise’ using Jasmine unit test framework. We will go with the example given below.

Specifically we are looking at a service which is returning a data from a .json file instead of hitting http url.

//defining a module with factory
angular.module('SampleTest').factory('TestFactory',TestFactory);
Function TestFactory(Restangular,ObjectRepositaory){
// creatinga samplefunction
return{sampleFunction:function(){
//setting URL for retangular to call API
var restangular = Restangular.withConfig(function (configurer){configurer.setBaseUrl('mockData/data'); configurer.setRequestSuffix('.json')});
return Restangular.all('dataFile').getList().then(function (response){
//inside promise
ObjectRepositaory = response;
}}}

Description:

So we have created ‘sampleFunction’ inside a factory named ‘TestFactory’. So basically in this function we are fetching a data resided in ‘dataFile.json’ and once the service returns ‘success’ we are storing this data in to an repository called ‘ObjectRepositaory’.

Now we  will test this function using a ‘Jasmine’ framework. So as discussed earlier to begin with unit test we will create ‘describe’ block as test suit which will have necessary injections in ‘beforeEach’ function and followed with ‘it’ the actual test case.

So have a look at a test case written below.
describe('Test', function(){ var httpBackend, Restangular;
beforeEach(function() {module('SampleTest');});
beforeEach(inject(function( _Restangular_, _$httpBackend_) {
httpBackend = _$httpBackend_;
Restangular = _Restangular_;
}));
describe('Test result', function(){
it('A description of what should the method do', inject(function(TestFactory,ObjectRepositaory){ spyOn(Restangular, 'all').andCallThrough();
// a mock to be returned from http
var dummyResponse = [{id:1,name:'ABC'}];
//This whenGET is used in case of json mocked service
httpBackend.whenGET(URL).respond(dummyResponse);
//This whenGET is used in case of actual http url
//httpBackend.expectGET(URL).respond(dummyResponse);
TestFactory.sampleFunction();
// important to flush the backend to unproxy the restangular promise
httpBackend.flush();
// expect the objectRepositary has a result
expect(ObjectRepositaory.length).toEqual(1);
}));
});
});

Explanation:

So, As you observed we have injected ‘Restangular’, ‘$httpBackend. Here we are using ‘httpBackend’ for mocking a service. We have mocked response as ‘dummyResponse’ which is eventually going to be returned by a fake service call.
In above code you will see the use of ‘httpBackend.whenGET’ instead of ‘httpBackend.expectGET’ because it actually a difference ‘Request Expectation’ vs ‘Backend Defination’. We are using a json file data instated of actually calling a ‘http’ url which acts as backend for our application which doesn’t assert if a particular request was made or not, it just returns a trained response if a request is made. Even remember that due to not this we can’t check a service has been called or not using ‘toHaveBeenCalled’ (in case of using whenGET).

If we had used http url instead of .json then we might have used httpBackend.expectGET. The following link will explain httpBackend in more details. Click here
The most important thing is to use httpBackend.flush as described in code section.Only after the execution of flush() control goes inside the ‘susses promise’ and that is what we were looking for. Now each and every line inside a code is available for the tests. 🙂
Final assertion is doing exactly the same. Based on the service implementation what ever the response is returned by a service has to be copied in the repository object. So as per our test is considered as we mocked response with single item so the length of ‘ObjectRepositaory’ equals to one.

And that’s all my friends…


Leave a comment

Jasmine unit test for ‘controllers’

Welcome back guys,

As we have seen integration of ‘Jasmine’ and ‘karma’ with webstorm.Today, we will continue with the writing a JS unit test for a controller using ‘Jasmine’ & ‘karma’.
We will have an example of a simple. This controller is just a responsible for addition of the two numbers.
app.controller('addCtrl', function($scope, $location) {
console.log('add operation');
$scope.add=function(num1,num2)
{
$scope.result=parseInt(num1)+parseInt(num2);}});

In short controller ‘addCtrl’ contains a function ‘add’ which is returning a result of addition on two numbers: num1 & num2.Now we are going to write a JS test for the function.
Before begin with this first we need to add those dependent files in ‘karam.conf.js’ file under the ‘files’ section. Remember we have configured this file while initiating karma with few wizard steps. For reference click here. So as you can see below I have added few files along with ‘addCtrlSpec.js’. This file is going to contain tests for this controller.
files: [
'app/lib/angular.js',
'app/lib/angular-mocks.js',
'app/Controllers/additionController.js',
'TestFiles/addCtrlSpec.js',
],

Now following code snippet shows the actual code fore writing a spec.
describe('Test Addition', function ()
{ beforeEach(module('myApp'));
describe('myAppAddCtrlTest', function ()
{ it('Check Addtion test', inject(function ($controller)
{ var scope = {},
ctrl = $controller('addCtrl', {$scope: scope});
scope.add(4,5);
expect(scope.result).toBe(9); })); });

Explanation:

In this spec ‘describe’ is representing a test suit which can have multiple tests inside it. Whereas ‘beforeEach’ is the block which gets executed before ‘inner describe’. We can have ‘beforeEach’ even inside ‘inner describe’ or even inside ‘it’ as well but scope of that will be limited to that particular section only. Basically ‘beforeEach’ is used for injecting few modules or dependencies, mocking the data,carrying out specific action or initiating few variables etc. ‘it’ represents actual test. ‘it’ may contains more than one ‘expect’ statements. These expect statements are to check the result like checking the values of variable or method has been called or not. There are lots of options are available for these ‘expect’ statements.
So while looking at the code you can sense that,

  1. ‘Test Addition’ is my main test suit.
  2. Inside ‘beforeEach’ I have injected ‘myApp’ which is my main module of my application which contains all the controllers of my application. This ‘beforeEach’ will get executed every ‘inner descibe’ say ‘myAppAddCtrlTest’.
  3. it: ‘check addition test’ is the actual test. You can see that inside this ‘it’ I have injected a controller ‘addCtrl’ (along with the scope) which needs to be tested. And finally I called ‘add’ method using ‘scope’ and passed 4 & 5 as a dummy data to check weather this method is returning correct value or not.

Now this test is ready to run. In ‘karma’ we can’t run the individual test so to run the tests we need to start ‘karma’ first & then need to run tests. So to run that we can go to file ‘karma.conf.js’ file in project structure and write click in that and say run and will see the ‘karma’ has been stared in default browser and test is running green.

So in further posts we will discuss with directives and services too.

Till then bye!!!


2 Comments

Integration of ‘Jasmine’ with ‘Webstorm’

Hey guys,

It’s time to have some hands-on with unit testing !!!

Unit testing is one of the key features while developing any application weather it would be a server side code or client side and ‘Jasmine’ is one of the leading framework to test an angularJS application.So today we will walk through integrating ‘Jasmine’ with ‘WebStorm’.Of course, we should have ‘node.js’ installed on our machine that’s the prerequisite thing for this as you know. So basically to run specs(i.e. jasmine tests) we are going to use ‘karma’ as ‘test runner’ & ‘jasmine’ as test framework.

So majorly this integration will fall in two steps:

  1. Initialization of ‘karma’.
  2. Adding ‘jasmine’ intellisense.

Initializing ‘karma ’ with ‘jasmine’ framework.

  • Install ‘karma’ inside webstorm project with command on terminal ‘npm install –g karma’ which installs the ‘karma’ for our application even we might go for installing karma globally using command prompt.
  • To initialize ‘karma’ enter command ‘karma init’ on terminal. This command will initialize the karma and will be followed with certain questions to configure ‘karma.conf.js’. basically this file will be set through the option which we are going to set while initializing ‘karma’.
  • So using this configuration option we can adopt different Test frameworks like ‘Jasmine’, ‘mocha’ etc. so we are going through ‘Jasmine’ configuration. As I said earlier ‘karma ’ is a test runner & ‘Jasmine’ is a test framework.
  • So to configure this we will chose ‘jasmine’ framework. Then ‘no’ to Rquire.js. Then chose the suitable browser say ‘firefox’ then As we want that ‘ webstorm’ has to look after change in any tests so select ‘no’ to the question ‘Do you want Karma to watch all the files and run the tests on change ?’

So this will set our basic configuration.

And now it’s time to add few things in favor of developer’s favor – Intellisense.

‘Jasmine’ framework intellisense:

As with default options ‘webstorm ’ is not going to provide any auto complete facility for jasmine so we do some settings to make it possible. For that we need to add java script library to have that through settings of webstorm and need to include in current project.

To that please follow following steps:

  • In WebStorm, open the Settings dialog (File > Settings).
  • Under language & settings, navigate to JavaScript > Libraries.
  • Click the Download button on the right side. This opens the Download Library dialog.
  • Select “TypeScript community stubs” from the combo box.
  • Find the library ‘jasmine’, select it and click Download and Install.
  • After installing it makes sure that check box should be selected.

And now we are ready to go on writing specs……..

In next post even I will be going to share one easy sample for creating specs.


4 Comments

Re selecting same date in datepicker … from boot strap.

Once again datepicker comes in to action …

Guys, one the key issues with ‘datepicker’ is re selecting the same date in bootstrap datepicker control. Let’s consider a scenario that user has already selected a date say 1st Aug. 2014 so of course that date will get highlighted and now by mistake is again selecting a same date, in that case date say 1st Aug. 2014 (which is already selected) will gets deselect. And of-course multi-date selecting is false. So this is very odd behavior of user some times (specially in case where selecting a same date is not a functionality to deselect it.)

You can see this issue on

click here

So to resolve this issue we need to understand how datepicker runs behind the seen i.e. ‘bootstrap-datepicker’ js file.

Below code is a snap shot from datepicker bootstrap.js file


_toggle_multidate: function(date){
var ix = this.dates.contains(date);
if (!date){
this.dates.clear();
}
else if (ix !== -1){
this.dates.remove(ix);
}
else {
this.dates.push(date);
}
if (typeof this.o.multidate === 'number')
while (this.dates.length > this.o.multidate)
this.dates.remove(0);},

Analysis of existing code:

As shown in above code variable ‘ix’ holds index number (from an array of selected dates i.e. ‘this.dates’) if it founds duplicate date and if ‘ix’ holds value other than -1 then it shows that the selected date is duplicate one i.e. it already has been selected. So it removes that date from an array ‘this.dates’ so it won’t be able to select i.e. highlight it on UI.
So this is the section that we need to look at.

Solution:

To avoid such problem we can create a property as ‘multidateRemoveDuplicate’ which will be deciding factor to select of deselect duplicate date because user come across scenarios such as
1. If user re select already selected date it should get deselect
2. The selected date gets deselect only in case when some different date is selected.
(of course multi date selection is blocked in both cases).

So if the value of ‘multidateRemoveDuplicate’ is set to true then it will removes already selected date and if it is false then it wont.

Modified code:

To create ‘multidateRemoveDuplicate’ property we need to add following code in bootstrap-datepicker.js file.

1. The following code will assign default value to ‘multidateRemoveDuplicate’ as false.

var defaults = $.fn.datepicker.defaults = {
autoclose: false,
beforeShowDay: $.noop,
calendarWeeks: false,
clearBtn: false,
daysOfWeekDisabled: [],
endDate: Infinity,
forceParse: true,
format: 'mm/dd/yyyy',
keyboardNavigation: true,
language: 'en',
minViewMode: 0,
multidate: false,
multidateRemoveDuplicate: false,
multidateSeparator: ',',
orientation: "auto",
rtl: false,
startDate: -Infinity,
startView: 0,
todayBtn: false,
todayHighlight: false,
weekStart: 0
};

2. The following code need to add along with other set properties which are already exist and it is to set a value to property ‘multidateRemoveDuplicate’ (setter method)

setMultidateRemoveDuplicate: function (multidateRemoveDuplicate) {
this._process_options({ multidateRemoveDuplicate: multidateRemoveDuplicate });
this.update();
this.updateNavArrows();
},

3. The following code is to  default call set property of ‘multidateRemoveDuplicate’ i.e. ‘setMultidateRemoveDuplicate’ with ther set properties which are already exist.

var Datepicker = function(element, options){
.
.
this.setStartDate(this._o.startDate);
this.setEndDate(this._o.endDate);
this.setDaysOfWeekDisabled(this.o.daysOfWeekDisabled);
this.setMultidateRemoveDuplicate(this.o.multidateRemoveDuplicate);
this.fillDow();
this.fillMonths(); ...

Now we have to modify a code for _toggle_multidate function as given below.
The date will get removed from an array of dates based on the value assigned to ‘multidateRemoveDuplicate’

_toggle_multidate: function(date){
var ix = this.dates.contains(date);
if (!date){
this.dates.clear();
}
else if (ix !== -1){ if (this.o.multidateRemoveDuplicate) {
this.dates.remove(ix);} }
else {this.dates.push(date);}
if (typeof this.o.multidate === 'number')
while (this.dates.length > this.o.multidate)
this.dates.remove(0);},

And we can assign a value from our code based on the user requirement weather user re select already selected date it should get deselect or the selected date gets deselect only in case when some different date is selected.

That’s all my friends. Have a nice day!!! ….

🙂


Leave a comment

Writing a Directive ….. link or controller ?

Hey Guys,

As we know ‘Directive’ is a key for building an angularJS application. Its nothing without ‘Directives’. So here we can have a quick look at how to write a directive more on that what to use ‘link’ or ‘controller’? Otherwise confusion in choosing ‘link’ or ‘controller’ … then ‘Directive’ is just like a ‘Black-Box’.

So what is difference between ‘link’ & ‘controller’?

To understand this first we need to understand compilation process for directive. Consider a small application with nested directive. say ‘parent’ is a container and it has ‘Directive1’ which contains ‘ChildDirective’. So if we go through AngularJS doc. The sequence is as per following.
1. Parent container will get compile.
2. Directive1 will get compile.
3. ChildDirective will get compile.
4. Parent controller will get invoked
5. Parent Pre-link invoked.
6. Directive1 controller will get invoked.
7. Directive1 Pre-link invoked.
8. ChildDirective controller will get invoked.
9. ChildDirective Pre-link invoked.
10. ChildDirective Post-link invoked.
11. Directive1 Post-link invoked.
12. Parent container Post-link invoked.

So if you observed here order of invoking of ‘Post-Link’ is reversed and it is exactly what we were looking for. A ‘link’ function inside directive acts at ‘post-link’. where as ‘pre-link’ is rarely used. It means all child directives link functions get executed before the parent functions link functions.

So now consider a scenario where ‘Directive1’ want to have DOM manipulation of any element from ‘ChildDirective’

Now if we tried to have such ‘DOM’ manipulation inside ‘controller’ of ‘Direcive1’ it won’t be carried out because controller of ‘Directive1’ will get executed first than ‘post-link’ of ‘ChildDirective’.

So In such cases if we handle DOM manipulation inside ‘link’ of ‘Directive1’ then it will get executed. So over all its adivisable to have DOM manipulation inside ‘link’ function.

So Where we can use controller?
Stuff like using one directives controller in another i.e. assigning value in parent Directive (can be done in controller) and accessing it in child one can be done using controller. Because if you remember controller is acts like constructor more or less. So assigning default value is the main purpose of controller.

In short:

We can have a one quick question to our self weather we want it before compile or after compile. as controller as acts as constructor we can judge that whatever we can have before compile we can make it in ‘controller’ and things like ‘DOM’ manipulation which needs to complete compilation process can be carried out in ‘link’


Leave a comment

Introduction to AngularJS service

As we know angularJS is one of the leading framework now a days, the reason is it can used across the platforms even provides stability across the devices as well. It means it is compatible for application to run on laptops, desktop, smartphone & tabs. & for that separation of concern is at the heart while designing an AngularJS application. So to maintain this modularity i.e. separation angularJS has proposed two designs.

  1. Service
  2. Factory

Because while writing code controller must be responsible for binding model data to views using $scope. It does not contain logic to fetch the data or manipulating it. Not anything about business logic should be in controller.

Brief about AngularJS service:

As documented Angular services are substitutable objects that are wired together using dependency injection (DI). You can use services to organize and share code across your app.
Thus service is a stateless object that contains some useful functions. These functions can be called from anywhere; Controllers, Directive, Filters etc. So it increases modularity and reusability too.

So what are key advantages of putting a business logic in services?

  1. It fulfills the principle of separation of concern or segregation of duties. Each component is responsible for its own work making application more manageable
  2. This is the way by which each component can be more testable. AngularJS provides first class support for unit testing. Thus we can quickly write tests for our services making them robust and less error prone. For writing unit tests cases we can use Jasmine framework too.
  3. Increases reusability and modularity so that it reduces code maintainability efforts.

In angularJS there are two types of service that we can use.

  1. Internal Services: AngularJS provides few services like $location, $windows, $http that we can use as it is in our controller using dependency injection.
  2. Custom Services: This means we can write our own service in angularJs and we can use them via dependency injection.

Example of custom service:

If you see below I have created a sample service for addition of number.
app.service('MathSampleService', function() {
this.add = function(a, b) { return a + b };});

And this service is injected in controller to use that business logic.
app.controller('CalculatorController', function($scope, MathSampleService) {
$scope.doAdd = function() {
$scope.answer = MathSampleService.add($scope.number1,$scope.number2);}});

But keep it in mind while injecting service in controller name of service should be exact.

This is very simple and basic example.In real life scenario even we can inject one service into another service too.So If you observe our overall business logic remains inside a service and controller is just responsible for binding data to UI nothing else than that.

For Complete demo please look at the following link:

click here