X

Using Grunt: Jasmine and Phantom.js to Test your WebApp

Grunt

Sorry for not blogging for a while, have been busy with joining a new company. I wanted to finish up the blog post series with Running Grunt to test your JavaScript application.

In this post I will cover using Jasmine and Phantom.js. I have been a big fan of phantomjs a headless browser to test your web, its super fast and lightweight. In fact I did a local (Ottawa) JavaScript talk on it in 2012.

Jasmine

Jasmine is a BDD test framework for Javascript, we will be using to to test our app. Let’s get started and install jasmine to use in our express 4 application, again we will use npm or visual studio npm installer to install it.

npm install grunt-contrib-jasmine --save-dev

Jasmine npm install

Next we will write a simple JavaScript client code, let’s call it client.js script that we will perform the test on.

var AppClient = function (name) {
    this.name = name || "Taswar";
};

AppClient.prototype.setName = function (name) {
    this.name = name;
};

AppClient.prototype.getName = function () {
    return this.name;
};

AppClient.prototype.sayHi = function() {
    return this.name + ' says hi!';
};

We will now add an spec file for it to test the JavaScript client.js file we just created.

describe('The client app ', function () {
    var client;
    
    beforeEach(function () {
        client = new AppClient('Peter');
    });
    
    it("is a constructable object", function () {
        expect(typeof client).not.toBeUndefined();
    });

    it('should say hi', function () {
        expect(client.sayHi()).toEqual('Peter says hi!');
    }); 
});

The spec file is where we define our test, now that we have created the spec we can add our grunt task

module.exports = function (grunt) {
    grunt.initConfig({
        jasmine: {
            test: {
                src: 'public/javascripts/*.js',
                options: {
                    specs: 'test/*.spec.js'
                }
            }
        }    
    });
    
    // Next one would load plugins
    grunt.loadNpmTasks('grunt-contrib-jasmine');
    
    // Here is where we would define our task
    grunt.registerTask('default', ['jasmine']);
};

We can now run our grunt task using Task Runner or by command line

grunt jasmine

The output would be something like

grunt jasmine output

Now that we have Jasmine and grunt working, lets create a JQuery plugin so that we can test Jasmine with JQuery.
In order to do so we need to use bower. If you need a tutorial on bower you can look at my old post.
But first lets install bower using npm or by the npm tool in Visual Studio

npm install bower --save-dev

Bower NPM Install

Let’s now use bower to install jquery, jasmine-jquery plugin and we will save it to our dev environment.

bower install jquery jasmine-jquery --save-dev

I will reuse one of my plugin for jquery that I created that does locale sorting. The code base is small enough for us to test, since it sorts elements based on locale of the text. Lets place the file in our javascript folder so that Grunt can pick it up, lets call it localeSort.js

(function ($) {
    $.fn.localeSort = function (options) {
        var settings = $.extend({}, $.fn.localeSort.defaults, options), $this = this;
        
        return this.each(function () {
            function sorty(list, compare, elem) {
		elem = typeof elem !== 'undefined' ? elem : 'li';
				
                var listElements = list.find(elem);
                
                listElements.sort(compare);
 
                list.empty();
 
                listElements.each(function (index, li) {
                    list.append(li);
                });
            }
            
            if (settings.ul === true) {
                sorty($this, settings.compare);
            }
        });
    };
 
    $.fn.localeSort.defaults = {
        ul: true,
        compare: function localeCompareSort(a, b) {
            var t1 = $(a),
                t2 = $(b);
            return t1.text().localeCompare(t2.text());
        }
    };
}(jQuery));

We also need to let our Gruntfile to know about our “vendor” jasmine and jquery plugin, in order to run the task.

module.exports = function (grunt) {
    grunt.initConfig({
        jasmine: {
            test: {
                src: 'public/javascripts/*.js',
                options: {
                    vendor: [
                        'bower_components/jquery/dist/jquery.js',
                        'bower_components/jasmine-jquery/lib/jasmine-jquery.js'
                    ],                
                    specs: 'test/*.spec.js'
                }
            }
        }
    
    });
    
    // Next one would load plugins
    grunt.loadNpmTasks('grunt-contrib-jasmine');
    
    // Here is where we would define our task
    grunt.registerTask('default', ['jasmine']);
};

We will also create a spec file and created a folder called fixtures and placed a html file sampleSort.html in there which contains a unordered list with fruit names, please look at jsfiddle for input

jasmine.getFixtures().fixturesPath = 'test/fixtures';

describe('jquery sort plugin', function () {
    var elem;
    
    beforeEach(function () {
        loadFixtures('sampleSort.html');
        elem = $('#mylist2');
    });
    
    it('should  have French sorting', function () {
        elem.localeSort();
        var li = elem.find('li').map(function (i, el) {
            return $(el).text();
        }).get();

        
        expect(li).toEqual(['Orange', 'Poir', 'Pomme']);
    });        
});

The result of our jasmine test would show.

Jasmine Jquery Test

Summary

So this concludes our Grunt series, we have gone through the journey of using Grunt with Visual Studio, here were all the topics that were covered. Hope you enjoyed it.

  1. Using Grunt – The Javascript task runner
  2. Using Grunt – Visual Studio Grunt Launcher
  3. Using Grunt – Visual Studio 2013 Task Runner Explorer
  4. Using Grunt – Basic Tutorial
  5. Using Grunt – Copying Files
  6. Using Grunt – less and css minifcation
  7. Using Grunt – Javascript Uglify and Concat
Taswar Bhatti:
Related Post