Greg's Blog

helping me remember what I figure out

TCIAS: Now With Continuous Delivery

| Comments

This time last year, I reworked TCIAS and my initial focus was to develop the site using a build pipeline. I opted to a few tools:

The workflow went as follows, commit to Github, let Travis CI pick up the changes, on successful build, push coverage results to Coveralls. At that point I did a little bit of manual work, reviewed Coveralls, refreshed Code Climate and reviewed the results. The final step was to run:

Cap deploy

And push the changes to my server. Life was pretty good, but I was still missing that final step, automating the deployment to my box. Fast forward a year and a colleague suggested I check out Codeship.io.

I think I spent possibly an hour getting up to speed and configuring things, basically building on the Travis CI setup and in no time I had everything continuously deploying to my server. A few gotchas:

  • figuring out coveralls integration – as sadly it’s missing from the documentation section
  • figuring out my coveralls repo token
  • rvm ruby 2.1.0 – when the deployment kicked off and my deploy script started doing it’s thing on my box, it aborted complaining about rvm not being able to use ruby 2.1.0 (for the record I use rvm and had version 2.1.1 of ruby installed). Once I installed 2.1.0 everything was fine.

I am really impressed with how simple Codeship have made things. Maybe it’s because I ironed out a lot of the kinks when setting up Travis CI, however being able to just add a cap deploy configuration to your build pipeline that can use your Capistrano configuration without any change was just delightful. I highly recommend everyone check them out. They are incredibly helpful and communicative, very impressive and I am a happy customer, with a complete continuous integration pipeline.

Backbone the TDD Way

| Comments

Or how I decided to give Leanpub a whirl and publish a book.

I am not a prolific writer or even a good writer, but I have always enjoyed writing. I have often entertained the idea of writing a book. but was put off by the slow nature of publishing, the long road to getting your content out in front of people.

I like sharing what I find and learn, and the result was this blog. A little like writing a book, without the barriers to entry and I can get my thoughts and writings out quickly.

I work in technology, love what I do and am reasonably good at what I do. I am a big proponent of Agile, I like the visibility you get from the process, the iterative approach, the fail fast nature and continuously improving your project.

Last year I read a book published by a an ex-colleague of mine, Patrick Kua. He used a Leanpub to do so and this gave me an idea.

Leanpub’s motto is “Publish Early, Publish Often”, very agile, very lean. The barrier to publishing has been lowered. Everything is coming together, so today I am happy to announce that I am writing a book.

I am going to base the book on the series of blog posts I wrote a last year on Backbone.js and Jasmine. The content for those posts is available over at Github and I intend to keep the content of this book freely available over there as well, but for those folks who find/found the content useful, I figured maybe they would also like a book version (and yes maybe make a few quid out of it). If you are interested, then why not head over the books page and sign up to get notified when it will be available.

The book aims to take you through creating a basic app, introducing you to Backbone.js and using TDD as the guiding principle. Here’s a rough list of the chapters:

  • Setup
  • Building a search interface
  • Populating a result page
  • Testing routes
  • Tying it all together
  • Migrating your code to Require.js
  • Writing functional tests

I am looking for feedback on the topic, so feel free to raise any issues over there. If you have any suggestions for other areas to be covered please let me know.

So You Want to Write Some User Journey Tests

| Comments

On past projects I have relied on WebDriver to automate and write User Journey tests. This involved using either .Net or Java, which is fine, however much to my delight I was informed that there is a JavaScript version! Here’s a brief outline on how to get started with WebDriverJS and let the good times roll!

If you have node installed then you are good to go. If not, off you go ahead and install it now (you can build it from source too if you are that way inclined).

  1. open up your favourite terminal window and install selenium webdriver using npm: npm install selenium-webdriver
  2. WebDriverJS uses Mocha as it’s test runner, so go ahead and install that next: npm install -g mocha
  3. You will also need the selenium standalone server (I suggest you put the selenium stand alone server jar in a vendor folder in your project).

That’s all the software you will need, but before we get stuck in, I like to to follow a folder structure that looks a little like this:

vendor
test
    functional
        helpers
    unit

Right let’s write some code! I’ll start off with a few helper node modules (these live in test/functional/helpers) that’ll make things a little bit more re-usable. Let’s start with a helper to start the selenium server:

var assert = require('assert'),
    fs = require('fs'),
    remote = require('selenium-webdriver/remote'),
    SELENIUM = '../vendor/selenium/selenium-server-standalone-2.32.0.jar',
    server;

exports.setUpServer = function () {
    var jar = process.env.SELENIUM;
    if(!jar) {
        jar = SELENIUM;
    }
    assert.ok(!!jar, 'SELENIUM variable not set');
    assert.ok(fs.existsSync(jar), 'The specified jar does not exist: ' + jar);
    server = new remote.SeleniumServer({ jar: jar, port: 4444 });

    server.start();

    return server;
}

