Close

March 23, 2016

Setting up for AngularJS Unit testing

Seeing as there are already TONS of material about this subject, I am going to put it down so that I contribute to the information overload 😛 . Normally, when you start a project with AngularJS, you already have a clue of the libraries and the structures, ie directives, controllers, modules, filters and services in it, if not, well, there is some reading to be done.

You will also, most probably, have some sort of build tool in your arsenal, Grunt or Gulp or …… (fill in with your thing). Seeing as I am the most familiar with Grunt, that is what I will be using in this setup. As a testing framework we will be using Jasmine and Karma as the test runner. For this insane amount of tests that we will be doing, I think that a simple contact manager with the browsers’ localstorage as the persistence layer.

Project Structures

I really like John Papas style guide and way of naming the things, especially for larger systems, and, even though this is a simple small system, I believe that to still follow it is good practice. The folder structure:

/src

Grunt-ing karma.

to start, we need to install a few packages that will be required. I will not be using the concat files and copy and all those grunt plugins as they can be used too, but not in the scope of this article.

npm init

this will initialize the package.json so we can keep track of the packages we install

npm install -g grunt-cli

this will install the Grunt command line interface globally

npm install grunt --save-dev
npm install grunt-contrib-jshint --save-dev
npm install grunt-contrib-watch --save-dev

npm install grunt-karma --save-dev
npm install karma-chrome-launcher --save-dev
npm install karma-jasmine --save-dev

npm install karma --save-dev

npm install stuff

Getting the libraries

Next we install the libraries that we will be using, just the basic ones. To get started, we need to run the bower init command to get the needed bower.json file.

bower init

Then it is just simple install –save

bower install angularjs --save
bower install angular-route --save
bower install angular-resource --save

And this is required for us to do unit testing

bower install angular-mocks --save-dev

Next we have the gruntfile.js

module.exports = function(grunt) {

    grunt.initConfig({
        karma: {
            unit: {
                background: true,
                options: {
                    basePath: '',

                    frameworks: ['jasmine'],
                    browsers: ['Chrome'],

                    //background : true,
                    customLaunchers: {
                        Chrome_without_security: {
                            base: 'Chrome',
                            flags: ['--disable-web-security']
                        }
                    },
                    files: [
                        "bower_components/jquery/dist/jquery.js",
                        "bower_components/bootstrap/dist/bootstrap.js",
                        "bower_components/angular/angular.js",
                        "bower_components/angular-route/angular-route.js",
                        "bower_components/angular-mocks/angular-mocks.js",
                        "src/**/*.tpl.html",
                        "src/**/modules.*.js",
                        "src/**/controller.*.js",
                        "src/app.js",
                        "src/**/*-spec.js"
                    ],
                    exclude: [],

                    coverageReporter: {
                        type: 'html',
                        dir: 'coverage/'
                    },

                    // test results reporter to use
                    // possible values: 'dots', 'progress'
                    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
                    reporters: ['progress' ],

                    colors: true,
                    singlerun: false,
                    autoWatch: false,
                    logLevel: 'ERROR',

                    plugins: [
                        'karma-jasmine',
                        'karma-chrome-launcher',
                    ],

                }
            },
        },


        jshint: {
            files: ['gruntfile.js', 'src/**/*.js'],
            options: {
                globals: {
                    jQuery: true
                }
            }
        },
        watch: {
            files: ['<%= jshint.files %>'],
            tasks: ['jshint', 'karma:unit:run']
        }
    });

    grunt.loadNpmTasks('grunt-karma');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-watch');

    grunt.registerTask('default', ['karma:unit', 'watch']);

};

We have the karma config setup in the grunt file so we don’t need a karma.conf.js file apart from the grunt file.

Getting up with default view

Next up we need to get all the libraries installed we need, bower is AWESOME for this.

bower install --save angular

bower install --save angular-routes

bower install --save bootstrap

bower install --save-dev angular-mocks

Bootstrap is just so we can get some nice look with out tons of custom styling.

below is the index.html file as it should be.

<!DOCTYPE html ng-app="contactor">
<html>

<head>
    <title>Contactor</title>
    <link rel="stylesheet" type="text/css" href="../bower_components/bootstrap/dist/css/bootstrap.css">
</head>

<body>

<div class="container" ng-view>
    </div>

    <script src="../bower_components/jquery/dist/jquery.js"></script>
    <script src="../bower_components/bootstrap/dist/js/bootstrap.js"></script>
    <script src="../bower_components/angular/angular.js"></script>
    <script src="../bower_components/angular-route/angular-route.js"></script>
    <script src="../bower_components/angular-resource/angular-resource.js"></script>
</body>

</html>

We include the files manually, although Grunt has a nice templating features to include them as you add them.

Our App starts

Seeing as we are trying to get into TDD with AngularJS, lets do this a bit backwards, just to get the hang of this.

To get us up and running, lets display a list of contacts, thus, we create a contacts module and include it into our main app.js file.

We create the contacts folder, and in it, we create 3 files, one for the module, one for the controller and one being the template.

(function() {
    'use strict';

    angular
        .module('contacts', [
            'ngRoute'
        ]);

    angular.module('contacts')
    .config(function($routeProvider){
    	$routeProvider.when('/contacts', {
    		templateUrl: 'contacts/contactlist.tpl.html',
    		controller: 'ContactListController'
    	});
    });
})();
(function() {
    'use strict';

    angular
        .module('contacts')
        .controller('ContactListController', ['$scope', ContactListController]);

    /* @ngInject */
    function ContactListController($scope) {
        /*jshint validthis: true */
        var self = this;

        /* Interface */
        self.Title = 'ContactListController';

        init();

        /* Implementation */
        function init() {
        }

        /* End Implementation */
    }
})();

Remember to add these files to the to the index.html file

In the follow-up I will start doing the tests and showing what is the difference between a coverage test and a valuable test.

Leave a Reply

Your email address will not be published. Required fields are marked *