Best features of Jasmine

Jasmine is a suite full of useful features for testing but many are overlooked or unused. This takes a look at some of the best features, including asynchronous calls, spying and mocking.

1005541K5-6

All the example code can be found on this JSFiddle.

Lets start with a JS class, it uses a facade pattern so it can keep some methods (and potentially properties) private.
Its methods include:
- normal methods,

- private methods,

- using arguments,

- using promises.

function CleanObject () {
    var methods = {
        returnHello: function() {
            return "hello";
        },    
        runAsync: function () {
            var defer = $.Deferred();
            this._returnSuccess().done(function (data) {
                defer.resolve(data);
            }).fail(function () {
                defer.reject('something went wrong');
            });
            return defer;
        },
        _returnSuccess: function () {
            var defer = $.Deferred();
            defer.resolve("it works");

            return defer;
        },
        doubleNumber: function (number) {
            return number * 2;
        }
    };
    return {
        returnHello: function () {
            return methods.returnHello();
        },
        runAsync: function () {
            // doesn't need to return another defer or wrap in promise block.
            return methods.runAsync();
        },
        doubleNumber: function (one) {
            return methods.doubleNumber(one);
        },
        returnNumber: function () {
            this.doubleNumber(6);
        }
    };
};

Lets create our Describe block.

describe("My CleanObject", function() {
    var myObject = new CleanObject();
});

Next is basic spying. We spy on a method and return a different value for the test when it is called using ‘andReturn’ and assert using ‘toBe’.

it("can spy on myMethod", function() {   
    expect(myObject.returnHello()).toBe('hello');
    spyOn(myObject, 'returnHello').andReturn('Something New');

    expect(myObject.returnHello()).toBe('Something New');
});

Now we move onto promises. We setup a promisePass which will pass and then a promiseFail which will fail. It spies on the myObject and uses ‘andCallFake’ to fail promiseFail object. This will check for rejected and resolved/passed results.

it("can run a promise", function() {

    var promisePass = myObject.runAsync();
    promisePass.then(function(message){
        expect(message).toBe('it works');
    }, function(error){
        expect(false).toBe(true); // fails if called
    });

    spyOn(myObject, 'runAsync').andCallFake(function () {
        var defer = $.Deferred();
        return defer.reject("failed test");
    });

    var promiseFail = myObject.runAsync();
    promiseFail.then(function(message){
        expect(true).toBe(false); // fails if called
    }, function(error){
        expect(error).toBe("failed test");
    });

});

There are 2 techniques to test arguments handed to a method. Very useful for testing methods which run ajax calls. (A) uses the ‘andCallFake’ and reads better. (B) uses ‘mostRecentCall.args[0]‘ which uses more code and is not quite as readabe, but still does the job.

it("can spy and check args", function() {
    // A)
    spyOn(myObject, 'handArgs').andCallFake(function (one) {
        expect(one).toBe(6);
    });
    myObject.returnNumber();

    // B)
    var uselessSpy, theArgs, 
    newObj = new CleanObject();
    uselessSpy = spyOn(newObj, 'handArgs');   
    newObj.returnNumber();
    theArgs = uselessSpy.mostRecentCall.args[0];
    expect(theArgs).toBe(6);
});

Last is an example of something making use of Jasmines other Asychronous features. Largely ‘runs()’ and ‘waitsFor()’.
This example is found at Jasmine

runs() will run everything serially (i.e. in sequence, only moving on once one has completed)

waitsFor() blocks until the condition its waiting for is met OR it times out.

it("should support async execution", function() {
    var value, flag;
    runs(function() {
        flag = false;
        value = 0;
        setTimeout(function() {
            flag = true;
        }, 500);
    });

    waitsFor(function() {
        value++;
        return flag;
    }, "The Value should be incremented", 750);

    runs(function() {
        expect(value).toBeGreaterThan(0);
    });
});

Jasmine has many many other features but these are just a couple of the more useful features.

Leave a Reply