And now for the WebDriver helper:

var webdriver = require('selenium-webdriver');

exports.setUpWebDriver = function(server) {
    return new webdriver.Builder().
        usingServer(server.address()).
        withCapabilities({ 'browserName': 'firefox' }).
        build();
};

exports.By = webdriver.By;

This setup assumes you have FireFox installed, as it’s the simplest browser to get started with, but you can use a bunch of different ones. Now for our test, which will go to a page and assert the value of a title is correct.

var assert = require('assert'),
    test = require('selenium-webdriver/testing'),
    serverHelper = require('./helpers/server.helper'),
    webDriverHelper = require('./helpers/webdriver.helper'),
    driver,
    server;

test.before(function () {
    server = serverHelper.setUpServer();
    driver = webDriverHelper.setUpWebDriver(server);

    driver.get('http://www.google.co.uk/');
});


test.describe('Homepage view', function () {

    test.it('should have the correct title', function () {
        driver.getTitle().then(function (title) {
            assert.equal(title, 'Google');
        });
    });
});

test.after(function () {
    driver.quit();
    server.stop();
});

This file lives in your functional test folder and let’s call it test-journey.js. It basically sets up the server and driver (i.e. starts our browser and navigates to Google), before running the simple title assertion and when done, closes the browser and server. To run this test, in your terminal window inside test/functional, type:

mocha -R list test-journey.js

Keep your fingers crossed and after a few moments FireFox should fire up and run the test. If the test passed, then your console should display something like this:

. Homepage view should have the correct title: 407ms

1 test complete (13 seconds)

Pretty straightforward, no?

jQuery Dial

| Comments

A long with some of my work colleagues we recently built a jQuery Dial/Knob UI control that we decided to open-source and share with others. We tested it against the following browsers:

  • Chrome 23
  • Opera 12.11
  • Safari 6.0.2
  • Firefox 17
  • IE6+

Check out the project page, for instructions on how to use it and a working example. Let me know about your thoughts or indeed any issues.

What Is a Closure in JavaScript?

| Comments

If we turn to Google, invariably you are led to Stackoverflow. There’s a ton of information in that post, but I am going to try and put it into my on words so that the information sticks. A closure is a function with an inner function keyword AND you return that inner function. The inner function has access to the private member variables of the outer function. Here’s an example

 function foo(x) {
   var tmp = 3;
   return function (y) {
     alert(x + y + (++tmp));
   }
 }
 var bar = foo(2); // bar is now a closure.      
 bar(10);

But what is happening here? For starters we are creating our closure by calling bar = foo(2). So bar holds a reference to our closure, i.e. we are assigning bar a reference to our inner function. Of note as well is that the inner function is being returned from the outer function before being executed.

Now we invoke bar(10) which alerts 16, because bar() can see tmp and x. When you run bar(10) again and you get a slightly different result (i.e. 17) and that is because both x and tmp are still alive and well, and since tmp was incremented by 1 we know get 17 instead of 16. Also we have effectively we have closed over the internal variables, i.e. we can’t access tmp.

In this case our inner function here is an anonymous function, it could just as easily have been written as follows:

 function foo(x) {
   var tmp = 3;
   alertSum = function (y) {
     alert(x + y + (++tmp));
   };       
   return alertSum;
 }
 var bar = foo(2); // bar is now a closure.
 bar(10);

A closure is a special kind of object that combines both a function and the environment it was created in. The ‘environment’ refers to the local variables that are in scope, when the closure was created. In the previous example from Stackoverflow, that would be tmp and x. When the closure was created the value of tmp was 3, but then you invoked bar(10) the first time it’s value was incremented to 4. Now as described we invoked bar(10) again and got 17, because tmp now had a value of 5.

This combination of data and function, resembled key Object Oriented design construct, where it differs, is that we only work with one method here, where in OO an object has data and one or more methods that interact with the objects data.

Sometimes closures are also called function factories, because you can create new functions based on the initial value passed into the closure when you created it. Consider this example from the Mozilla article:

 function makeAdder(x) {
   return function(y) {
     return x + y;
   };
 }

 var add5 = makeAdder(5);
 var add10 = makeAdder(10);

 print(add5(2));  // 7
 print(add10(2)); // 12

It’s always helpful to come up with your own example, so how about using a closure to create a dice maker? If you have ever played Dungeon and Dragons, you need a bunch of different dice to play. Now we could use a closure as a function factory to create x number of sided dice and return a roll method that we could invoke on that die:

 function dieMaker(x) {
     var sides = x;

     function getRandomInt(min, max) {
       return Math.floor(Math.random() * (max - min + 1)) + min;
     }

     roll = function() {
         return getRandomInt(1, sides);                        
     }

     return roll;
 }​;

 var sixSidedDie = dieMaker(6);
 alert(sixSidedDie());

