Sunday, November 13, 2011

Backbone.js Hash Tag URLs with Jasmine

‹prev | My Chain | next›

Up today, I continue my efforts to get the jasmine test suite for my Backbone.js under control. Of the nine specs that I have, 4 are still failing:


That first one is odd. I am explicitly testing that my Backbone app is CouchDB aware. Why it should have been couch aware at one point, but no longer is a minor mystery. Actually, since the app still works, it is more likely that I am doing something stupid.

Upon closer inspection, it is really strange that the error message indicates that the CouchDB revision attribute is not set. I am quite definitely setting that in my test setup:
  var server
    // ...
    , fifteenth = year + '-' + month + "-15"
    , couch_doc = {
        "_id": "42",
        "_rev": "1-2345",
        "title": "Get Funky",
        "description": "asdf",
        "startDate": fifteenth
      }
    , doc_list = {
        "total_rows": 1,
        "rows":[{"value": couch_doc}]
      };

  beforeEach(function() {
    // stub XHR requests with sinon.js
    server = sinon.fakeServer.create();

    // load fixutre into memory (already preloaded before sinon.js)
    loadFixtures('homepage.html');

    // populate appointments for this month
    server.respondWith('GET', /\/appointments\?/,
      [200, { "Content-Type": "application/json" }, JSON.stringify(doc_list)]);
    server.respond();
  });
What is more, the objects that I do see in the collection, when I console.log() the collection, have none of the couch_doc attributes. In fact, the only attribute that I see is startDate: "2011-11". And I am not seeing the XHR log for the collection. It is almost as if the collection is not being loaded...

Well, of course, it is not being loaded. The reason is that, since I last ran specs, I switched the application's initialization to be triggered by the current route. If the application loads up without a hashtag route, the router sets one, which then triggers the application initialization:
 var Routes = Backbone.Router.extend({
    routes: {
      "": "setDefault",
      "month/:date": "setMonth"
    },

    setDefault: function() {
      console.log("[setDefault]");
      var month = Helpers.to_iso8601(new Date).substr(0,7);
      window.location = '/#month/' + month;
    },

    setMonth: function(date) {
      console.log("[setMonth] %s", date);
      this.application.setDate(date);
    }
  });
This occurs even when running my jasmine test suite. I had loaded up the jasmine ruby gem server at http://localhost:8888 but was immediately redirected to http://localhost:8888/#month/2011-11 after my application loaded.

I know from yesterday that I cannot restart my Backbone's history mechanism. I can, however, load the current URL which, as I just noted, contains the hash tag for the current month. I do that with Backbone.history.loadURL() in the spec setup:
  beforeEach(function() {
    // ...
    // load fixutre into memory (already preloaded before sinon.js)
    loadFixtures('homepage.html');

    Backbone.history.loadUrl();

    // ...
  });
I am not 100% sold on this approach. I am somewhat reliant on earlier tests loading the application to set the hash tag properly. It also feel a little like reaching under the covers to call Backbone.history.loadURL() from the test suite. Still, at this point, I do not see much downside.

This approach certainly beats adding more junk to yesterday's try - catch block for testing-only:
  try {
    Backbone.history.start();
  } catch (x) {
    console.log(x);
    // Must be testing, so let's manually load the hash tag URL:
    // Backbone.history.loadUrl();
    // 
    // Or maybe just tell the collection to fetch itself
    // appointments.fetch();
  }
If I get desperate or run into a situation in which loadURL does not work, I will keep that in my back pocket. For now, I am down to two failing tests:


I will pick back up with those two tomorrow.

Day #204

No comments:

Post a Comment