Archive

Posts Tagged ‘javascript’

JavaScript as a First Class Language

December 8th, 2011

A couple of weeks ago I presented at the internal ThoughtWorks conference called XConf about how we have been treating JavaScript as a First Class Language recently on our current project. What it means to us is:

  • Modularise JS code (JAWR helps)
  • Unit test it. (we use Jasmine and JSTestDriver)
  • Static analysis, “checkstyle for JS”. (we use JSHint)
  • JS Dependency Injection to facilitate testing

Here are the slides with more info and some code samples.

Technical , ,

Testing Ajax with WebDriver – Make your tests deterministic

August 24th, 2011

We had some non-deterministic tests on our project so we decided to implement a generic way to test ajax calls using webdriver. I was quite impressed with how quickly we achieved this, mainly due to the fact that javascript is dynamic and functional. And also thanks to my js learning sessions with Romain, who is also responsible for a great majority of the js code below :)

Here’s the code, split into well defined components as we’ve been treating javascript as a first class language. It has also been unit tested, but I’ll save that for another post.

Http

A wrapper around jquery ajax

var Async = Async || {};
Async.Http = function() {

    function get(url, data, successHandler, errorHandler) {
        $.ajax({
            url: url,
            data: data,
            dataType: 'json',
            contentType: 'application/json; charset=utf-8',
            async: false,
            success: successHandler,
            error: errorHandler
        });
    }

    function post(url, data, successHandler, errorHandler) {
        $.ajax({
            type: 'POST',
            url: url,
            data: JSON.stringify(data),
            dataType: 'json',
            contentType: 'application/json; charset=utf-8',
            success: successHandler,
            error: errorHandler
        });
    }

    return {
        get: get,
        post: post
    };

};

Notifier

A stateful js component that keeps track of all the ajax calls and adds a div to the dom with that information.

var Async = Async || {};
Async.Notifier = function() {

    var $notifierElement = $('<div id="asyncNotifier" class="done">');
    $('body').append($notifierElement);    

    var inProgress = 0;

    function start() {
        ++inProgress;
        $notifierElement.removeClass('done');
    }

    function finished() {
        --inProgress;
        if (inProgress === 0) {
            $notifierElement.addClass('done');
        }
    }

    return {
        start: start,
        finished: finished
    };

};

HttpAsyncDecorated

A decorated version of Async.Http that uses Notifier.

var Async = Async || {};
Async.HttpAsyncDecorated = function(http, asyncNotifier) {

    function decorateWithFinish(handler) {
        return function(data, textStatus, jqXHR) {
            handler(data, textStatus, jqXHR);
            asyncNotifier.finished();
        };
    }

    function get(url, data, successHandler, errorHandler) {
        asyncNotifier.start();
        http.get(url, data, decorateWithFinish(successHandler), decorateWithFinish(errorHandler));
    }

    function post(url, data, successHandler, errorHandler) {
        asyncNotifier.start();
        http.post(url, data, decorateWithFinish(successHandler), decorateWithFinish(errorHandler));
    }

    return {
        get: get,
        post: post
    };

};

JS App Context (Wiring things together)

Here’s the js code that glues everything together… Like a “javascript app context”.

var MyAppMain = MyAppMain || {};
MyAppMain.Context = function() {
    function startup() {
        var http = Async.HttpAsyncDecorated(Async.Http(), Async.Notifier());
	MyApp.SomethingThatUsesAjaxHttp(http);
    }

    return {
        startup: startup
    };
};

WebDriver

And finally we need to use webdriver to wait for the div with the class asyncNotifier. We used WebDriverWait for that.

public static void waitForAsyncCallsToFinish(WebDriver driver)
{
	waitForCssClass(driver, By.id("asyncNotifier"), "done");
}

Technical ,