By way of quick follow up to yesterday's Backbone.js testing post, an astute reader pointed out that I had failed to read the documentation on
Backbone.history.navigate()
. It seems that it takes two arguments—if the second is true, then the route being navigated will trigger. Thus I can replace last night's default route:
var Routes = Backbone.Router.extend({
// ...
_setDefault: function() {
console.log("[setDefault]");
var month = Helpers.to_iso8601(new Date).substr(0,7);
Backbone.history.navigate('#month/' + month);
this.setMonth(month);
},
// ...
});
Which can be replaced with a version that removes the explicit call to setMonth()
and adds true
as a second argument to navgiate()
: var Routes = Backbone.Router.extend({
// ...
_setDefault: function() {
console.log("[setDefault]");
var month = Helpers.to_iso8601(new Date).substr(0,7);
Backbone.history.navigate('#month/' + month, true);
},
// ...
});
This works by virtue of a month-matcher route, which is fired after navigating to the month route in combination with the true
second argument to navigate()
: var Routes = Backbone.Router.extend({
routes: {
// ...
"month/:date": "setMonth"
},
// ...
setMonth: function(date) {
console.log("[setMonth] %s", date);
this.application.setDate(date);
}
});
And that works. When I open the root URL for my app, the default route kicks in, navigates to the current month and my appointments are on the calendar:And if I remove the
true
second argument, my calendar now lacks appointments because nothing triggers the appropriate route:The thing is, that my specs continue to pass:
This is because my tests inject a different, testing route and then manually does the route's job—setting the current date:
beforeEach(function() {
// ...
window.calendar = new Cal($('#calendar'), {
defaultRoute: function() {
console.log("[defaultRoute] NOP");
}
});
window.calendar.application.setDate("2011-11");
// ...
});
Now, to a certain extent, I do not have much choice. I have to explicitly set the date in my tests otherwise my November based tests are going to fail once December rolls around. But on the other hand, how can I get my tests to fail when routing is broken?Ah, but wait a second. I have been building on a number of assumptions that are probably incorrect. Instead of using
Backbone.history.navigate()
to move my application around, I have been manually setting window.location
. I have already found that some things are easier if I use navigate()
. Perhaps testing is similarly easier.So, I remove the
beforeEach(function() {
// ...
window.calendar = new Cal($('#calendar'));
Backbone.history.loadUrl();
// ...
});
(I do need to read-add the manual Backbone.history.loadUrl()
between runs per http://japhr.blogspot.com/2011/11/backbonejs-hash-tag-urls-with-jasmine.html)Then, in my application code, I remove the
true
second argument to navigate()
: var Routes = Backbone.Router.extend({
// ...
_setDefault: function() {
console.log("[setDefault]");
var month = Helpers.to_iso8601(new Date).substr(0,7);
Backbone.history.navigate('#month/' + month);
},
setMonth: function(date) {
console.log("[setMonth] %s", date);
this.application.setDate(date);
}
});
With that, I am failing again:Most importantly here, is not that I have failing specs, but that the console output includes logging statements for the default route being called, but not a subsequent logging message from
setMonth()
. If I re-add the true
second argument to navigate()
: var Routes = Backbone.Router.extend({
// ...
_setDefault: function() {
console.log("[setDefault]");
var month = Helpers.to_iso8601(new Date).substr(0,7);
Backbone.history.navigate('#month/' + month, true);
},
setMonth: function(date) {
console.log("[setMonth] %s", date);
this.application.setDate(date);
}
});
Then my Jasmine tests pass and my console logs output from both the default route and the subsequent setMonth()
triggered route:Nice. That was a big point of frustration in my Backbone testing efforts. As usual, had I been doing things idiomatically, life would have been much easier. Much thanks to Nick Gauthier (my Recipes with Backbone co-author) and Patrick (in last night's comments) for showing me the way.
I could still ask for a more obvious failure in my tests than I have here, so I think tomorrow I will try to implement a routing-only test. That could very well be the end of my testing exploration.
Day #213
No comments:
Post a Comment