Sick of incurring the wrath of your team mates for pushing test-breaking code? Those days are behind you with Git hooks.

My use case: Working on front-end code breaks our Selenium based acceptance tests when I move widgets around. We make use of Gradle to run build tasks so why not run the test task before I push to origin?

Start by creating a hooks directory if there isn’t one already in your $PROJECT/.git folder.

Then in your terminal: touch pre-push.sh && chmod a+x pre-push.sh && ln -s ../../git-hooks/pre-push.sh pre-push.

You are ready to add logic to your hook. There are plenty of examples of different tasks you can run; from linting your JavaScript to removing comments or not pushing commits with ‘WIP’ in the message.

Here, is my logic for running Gradle’s test task:

#!/bin/sh
  
  git stash -q --keep-index
  
  ./gradlew test
  
  RESULT=$?
  
  git stash pop -q
  
  exit $RESULT

Voila. Git won’t push until your tests pass! You can bypass this hook if you want by using the following flag: git push origin master --no-verify

Have fun.

JavaScript Encryption and Decryption

In my previous post on JavaScript crypto we looked at uploading a file which was to be encrypted server-side then downloaded and decrypted in the browser. In this post we will tackle both encryption and decryption and also take a look at some nuances of the HTML5 File Api

Encryption

First of all we need to get a file off the file system. In our application we are making use of Fine Uploader which takes care of lots of minutiae like chunking for us. I won’t go into detail on setting up Fine Uploader as they have very good documentation.

When a file is selected (or drag-dropped) by the user I need to intercept it, encrypt it, then send it on its merry way. Here’s the interception code:

//create a key and initializationVector .. 
//this can be done by CryptoJS or your own server-side technology
//it is easy to get a file using the HTML File Api, here I'm using Fine Uploader
var file = fineuploader.getFile(someId);

var reader = new FileReader();
reader.onload = function (e) {
    var encrypted = CryptoJS.AES.encrypt(
        //convert to a word array via CryptoJS. 'this' is the file reader.
        arrayBufferToWordArray(this.result), 
        //our server generated key happens to be in Base64. 
        //We need to convert it to a word array
        CryptoJS.enc.Base64.parse(key), 
        {
            // iv was created on our server with the key 
            iv: CryptoJS.enc.Base64.parse(initializationVector) 
        });

    var blob = new Blob([encrypted], {type: file.type});
    
    //now give back to Fine Uploader to continue upload to server.
    //or you could store it locally via FileWriter
};

reader.readAsArrayBuffer(file);

We really need to call FileReader.readAsArrayBuffer as using any of the other string based variants will mess around with encoding when encrypting.

Then we just need to construct a new Blob with the encrypted result and upload it to the server (or cloud storage of choice).

Decryption

When we download from the server we need to intercept the file, decrypt the contents and then hand it off to the browser as though it is a normal file download.

Using AngularJS’s $http service:

$http({
         url: "path/to/file",
         method: "GET"
     }).then(function (response) {
         var decrypted = CryptoJS.AES.decrypt(
             response.data,
             //again .. we retrieved these from our server.. you may have them elsewhere
             CryptoJS.enc.Base64.parse(key), 
             {
                 iv: CryptoJS.enc.Base64.parse(initializationVector)
             });

         //we need to jump through a hoop or two here
         var blob = new Blob([new Uint8Array(toArrayBuffer(decrypted))], 
            {type: response.data.mimeType});
        
         var url = (window.webkitURL || window.URL).createObjectURL(blob);
         var a = document.createElement('a');
         a.download = fileResponse.data.name;
         a.href = url;

         $("body").append(a);
         a.click();
         $(a).remove();
         (window.webkitURL || window.URL).revokeObjectURL(url);
     });

There’s a few things going on here:

  1. Download the raw encrypted content via $http
  2. We need to decrypt using the same key and initialisation vector as when we encrypted
  3. We then create a new Blob where the contents are converted to a Uint8Array using CryptoJS helpers
  4. The mime type is something we determined on upload and is stored on our server.
  5. We need to generate a Url via createObjectURL
  6. Then we are relying on an anchor tag with the download attribute from HTML5. to get a seamless download experience (you may want to use Modernizr here)
  7. Click it and watch the file pop into your (supported) browser’s download list.

That’s it .. any questions please leave a comment.

This is a brief companion piece to the previous post on writing a custom directive that deals with unit testing that directive and handling isolated scope.

I already described how to set up unit tests in a previous post so we’ll just dive right in.

First we need to set up our tests using Jasmine’s beforeEach functions:

