Sunday, September 22, 2013

Full-Stack Backbone.js Testing with Dart

Over the last few days, I have more or less gotten Dart's awesome unit testing working with a Backbone.js application. Thanks to the magic of Dart's js-interop, I have a real test running against the Funky Calendar from Recipes with Backbone. And after last night, I have setup and teardown working. For my latest feat of insanity (and I mean that, there's no real reason to do this) I will attempt testing the creation of appointments in the Backbone.js calendar.

If there is a deficiency to testing Dart applications, it is the inability to stub HTTP requests. Although this makes unit testing tougher, it has the advantage of forcing developers into a more full-stack frame of mind. Towards that end, I have a “real fake” test server (plummbur-kruk) backing my REST-like Backbone application in test. In the test setup, I am already creating a calendar appointment for the current month:
      document.head.append(new BaseElement()..href = Kruk.SERVER_ROOT);;

      el = document.body.append(new Element.html('<div id=calendar>'));

       var doc = '''
           "title": "Get Funky",
           "description": "asdf",
           "startDate": "${fifteenth}"

      return Future.wait([
        Kruk.alias('/widgets', as: '/appointments')
With that setup in place, can start my Backbone application and eventually check my expectation that the appointment on the 15th of the month is included in the app:
expect(cell.text, matches("Get Funky"));
Tonight, I would like add a new test that clicks on particular date, enters appointment information, clicks the save button, and finally verifies that the appointment is now included on the calendar.

I start with the usual Backbone test thing (though with a Dart js-interop twist) by creating an instance of the Backbone application and ensuring that Backbone history is running properly:
    test("can create new appointments", (){
      new js.Proxy(js.context.Cal, query('#calendar'));
      // ...
Next, I find the table cell that contains the 14th of the month and click on it:
    test("can create new appointments", (){
      // ...
      var cell = queryAll('td').
        where((el)=> == fourteenth).
      // ...
This should result in a popup dialog with a few appointment fields. I fill in those appointment values next:
    test("can create new appointments", (){
      // ...
          value = 'Test Appointment'
          value = 'asdf';
      // ...
Finally, I click the OK button in the popup:
    test("can create new appointments", (){
      // ...
      // ...
With that, I should be able to check my expectation that the fourteenth of the month now contains an appointment created in my test (after a brief wait for all of the Backbone events to propagate):
    test("can create new appointments", (){
      // ...
      new Timer(
        new Duration(milliseconds: 10),
          expect(cell.text, matches("Test Appointment"));
But, for some reason, that fails:
FAIL: the initial view can create new appointments
  Expected: match 'Test Appointment'
    Actual: '14'
All that is in the table cell for the 14th is the day of the month. If I remove the teardown step to see the status of the (un-styled) popup dialog, I find that everything seems to have worked except for the clicking of the button:

And oddly enough, if I use jQuery (which is available to me via js-interop), I am able to click the button:
      js.context.jQuery('.ui-dialog-buttonset button').click();
Which results in a successful test:
PASS: the initial view can create new appointments
I am at a loss to explain why the click event in jQuery works, but it does not work from Dart. Perhaps there is an additional event property that is being added by jQuery? I have a working test, but would very much like to have the test in pure Dart (or at least have a idea why that won't work). So I will likely use that as an excuse to continue investigation tomorrow…

Day #882

No comments:

Post a Comment