Backbone-Jasmine - Part 4: Display Results

| Comments

Display Results

Time to display the response back to the user, to this end we’ll leverage Underscore.js built-in templating language. Our template to represent the Feed model will end up looking something like this:

<dl>
    <dt>itemId</dt>
    <dd><%= itemId %></dd>
    <dt>timestamp</dt>
    <dd><%= timestamp %></dd>
    <dt>type</dt>
    <dd><%= type %></dd>
    <dt>featOfStrength</dt>
    <dd><%= featOfStrength %></dd>
    <dt>name</dt>
    <dd><%= name %></dd>
    <dt>quantity</dt>
    <dd><%= quantity %></dd>
</dl>

We’ll use a FeedView to populate the template, so given what we know about the FeedModel and the JS template, let’s go ahead and write some tests to populate the template from the model.

describe('Feed View', function () {
    beforeEach(function() {
        loadFixtures('search-results.html');
    });

    it('should render a view item based on model values', function () {
        var feedModel = new BackboneJasmine.Feed({
                'itemId':'1',
                'timestamp':'1',
                'type': 'LOOT',
                'featOfStrength': 'Feat of Strength',
                'name': 'Name',
                'quantity': '1'
            }),
            view = new BackboneJasmine.FeedView({model:feedModel}),
            el = '';

        view.render();

        el = $(view.el).find('dl dd');

        expect($(el[0]).text()).toBe(view.model.get('itemId'));
        expect($(el[1]).text()).toBe(view.model.get('timestamp'));
        expect($(el[2]).text()).toBe(view.model.get('type'));
        expect($(el[3]).text()).toBe(view.model.get('featOfStrength'));
        expect($(el[4]).text()).toBe(view.model.get('name'));
        expect($(el[5]).text()).toBe(view.model.get('quantity'));
    });
});

To get the tests to pass we need to first create a FeedView object and it will look as follows:

var BackboneJasmine = BackboneJasmine || {};

BackboneJasmine.FeedView = Backbone.View.extend({

    tagName: 'li',
    className: 'feed',
    model: BackboneJasmine.Feed,

    render: function() {
        var variables = {
            itemId: this.model.get('itemId'),
            timestamp: this.model.get('timestamp'),
            type: this.model.get('type'),
            featOfStrength: this.model.get('featOfStrength'),
            name: this.model.get('name'),
            quantity: this.model.get('quantity')
        };

        var template = _.template($('#result-item').html(), variables);
        this.$el.html(template);
    }

});

The next step involves building out the result view, which will be bound to our collection and display multiple FeedViews. Let’s start by fleshing out the test a little to get us started

describe('Result View', function() {
    beforeEach(function() {

    });

    it('should load a fixture', function () {
        expect($('section.search-results')).toExist();
    });

    it('should display a result data', function() {

        var els = $('.search-results > ul li');
        expect($('.search-results')).not.toBeHidden();
        expect(els.length).not.toBe(0);
        expect(els.find('dl > dd').first().text()).toBe('77022');
    });
});

We can get the first test to pass easily by creating our fixture and adding it to the spec, but we’ll also need to start start pulling our result view, which will be populated with our response fixture:

beforeEach(function() {
    loadFixtures('search-results.html');
    this.response = readFixtures('feed.json');

    this.view = new BackboneJasmine.ResultView();
    this.view.collection.add(JSON.parse(this.response).feed);
    this.view.render();
});

With this in place, we can build out the ResultView object.

var BackboneJasmine = BackboneJasmine || {};

BackboneJasmine.ResultView = Backbone.View.extend({
    el: 'section.search-results',

    initialize: function() {
        _.bindAll(this, 'addFeed');

        this.collection = new BackboneJasmine.SearchCollection();
        this.$el.hide();
        this.render();
    },

    render: function() {
        this.$el.show();
        this.collection.each(this.addFeed);
    },

    addFeed: function(feed) {
        var view = new BackboneJasmine.FeedView({model: feed}),
            feedItem = view.render().el;
        this.$el.find('ul').append(feedItem);
    }

});

‘This is an idealistic view’ of syncing data between your services and your UI. Next up I’ll look at customising the collection fetch method and later on extend this to make a JSONP call.

Backbone-Jasmine: Part 3 - Search Results

| Comments

In the following we will leverage Backbone Collections and the fetch feature in order to make a call to the service, receive some JSON and build up an array of models from that response. Let’s start with creating the collection tests:

describe('Search Collection', function() {

    beforeEach(function() {
        this.collection = new BackboneJasmine.SearchCollection();
    });

    it('should initialise with an empty collection', function() {
        expect(this.collection.length).toBe(0);
    });
});

