Saturday, November 26, 2011

BDDing Backbone.js with Jasmine (Day 2)

‹prev | My Chain | next›

After my jasmine-fueled BDD session last night, it is time to poke my head up to see how it looks. The verdict is that I need to drive a few more things:

So, from top-to-bottom, I need to remove the sub-title date, need more appointments (those are only from November, it should include all appointments, the appointment titles should be defined, and the next / previous navigation elements should be gone.

Removing the subtitle and the navigation elements should be the responsibility of the Month View, not my new list view. So I add new specs to my Month view:

  describe("month view", function() {
    // ...
    describe("leaving", function() {
      it("removes its subtitle");
      it("removes navigation elements");
I already have spec setup code to create a Month view. For the setup in this spec, I need to also navigate to the list view, which should remove the subtitle and navigation elements:
    describe("leaving", function() {
      beforeEach(function() {
        window.calendar = new Cal($('#calendar'));
        Backbone.history.navigate('', true);
        Backbone.history.navigate('#list', true);
        // ....
      // ...
With the setup navigating to the list view, I can define my expectation:
      it("removes its subtitle", function() {
        expect($('h1')).not.toHaveText(new RegExp(year));
Which fails:

To make that pass, I simply need to have a higher level view (the application view in this case), tell the Title View to remove itself when switching to the List View:
    var Application = Backbone.View.extend({
      // ...
      render: function() {
        if (this.view == 'list') {
          view = new CalendarList({collection: this.collection});
        else { /* ... */ }

      // ...
And now I have reached the green:

I write a similar spec for my navigation controls, except in this case I expect the controls to be hidden:
      it("removes navigation elements", function() {
To make that pass, I again make the higher level view responsible for telling the lower order view to remove itself.

The last thing that I try to solve tonight is the mystery "unknown" titles. For that, I know that my fake (sinon.js) server response includes an appointment titled "Appt 001". So I create an expectation that the appointment list view should include that title:
  describe("list view", function() {
    var couch_doc1 = { "title": "Appt 001", /* ... */ }
    // ...
      , doc_list = { "rows": [ {"value": couch_doc2}, /* ... */ ] };

    // ...
    it("displays appointment titles", function() {
      expect($('#appointment-list')).toHaveText(/Appt 001/);
To make this pass, I simply have to recall that accessing Backbone model attributes is done via a get() method, not by accessing attributes directly on the model:
    var CalendarList = Backbone.View.extend({
      // ...
      render: function() {
          '<h2>Appointment List</h2>' +
          '<ol id="appointment-list">' +
          this.collection.reduce(function(memo, appointment) {
            return memo + '<li>' + appointment.title + '</li>';
          }, "") +

        return this;
After changing that to appointment.get("title"), I have my green test. And quick sanity check reveals that I fixed most of my problems:

I call it a night here. Up tomorrow: I need to do some more experimenting with the router to support a recipe in Recipes with Backbone.

Day #217

No comments:

Post a Comment