Wednesday, November 16, 2011

Fixture Phantom Backbone.js Views

‹prev | My Chain | next›

Last night I removed jQuery UI dialogs from the web page of my Backbone.js application. Instead, I move the necessary DOM into the application itself. This has the advantage of decoupling my application from my web page. This should have the side-benefit of making testing easier since I will no longer have to load a fixture of the web page with each test.

It should make it easier, except after last night, two of my jasmine tests are now failing:



The first failure is telling me that my dialog is no longer showing. The second tells me that, even if it were showing, it would not contain the correct title. Ugh.

The add appointment dialog in my real application is definitely working, even after repeated opens:


Since it worksforme, I suspect something going wrong with my tests—or at least my expectations of how the tests should work. Since my tests have not changed, however, I first check out my code changes. After rooting through the changes and some well-placed debugger statements, I realize that my add-appointment dialog is sticking around between specs.

This is caused by how I add the dialog HTML to the DOM:
    var AppointmentAdd = new (Backbone.View.extend({
      initialize: function() {
        this.ensureDom();
        // ...
      },
      ensureDom: function() {
        if ($('#calendar-add-appointment').length > 0) return;

        // $('#calendar-add-appointment') does not exist, so create and populate it here
      }
      // ...
    });
In between specs, I am closing dialog windows:
  afterEach(function() {
    $('#calendar-add-appointment').dialog('close');
    $('#calendar-edit-appointment').dialog('close');
The dialog is no longer visible, but it is most definitely still in the DOM. Since it remains in the DOM, the guard clause in ensureDom() is met. The implication is that all future dialog operations take place on the empty Backbone <div>. Bah!

The solution, thankfully, is simple enough. In addition to closing the dialog between spec runs, I also need to remove the appointment dialog:
  afterEach(function() {
    $('#calendar-add-appointment').dialog('close');
    $('#calendar-add-appointment').remove();

    $('#calendar-edit-appointment').dialog('close');
  });
It will be recreated on the next run so any other tests that rely on its presence should continue to pass.

And indeed, my tests are passing again:


After applying the same technique to convert the edit-dialog to a in-Backbone operation, I call it a night. Up tomorrow, I hope to rid myself of fixtures altogether. They have proven to be a bit of a pain.


Day #207

No comments:

Post a Comment