Next populating the collection with some dummy data:

describe('fetch', function() {
    beforeEach(function() {
        this.server = sinon.fakeServer.create();
        this.server.respondWith('GET', '/search', [
            200,
            {"Content-Type": "application/json"},
            this.response
        ]);
    });

    afterEach(function() {
        this.server.restore();
        this.collection.reset();
    });

    it('should populate the collection', function() {

        this.collection.fetch();
        this.server.respond();

        expect(this.server.requests.length)
            .toEqual(1);
        expect(this.server.requests[0].method)
            .toEqual("GET");
        expect(this.server.requests[0].url)
            .toEqual("/search");

        expect(this.collection.length).toBe(JSON.parse(this.response).feed.length);
    })
});

Since the API is for a character’s feed, let’s call our model Feed. The call to fetch() will go away get the JSON and magically take the data and create one feed model for each feed entry returned and store it in the collection. However because the response is wrapped within a feed object, the collection object also has a parse method to handle the response and let Backbone to work the magic described previously.

var BackboneJasmine = BackboneJasmine || {};

BackboneJasmine.SearchCollection = Backbone.Collection.extend({
    model: BackboneJasmine.Feed,
    url:'search',

    parse:function (response) {
        return response.feed;
    }
});

All the code is in the ‘Search Results branch’.

Maven Example POM File to Build With Jasmine, JSlint, SASS and YUI

| Comments

Since we seem to be repeating these steps time and again here’s an example of a POM file to run JSLint, Jasmine, SASS and YUI as part of the build Maven build process:
<build>
   <plugins>
        <plugin>
            <groupId>com.github.searls</groupId>
            <artifactId>jasmine-maven-plugin</artifactId>
            <version>1.2.0.0</version>
            <extensions>true</extensions>
            <executions>
                <execution>
                    <goals>
                        <goal>test</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <jsSrcDir>${project.basedir}/src/main/js</jsSrcDir>
                <jsTestSrcDir>${project.basedir}/src/test/js</jsTestSrcDir>
            </configuration>
        </plugin>

        <plugin>
            <groupId>org.jasig.maven</groupId>
            <artifactId>sass-maven-plugin</artifactId>
            <version>1.0.0</version>
            <executions>
                <execution>
                    <phase>generate-resources</phase>
                    <goals>
                        <goal>update-stylesheets</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <sassSourceDirectory>${project.basedir}/src/main</sassSourceDirectory>
                <baseOutputDirectory>${project.build.directory}/classes/assets/stylesheets</baseOutputDirectory>
                <sassOptions>
                    <cache_location>'${project.build.directory}/sass_cache'</cache_location>
                    <always_update>true</always_update>
                    <style>:compressed</style>
                </sassOptions>
            </configuration>
            <dependencies>
                <dependency>
                    <groupId>com.google.guava</groupId>
                    <artifactId>guava</artifactId>
                    <version>13.0.1</version>
                </dependency>
            </dependencies>
        </plugin>

        <plugin>
            <groupId>com.googlecode.jslint4java</groupId>
            <artifactId>jslint4java-maven-plugin</artifactId>
            <version>2.0.2</version>
            <executions>
                <execution>
                    <id>lint</id>
                    <phase>process-resources</phase>
                    <goals>
                        <goal>lint</goal>
                    </goals>
                    <configuration>
                        <failOnError>true</failOnError>
                        <sourceFolders>
                            <sourceFolder>${project.basedir}/src/main/js</sourceFolder>
                        </sourceFolders>
                        <options>
                            <predef>jQuery, $</predef>
                            <browser>true</browser>
                        </options>
                    </configuration>
                </execution>
            </executions>
        </plugin>

        <plugin>
            <groupId>net.alchim31.maven</groupId>
            <version>1.3.0</version>
            <artifactId>yuicompressor-maven-plugin</artifactId>
            <executions>
                <execution>
                    <phase>generate-resources</phase>
                    <goals>
                        <goal>compress</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <nosuffix>true</nosuffix>
                <preserveAllSemiColons>true</preserveAllSemiColons>
                <sourceDirectory>${project.basedir}/src/main/js/</sourceDirectory>
                <outputDirectory>${project.build.directory}/js-min/</outputDirectory>
                <excludes>
                    <exclude>**/vendor/*.js</exclude>
                </excludes>
                <aggregations>
                    <aggregation>
                        <insertNewLine>true</insertNewLine>
                        <output>${project.build.directory}/classes/assets/js/all.js</output>
                        <includes>
                            <include>${project.build.directory}/js-min/HelloWorld.js</include>
                        </includes>
                    </aggregation>
                </aggregations>
            </configuration>
        </plugin>
    </plugins>
</build>