describe('sorter', function () {
    "use strict";
    var _scope, _compile, _element, _mediator;

    beforeEach(module('myApp'));
    beforeEach(module('templates'));

    beforeEach(inject(function ($rootScope, $compile, mediator) {
        _scope = $rootScope.$new({});
        _compile = $compile;
        _scope.someSortFunction = function(){};
        _mediator = mediator;
        _element = _compile("<sorter sort-by=\"name\" sort=\"someSortFunction\" column-title=\"Name\"></sorter>")(_scope);

    }));

  ...

Here I am injecting the services I need, including the custom mediator service described in the last post. Notice how I set an arbitrary function someSortFunction to the scope then configure that in the compile statement for the directive.

This shows the power of directives where you are able to isolate the scope then re-use it across applications or modules, configuring functionality appropriately.

Next we will write some tests that exercise the logic in the directive:

it("should call the configured 'sort' function on sortColumn", function(){
    var sut =  _element.isolateScope();
    var stub = sinon.stub(sut, "sort");
    sut.sortColumn();
    expect(stub.called).toBe(true);
});


...

Here we need to work with the isolated scope as opposed to the _scope variable we set up in the initialiser functions. It is obtained by calling _element.isolatedScope and this is our ‘system under test’.

We are also making use of Sinon to stub the sort function we configured earlier so we can test that it is called in our proxy sortColumn function. This is especially useful to stub functions on custom services like the mediator we injected in earlier.

That’s it!

Sorting columns on tabular data is a very common task. In this post we will walk through what it takes to write a widget that can be dropped into a table heading that is clickable and will sort the table by that column.

First let’s set up the directive:

myNamespace.app.directive("sorter", ['mediator',
        function (mediator) {
            return{
                restrict: 'E',
                replace: true,
                template : "<a href ng-click=\"sortColumn()\"> \{\{ columnTitle \}\} <i ng-class=\"orderByIcon()\" ng-show=\"showSortIcon == true\"></i></a>",
                scope : {
                    sort : "=",
                    sortBy: "@",
                    columnTitle : "@"
                },
                link: function ($scope, element, attrs) {
                       $scope.orderBy = "DESC";
                       $scope.showSortIcon = false;
                }
            };
        }]);

The directive is configured with an isolated scope so we can reuse it across multiple columns. We allow element only syntax (specified by restrict: 'E') although you are free to use attribute or class.

For brevity we have placed the template in the directive as it is a very simple HTML chunk, you could also use templateUrl if you wanted to separate your view out. The template has an anchor tag that calls a sortBy function and contains the column title and an icon that will be an arrow up or down.

Notice that there is a mediator service being injected into the directive. This is a service I wrote that wraps Angular’s $rootScope.$broadcast mechanism, which I use to communicate between decoupled controllers and directives.

The mediator includes two functions that enable subscription and notification of named events:

var SORT_SELECTED = "event:SORT_SELECTED";//lots of other events declared

...

function subscribeEvent(event, $scope, handler) {
      return $scope.$on(event, function (sender, args) {
      handler(args);
  });
}

function notifyEvent(event, object) {
    $rootScope.$broadcast(event, object);
}

...

return {
  SORT_SELECTED : SORT_SELECTED
}

We want to use this mechanism in our directive so we can broadcast to other sorters on the page that we are currently in context and the arrow icon is to be displayed on our column only

// sorter directive

mediator.subscribeEvent(mediator.SORT_SELECTED, $scope,  function(currentSort){
    $scope.showSortIcon = currentSort.sortBy === $scope.sortBy;
});

All we need to do now is to call our sorting function when the user clicks the link:

//toggles ascending / descending
function toggleOrderBy() {
    $scope.orderBy= $scope.orderBy === "ASC" ? "DESC" : "ASC";
}

$scope.sortColumn = function () {
    var currentSort = {sortBy: $scope.sortBy, orderBy: $scope.orderBy};

    //first notify other sort headers that they need to hide their arrow icon
    mediator.notifyEvent(mediator.SORT_SELECTED, currentSort);

    //call 'sort' configured on the scope
    $scope.sort(currentSort);
    toggleOrderBy();
};

$scope.sort is a function we configured in our isolated scope earlier. This is a function on any given controller that calls out to the server with filter / sort parameters and is specified when we use the directive in HTML:

<th>
    <!-- sort="sortFunction" will be a function on the holding controller -->
    <sorter sort-by="email" sort="sortFunction" column-title="Customer Email"></sorter>
<th>

Then in the controller we define the sortBy function:

$scope.sortFunction = function(params){//obviously named better :)

  //params will at this stage contain the column name and ascending or descending info
  /*
  {
      sortBy : 'email' ,
      orderBy : 'ASC'
  }
  */
  //_.extend params with other filter options here if required.
  myService.getFoobars(params)
    .then(success, error);
}

And there you have it: a reusable sort widget for any table. Full source code (and useable widget) can be found here

There are many articles and tutorials out there on AngularJS.

I am currently the sole front-end developer on a large AngularJS application and instead of trying to write yet another Angular tutorial, I thought it would be good to jot down some thoughts and findings here.

Project Layout

I am following the pattern of breaking the project structure into features as opposed to Controllers/Services/Directives etc.

-feature1
--feature1Ctrl.js
--feature1Service.js
--fooDirective.js
--fooView.html

// or for more complex features

-feature2
--controllers
---feature2FooCtrl.js
---feature2BarCtrl.js
--services
---feature2FooService.js
---feature2BarService.js
--directives
--views

//and we have a shared area for common views, services and directives

--shared
---directives
---services
---views

This way it is very easy to reason with the application, especially for any new developers.

Directives

It is very tempting to run absolutely wild with directives. My first foray into Angular territory led me to really DSL my HTML with lots of nested directives; I came to fondly (read: not fondly) refer to this as Directive Inception™. After leaving a feature for a few weeks/months then coming back, it was incredibly hard to reason with things like scoping and discoverability of code.

I have found a measure of taste is required where code can be componentised more adequately using controllers and services. Use common sense. Maintainability should be front-of-mind.

A side note: I have no problem using jQuery –with restraint– in an Angular application. A simple $("#myelement").doDomThing() is more elegant than the heavy handed doDomThingDirective.js approach, if it is a simple interaction. This is in my humblest opinion ;)

Controllers

Controllers should be written in much the same way as server side MVC controllers, in that they must follow the Single Responsibility Principle.

A controller is responsible for setting scope and handling user interactions and handing them off to a service or utility for processing. Keep controllers simple and clean.

Here is a typical controller function:

$scope.getItems = function () {
            fooService.getFooItems(/* maybe some filter parameters here */)
                .then(function (response) {
                    $scope.fooItems = response.data;
                },
                function (){
                    //handle error response
                }
                );
            };

I also like to handle promise callbacks with common functions where I can:

$scope.getItems = function () {
            fooService.getFooItems(/* maybe some filter parameters here */)
                .then(success, error); //clean .. readable.
            };

Services

I use services primarily for sending http requests. They have no knowledge of scope and are very simple and clean. A typical function looks like this;

function getFoo(id) {
    return $http({
        url: endpointUrl + '/' + id,
        method: "GET"
    });
}

return {
    getFoo : getFoo //etc...
}

I will also place feature specific business logic functions into services. I have a common utiltyService in the shared folder for common functions.

It is the responsibility of controllers and directives to receive a promise and hook into success and error callbacks appropriately.

Testing

If we have followed all the basic principles laid out above, testing should be a breeze as we have low coupling, high cohesion and separation of ‘layers’ (to facilitate stubbing).

I use Jasmine and Karma to run unit tests. Controller and service tests are very straightforward and well documented. I did run into some gotchas regarding testing directives.

First, in your Karma configuration file you will need to utilise the karma-ng-html2js-preprocessor plugin. Then you may need to intercept the cacheIdFromPath property depending on your project layout. Mine looks like this:

ngHtml2JsPreprocessor: {
  cacheIdFromPath : function(filepath) {
      var template = "../"+  filepath.split('web/').pop();//our output path
      // good idea to log here for verification
      console.log("Processing web app template: ", template)
      return template;
  },
  moduleName : 'templates' //this will be used in the tests
}

Note the assignment of the module name. This will be called in the Jasmine beforeEach functions for every test harness:

describe('my awesome tests', function () {
    "use strict";
    var _scope, _compile, _element, _q;

    beforeEach(module('myApplication'));

    //very important. This is how templates are discovered by $compile
    beforeEach(module('templates'));

    beforeEach(inject(function ($rootScope, $compile) {//inject other services
        _scope = $rootScope.$new();
        _compile = $compile;
        _element = _compile("<awesome-directive></awesome-directive>")(_scope);

    }));

    it("should do foo ", function () {
        _scope.$digest();
        _scope.myScopeItem = ['foo', 'bar'];
        _scope.$digest();
        //if you are using isolated scope in your directive:
        var actual = _element.isolateScope().testScopeItem('foo');
        //elsewise:  var actual = _scope.testScopeItem('foo');
        expect(actual).toBe('bar');
    });

});

Observe that we need to add each required module before our tests are ran; the application module of course and also the template module we specified in the Karma configuration.

Another thing to note when testing directives is to call scope.$digest at the top of each test and again when setting expectations on the scope. This simulates Angular’s digest loop and applies scope bindings.

I also make heavy use of sinon.js to mock services in directive and controller tests.

it("should call service.doFoo in important function", function(){
     var stub = sinon.stub(_fooService, "doFoo", function () {
         return _q.defer().promise;   // a good way to simulate a http call using Angular's $q service
     });

     scope.importantControllerFunction();

     expect(stub.called).toBe(true);
 });

Have fun with Angular and feel free to leave any comments