Thursday, September 8, 2011

Jasmine Testing Backbone.js Applications

‹prev | My Chain | next›

Up tonight, I would like to see if I can get my Backbone application tested in jasmine.

First up, I generate a fixture of my Backbone application's homepage:
// Force test environment
process.env.NODE_ENV = 'test';

var app = require('../app'),
    assert = require('assert'),
    fs = require('fs');

module.exports = {
  // ...
  'generate fixture': function() {
    assert.response(app,
      { url: '/' },
      function(res) {
        fs.mkdir('fixtures', 0775, function() {
          fs.writeFile('fixtures/homepage.html', res.body);
        });
      });
  }
};
I will have to always remember to run this expresso.js test before running my Jasmine tests, but I can live with that.

Now, to actually test this, I need the jasmine gem:
gem install jasmine
This will enable me start a local web server. From that web server I can run the entire suite in a browser, including fixture loading. This is a node.js application, but I still think jasmine-gem may be my best option for testing here.

Next, I initialize the jasmine-gem config files and support structure:
$ jasmine init
Jasmine has been installed with example specs.

To run the server:

rake jasmine

To run the automated CI task with Selenium:

rake jasmine:ci
After following those instructions and running rake jasmine, I point my browser to http://localhost:8888 and, the sample specs pass!
To actually load in my homepage fixture, I will need jasmine-jquery:
➜  calendar git:(master) cd spec/javascripts/helpers
➜  helpers git:(master) wget https://github.com/downloads/velesin/jasmine-jquery/jasmine-jquery-1.3.1.js
I create a dirt simple test:
describe("Home", function() {
  it("uses the /appointments url-space", function () {
    loadFixtures('homepage.html');

    var it = new Appointment;
    expect(it.urlRoot).toEqual("/appointments");
  });
});
And load it up to see a Javascript console error:
(Uncaught TypeError: Cannot call method 'extend' of undefined)

That is easy enough to solve. I just need to ensure that underscore.js is loaded before anything else (Backbone in particular). So I update spec/javascripts/support/jasmine.yml:
src_files:
    - public/javascripts/underscore.js
    - public/javascripts/**/*.js
After reloading, I see:
(TypeError: Object [object Object] has no method 'dialog')

After again fiddling with the src_files order, I then get:
(TypeError: Cannot call method 'ajax' of undefined)

Both of which can be solved by more explicit ordering of JS files:
src_files:
    - public/javascripts/jquery.min.js
    - public/javascripts/jquery-ui.min.js
    - public/javascripts/underscore.js
    - public/javascripts/backbone.js
    - public/javascripts/**/*.js
And, with that, I see:
Success!

Well, that was not too hard in the end. I am not testing any AJAX interaction and firing events, but I am quite pleased with how easy this was to get set up.

Day #137

No comments:

Post a Comment