Advertisement

Sunday, September 17, 2017

Adding 0% coverage in Istanbul code coverage report

In this post I am setting up a NodeJS project, it has a test project  to run automation tests, i also takes care of code coverage as well.  The project uses following frameworks:

  • NodeJS (https://github.com/nodejs)
  • Istanbul middleware (https://github.com/gotwarlost/istanbul-middleware)
  • ExpressJS  (https://expressjs.com/)
  • Protractor (https://github.com/angular/protractor)
In first step I am creating a NodeJS project:

  • Install NodeJs 
  • Go to project folder for example C:\\\
  • Open command prompt/terminal in the above location, run the following commands:   
           npm init
           npm install express
  • After the above commands running successfully, create a file named server.js, and have the following code:
   

  • In the same folder create a sub-folder named public, so in the above project we are creating a static server to serve static files like html and images. In the public folder create a HTML file named index.html. Following are the contents of index.html:





  • In the above public folder you may create a folder named src, under src folder you may have multiple sub-folders, each sub-folder may act as module, and each module may have single or multiple javascript files.
  • Before running any testcase to test the above project all the code in src folder need to be instrumented.
  • For instrumentation istanbul-instrumentor cli utility can be used. Keep the instrumented code in public-coverage folder.
  • If you notice the above index.html one of the instrumented Javascript file is used, so when any automation test case launch this html file the coverage for the particular file will be collected, however other instrumented Javascript file's coverage won't be collected. However those non-loaded file's coverage should be actually 0%.
  Let's create the test project which will run autonomous tests on the above project, basically it will load the index.html in browser, it will collect the coverage data and pushes it to istanbul coverage collector. 
  • Here Protractor is used to run autonomous tests, following is my Protractor configuration file:  
  •  Below is the content of spec.js file:
           
  

  • In the above code for staticdir's value you have to give the path where your instrumented code resides.
  • In node_modules/archiver/lib/core.js you have to modify the code to do coverage calculation for non-loaded files during tests. Following is the file's modified code.
       
  • As we have modified the core .js file the node_modules/istanbul-middleware/lib/handlers.js code has to be modified. Following is the code for handler.js
  • That's all. Now if you run your tests, whichever files not loaded during test will also be covered in the coverage report having 0% coverage for those.

Saturday, December 5, 2015

Creating Services in Angular2.0

In an application,  service is a component which consists of business logic or set of individual functions. Services often served as loosely coupled modules.

If you are building an Angular2.0 application there are various ways to inject the service into your component. Service consumption in Angular2.0 application follows dependency injection principles. Component can be resembled to directives in Angular1.x. So if you component needs a service instance, then the service can be injected while constructing the component.

For example here I am creating a component named as Event component, following is the way the component can be accessed in HTML:


<event-component></event-component>

The Angular2.0 code for the above component written below:

@Component({

    selector: 'event-component',
    templateUrl:'eventcomp.html',
    styles: [],
    directives: []

})

class EventComponent {

  constructor(VenueService:VenueService,

  @Inject('App.config')config: config,food:FoodAndBeveragesService) {

    this.title=config.title;
    this.schedule=config.schedule;
    this.duration=config.duration;
    this.venueServiceInst=VenueService;
    this.booked=false;
    this.beveragesIncluded=food.beveragesIncluded;

  }

  bookVenue(){

    if(this.venueServiceInst.bookVenue()){
      this.booked=true;
    }
  }
}

The constructor in the above code has three services injected into it.


  • VenueService
  • FoodAndBeveragesService
  • config

While bootstrap of your component you can configure services for your component, as written below:


bootstrap(EventComponent,[VenueService,FoodAndBeveragesServiceProvider,
provide('App.config', {useValue:config})]);

The VenueService code is pretty simple, following is the code:


import {Injectable} from 'angular2/angular2';
@Injectable()
export class VenueService{
  bookVenue(){
    console.log('booking venue');
    return true;
  }
}


The above service is written in a separate typescript file. So the export notifies which class you want to expose for access from other files. The Injectable annotation says that the service is injectable.

The FoodAndBeveragesService code is as simple as above service, following is the code:


import {Injectable} from 'angular2/angular2';

@Injectable()
export class FoodAndBeveragesService{

beveragesIncluded:boolean;
  constructor(beveragesIncluded?:boolean){
  this.beveragesIncluded=beveragesIncluded; 
  }

  bookFoodAndBeverages(){

    return true;
  }
}

But while injecting there is a provider configured for it, to create a provider for the service, here is the code snippet for it:

let foodAndBeveragesServiceFactory = () => {
  var beveragesIncluded=true;
  return new FoodAndBeveragesService();
};

let foodAndBeveragesServiceDefinition = {
   useFactory: foodAndBeveragesServiceFactory,
   deps:[]
};

let FoodAndBeveragesServiceProvider = provide(FoodAndBeveragesService, foodAndBeveragesServiceDefinition);
The contrasting difference between the  injection of VenueService and FoodAndBeverageService is the creation of the service instance is in the control of it's corresponding factory method, so in the above factory creation we can change the invocation of the service instance creation as shown in the following code:

let foodAndBeveragesServiceFactory = () => {
  var beveragesIncluded=true;
  return new FoodAndBeveragesService(beveragesIncluded);
};
Now lets come to config service, this is how it's been created:

let config = {

  title: 'AngularJS Meetup',

  schedule:'Mon, 23rd Dec 2015',

  duration:'6'

};
So config is basically an object which can be injected in to any component. To inject it as it's written in the bootstraping of the component:

provide('App.config', {useValue:config})
And while injecting it in the constructor of the component we mention it as follows:

@Inject('App.config')config: config

So above are the ways to create and inject services in Angular2.0. Following is the working code base of the above examples.

Saturday, November 21, 2015

Creating a video player using Angular 2.0

The best way to learn Angular2.0 is to write components. So instead of writing tutorial I prefer to start creating components. In this post we will create a video player having custom control to show the usage of Angular2.0

Typescript and SystemJS are two dependencies requires for this example.

Please install Angular2.0 as mentioned in the below link:

https://angular.io/docs/ts/latest/quickstart.html

The following plunkr contains the codebase  for the component:

The full-screen feature might not work because of browser's restriction. However once you copy the codebase to your favorite editor and run it, the full-screen feature will work smoothly. All Functionalities have been tested in Safari, Chrome and Firefox browser.

Please fell free to comment on the component so that I can extend it to have more functionalities.






Thursday, July 30, 2015

Adding pagination functionality in table using AngularJS

AngularJS (v 1.4) provides limito  filter to create a new array with specified number of elements out of existing array. It also supports from which index you want to create a new array.

you may read more about the filter from the following URL:

https://code.angularjs.org/1.4.0/docs/api/ng/filter/limitTo

Ex:

{{ sample_array | limitTo : numberofelement_perpage : startingrowno}}
where in my controller :

$scope.sample_array=["elem1","elem2","elem3","elem4","elem5","elem6","elem7","elem8","elem9","elem10"];
$scope.numberofelement_perpage=5;
$scope.startingrowno=0;
Using above filter we can create client side pagination in HTML table.


Following Plnukr shows the usage of limitito and begin to create client side pagination in HTML table.

http://plnkr.co/edit/tWFUPm?p=preview


Saturday, March 28, 2015

Sample Grunt.js file for your javascript project

Grunt is a well-known javascript task runner. To set up your project for development and production you can use grunt to automating few steps like creating css files from your LESS or SASS module, combining all your javascript files to a single one, compressing your javascript, etc.

In this post I am going to explain a sample gruntfile for javascript project, I am not covering CSS part of the project in this post.

Follow the below steps:


Create a project directory, for example learninggrunt

Navigate to learninggrunt directory in your command prompt/terminal.

Execute the following command:

npm init

The above command will ask you various question, for now just type yes in every option and leave it.

Now you will see a package.json file created in learninggrunt folder/directory.

Execute the following commands:

npm install grunt --save-dev
npm install grunt-contrib-clean --save-dev
npm install grunt-contrib-uglify --save-dev
npm install grunt-contrib-watch --save-dev
If above commands are successfully executed then create a gruntfile.js in learninggrunt directory.

The project folder structure you can create similar to this:



  
  • The 'dist' directory contains the uglified/minified/compressed javascript file along with it's map file.
  • The 'src' directory contains all your javascript source code
  • The 'lib' directory contains any library that  you are using in your current project, for example I am using AngularJS.


The content of gruntfile.js is below: 

module.exports = function(grunt) {
  grunt.initConfig({
    clean: {

      release: ["dist"]
    },
    uglify: {
      dev_target: {
        sources: {
          src: 'src/**/*.js'
        },
        options: {
          sourceMap: true
        },
        files: {
          'dist/main.js': ['lib/angular-1.3.15/angular.js', 'src/**/*.js']
        }
      },
      prod_target: {

        files: {
          'dist/main.js': ['lib/angular-1.3.15/angular.min.js', 'src/**/*.js']
        }
      }
    },
    watch: {
      files: ['<%= uglify.dev_target.sources.src %>'],
      tasks: ['uglify:dev_target']
    }
  });
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.registerTask('build_dev', ['clean', 'uglify:dev_target', 'watch']);
  grunt.registerTask('build_prod', ['clean', 'uglify:prod_target']);
};

Next you can run the build_dev or build_prod task like the below command under the learninggrunt directory:

grunt build_dev(For development release )

grunt build_prod(For production release)


After executing build_dev grunt task you will find main.js and main.js.map files:







The map file helps you to debug the javascript source code in browser.


After executing build_prod grunt task you will find only main.js file, you do not need a debugging feature in production environment.





So you can just send your 'dist' directory to production server or any module that is dependent on the feature you are developing. The main.js file contains all your javascript code which you have developed in 'src' folder along with required libraries.

Sunday, February 22, 2015

AngularJS controller in-depth

Controller in an AngularJS application plays as a role of bridge between your model and view. There are certain best practices need to be followed while designing a controller for your application.

  • REST calls should not be invoked in controller(Use Services).
  • Any filtering of the data like changing the text as browser language changes should not be done in controller(Use Filters)
  • Controllers should not be used to act as a communicator between two different AngularJS modules(Use event emitters)

Following example shows how to write a controller("Controller as" Syntax):

HTML file


<html>

  <head>
    <script data-require="angular.js@*" data-semver="1.4.0-beta.4" src="https://code.angularjs.org/1.4.0-beta.4/angular.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body>
    <div ng-app="testapp">
      <div ng-controller="utilcontroller as util">
        <input type="text" ng-model="util.name">
        <button ng-click="util.greeting()">Say Hii</button>
        <div>
          <b>{{util.nameWithGreetingMsg}}</b>
        </div>

      </div>

    </div>
  </body>

Javascript file(script.js mentioned in the HTML file)


angular.module("testapp", []).controller('utilcontroller', function() {

    this.greeting = function() {
   
    this.nameWithGreetingMsg = "Hello " + this.name;
  }
});


Constructor is a constructor function, in the above example utilcontroller  is the constructor function, so when we mention the ng-controller directive in the HTML, this constructor function get called and a new object gets created. In the above example the new object name is util.

Let's write without "controller as" syntax.

HTML file

<!DOCTYPE html>
<html>

<head>
  <script data-require="angular.js@*" data-semver="1.4.0-beta.4" src="https://code.angularjs.org/1.4.0-beta.4/angular.js"></script>
  <link rel="stylesheet" href="style.css" />
  <script src="script.js"></script>
</head>

<body>
  <div ng-app="testapp">
    <div ng-controller="utilcontroller">
      <input type="text" ng-model="name">
      <button ng-click="greeting()">Say Hii</button>
      <div>
        <b>{{nameWithGreetingMsg}}</b>
      </div>

    </div>

  </div>
</body>
</html>

Javascript file(script.js mentioned in the HTML file)


angular.module("testapp", []).controller('utilcontroller', function($scope) {

  $scope.greeting = function() {

    $scope.nameWithGreetingMsg = "Hello " + $scope.name;
  }

});

In the above program all the properties and methods are attached to $scope.


Scope Inheritance

To achieve scope inheritance controllers can be used. It's very normal while creating an HTML view we assign different controllers at different view level. so for example in the below program:

<div ng-controller="vehiclecontroller as vehicle">
  <div ng-controller="carcontroller as car">
    No of wheels: <b>{{car.wheels}}</b>
    <button ng-click="vehicle.start()">Start Car</button>
  </div>
  <div ng-controller="bikecontroller as bike">
    No of wheels: <b>{{bike.wheels}}</b>
    <button ng-click="vehicle.start()">Start Bike</button>
  </div>
</div>

We have one parent controller and two child controllers,  the child controller are able to access the parent scope's data through referring the parent controller's name(vehicle.start). The 'start' method is defined in vehiclecontroller function:

angular.module("testapp", []).controller('vehiclecontroller', function() {
  
  this.start = function() {

    console.log("vehicle started");
  }

}).controller('carcontroller', function() {
  this.wheels = 4;
}).controller('bikecontroller', function() {
  this.wheels = 2;
});

$watch in controller

$watch is AngularJS is used to observe the scope properties, once the property's value  changes the callback function defined in the $watch executes.

Inside controller we write watchers(in case of controller as syntax):

controller('carcontroller', function($scope) {
  this.wheels = 4;
  this.gear="neutral";
  $scope.$watch(angular.bind(this,function(){return this.gear}),function(newVal,oldVal){
    console.log("Gear changed from"+ oldVal+ "to "+newVal);
  });


Note: More about angular.bind.


In case of without controller as syntax the $watch is pretty simple:
 $scope.$watch('gear',function(newVal,oldVal){
    console.log("Gear changed from"+ oldVal+ "to "+newVal);
  });


That's pretty much for controller's role inAngularJS app. In the upcoming post we will learn about FormController role in an application.



Friday, December 19, 2014

Developing photo album using Flickr API in plain JS

In many top companies's machine test interview round they ask to develop a photo album using Flickr API in plain javascript without using any third party libraries like jQuery.

The following solution has below features:

1: Ability to search photos from Flickr
2: Responsive design
3: Showing only top 20 results from the above search

First create Flickr API key following steps mentioned in the below URL:

https://www.flickr.com/services/api/misc.api_keys.html


 The HTML code is below:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <script src="main.js"></script>
    <title></title>
    <link rel="stylesheet" type="text/css" href="main.css">

</head>
<body>
<div class="tools">
    <input type="text" placeholder="searchphotos" id="searchtext">
    <button title="Search Flickr photos" onclick=" exportObj.search()" style="">Search</button>
    <div class="wrap">

        <br/>
    </div>
</div>
</body>
</html>
The main.js javascript code goes below:

var exportObj = (function () {
    var exportObj = {};
    var xmlhttp;
    var jsonResponse;
    /**     * Initialize the AJAX     */    if (window.XMLHttpRequest) {
        xmlhttp = new XMLHttpRequest();
    }
    /**     * Response handler for any AJAX request     */    xmlhttp.onreadystatechange = function () {
        if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
            console.log(xmlhttp.responseText);
            var actualResponse = JSON.parse(xmlhttp.responseText);
            jsonResponse = actualResponse.photos;

            appendPhotos();
        }
    }
    /**     * It goes through the photos received as response, and append those to the wrapper div     */    function appendPhotos() {
        var src;
        var item;
        var oImg;
        var boxdiv;
        var innerbox;
        var titlebox        var wrapper = document.getElementsByClassName("wrap");
        wrapper[0].innerHTML = '';

        for (var i = 0; i < jsonResponse.photo.length; i++) {

            item = jsonResponse.photo[i];
            src = "http://farm" + item.farm + ".static.flickr.com/" + item.server + "/" + item.id + "_" + item.secret + "_m.jpg";
            oImg = document.createElement("img");
            oImg.setAttribute('src', src);
            oImg.setAttribute('alt', 'na');
            boxdiv = document.createElement("div");
            boxdiv.setAttribute("class", "box");
            innerbox = document.createElement("div");
            innerbox.setAttribute("class", "boxInner");
            titlebox = document.createElement("div");
            titlebox.innerText = item.title;
            innerbox.appendChild(oImg);
            innerbox.appendChild(titlebox);
            boxdiv.appendChild(innerbox);
            wrapper[0].appendChild(boxdiv);

        }
    }

    /**     * This is binded to search button in the view.     * When you click the search button in the UI this function get called.     * It sends a GET request to REST for fetching your serach related data     */    exportObj.search = function () {


        var apiKey = <put your Flickr API key here>;
        var searchtext = document.getElementById("searchtext");
        var searchkeyword = searchtext.value;
        var requestURL = 'https://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=' + apiKey + '&text=' + searchkeyword + '&safe_search=1&per_page=20&format=json&nojsoncallback=?';
        xmlhttp.open("GET", requestURL, true);
        xmlhttp.send();
    }
    return exportObj;

}());
The main.css  stylesheet  code goes below:

body {
    margin: 0;
    padding: 0;
    background: #EEE;
    font: 10px/13px 'Lucida Sans',sans-serif;
}

.wrap {
    overflow: hidden;
    margin: 70px;
}


.box {
    float: left;
    position: relative;
    width: 20%;
    padding-bottom: 20%;
}
.boxInner {
    position: absolute;
    left: 10px;
    right: 10px;
    top: 10px;
    bottom: 10px;
    overflow: hidden;
}
.boxInner img {
    width: 100%;
    display:block;
}
.boxInner:hover img {
    -webkit-transform:scale(1.75); /* Safari and Chrome */    -moz-transform:scale(1.25); /* Firefox */    -ms-transform:scale(1.25); /* IE 9 */    -o-transform:scale(1.25); /* Opera */    transform:scale(1.25);
}

@media only screen and (max-width : 480px) {
    /* Smartphone view: 1 tile */    .box {
        width: 100%;
        padding-bottom: 100%;
    }
}
@media only screen and (max-width : 650px) and (min-width : 481px) {
    /* Tablet view: 2 tiles */    .box {
        width: 50%;
        padding-bottom: 50%;
    }
}
@media only screen and (max-width : 1050px) and (min-width : 651px) {
    /* Small desktop / ipad view: 3 tiles */    .box {
        width: 33.3%;
        padding-bottom: 33.3%;
    }
}
@media only screen and (max-width : 1290px) and (min-width : 1051px) {
    /* Medium desktop: 4 tiles */    .box {
        width: 25%;
        padding-bottom: 25%;
    }
}