Friday, September 9, 2011

Stubbing Backbone Tests with Sinon.js

‹prev | My Chain | next›

Last night, I was able to take an HTML fixture from my Backbone.js application and run a simple jasmine test against it:
(the fixture loading is coming from jasmine-jquery)

That is not much of a test. It is more just an assertion of a configuration setting. To actually test my Backbone application, I am going to need to stub out the AJAX requests that Backbone makes. Even though my simple test passes, I see Backbone / AJAX errors in Chrome's Javascript console:
The current test:
describe("Home", function() {
  beforeEach(function() {
    loadFixtures('homepage.html');
  });

  it("uses the /appointments url-space", function () {
    var it = new window.Appointment;
    expect(it.urlRoot).toEqual("/appointments");
  });
});
If I can ensure that the AJAX call to /appointments returns and that I can control what it returns, I ought to be able to verify what the contents of the 15th will be:

  it("populates the calendar with appointments", function() {
    expect($('#2011-09-15')).toHaveText("Appt: Funk");
  });
So, before the fixture is loaded, I want to stub out calls to the /appointments namespace and return some dummy JSON data. Tonight, I am going to give sinon.js a try in this capacity. So first I grab the latest sinon.js:
wget http://sinonjs.org/releases/sinon-1.1.1.js -O spec/javascripts/helpers/sinon-1.1.1.js
There is no need to add this to spec/javascripts/support/jasmine.yml since it is already loaded by virtue of the default value for helpers (["helpers/**/*.js").
The actual response from my express.js (which is proxying a CouchDB backend) is:
➜  calendar git:(master) ✗ curl http://localhost:3000/appointments/
{"total_rows":7,"offset":0,"rows":[
{"id":"69bb0bd029c5ae5209168c96b0003125","key":"69bb0bd029c5ae5209168c96b0003125","value":{"rev":"1-4385f513d690af99b3bfaea2b08cb75c"},"doc":{"_id":"69bb0bd029c5ae5209168c96b0003125","_rev":"1-4385f513d690af99b3bfaea2b08cb75c","title":"Delete Me","description":"asdf","startDate":"2011-09-15"}},
/* ... */
]}
So maybe something like this will do:
jasmine.getFixtures().preload('homepage.html');

describe("Home", function() {
  beforeEach(function() {
    var server = sinon.fakeServer.create();
    server.respondWith(
      200,
      { "Content-Type": "application/json" },
      '{"total_rows":1,"offset":0,"rows":[' +
        '{"id":"42","key":"42","value":{"rev":"1-2345"},' +
        '"doc":{"_id":"42","_rev":"1-2345","title":"Funk","description":"asdf","startDate":"2011-09-15"}}' +
        ']}'
    );

    loadFixtures('homepage.html');

    server.respond();
  });

  it("populates the calendar with appointments", function() {
    expect($('#2011-09-15')).toHaveText("Funk");
  });
});
I preload my fixtures so that stubbing out XHR will not cause trouble with fixutre loading. Then I fake an XHR request.

Reloading, however, I am not seeing the fixture page populated:
That actually cuts down on XHR requests in the console, so I am fairly confident that sinon.js is doing something. Unfortunately, I am unable to get it to populate the Backbone collection. I am forced to call it a night here. Hopefully I can get this working correctly tomorrow.

Update: Figured it out. I was not sending back an array in server.respondWith(). The following works:
jasmine.getFixtures().preload('homepage.html');

describe("Home", function() {
  beforeEach(function() {
    var server = sinon.fakeServer.create();
    server.respondWith(
      [200,
      { "Content-Type": "application/json" },
      '{"total_rows":1,"offset":0,"rows":[' +
        '{"id":"42","key":"42","value":{"rev":"1-2345"},' +
        '"doc":{"_id":"42","_rev":"1-2345","title":"Funk","description":"asdf","startDate":"2011-09-15"}}' +
        ']}']
    );

    loadFixtures('homepage.html');

    server.respond();
    server.restore();
  });

  it("populates the calendar with appointments", function() {
    expect($('.appointment', '#2011-09-15')).toHaveText(/Funk/);
  });
});
This results in a passing test:
Yay!


Day #139

No comments:

Post a Comment