So I've just started to write tests for my in-progress javascript app, using sinon.js
& jasmine.js
. Works pretty well overall, but I need to also be able to test my routers.
The routers, in their current state, will trigger an number of views and other stuff, terminating the current jasmine.js
test by invoking Backbone.navigate
dependent on application state and UI itneraction.
So how could I test that routing to different locations would work, while keeping the routers "sandboxed" and not allowing them to change route?
Can I set up some sort of mock function that will monitor pushState changes or similar?
Here's a low-levelish way of doing it with jasmine, testing that pushState works as expected and that your router sets up things properly... I assume a
router
that has been initialized and has a home route mapped to ''. You can adapt this for your other routes. I also assume you've done in your app initialization aBackbone.history.start({ pushState: true });
You can effectively achieve similar things by doing
Backbone.history.stop();
it's meant for this reason.UPDATE: Browsers with no
pushState
:This of course will work fine if your browser you test on has support for
pushState
. If you test against browsers that don't, you can conditionally test as follows:If you are on IE6, good luck.
I started out using ggozad's solution of spying on
_updateHash
which partially worked for me. However, I discovered that my tests were confused because the hash never updated, so code that relied upon calls togetHash
orgetFragment
were failing.What I ended up with is the following helper function that spies on both
_updateHash
andgetHash
. The former records the request to update the hash, and the latter returns the last hash that was passed to_updateHash
. I call this helper function in my tests before I start the Backbone history.You have to mock Backbone.Router.route which is the function that is internally used to bind the functions on to Backbone.History.
Thats the original function:
you could to something like this, which simply call the functions when the router will be initialized:
You could also save the callbacks in a object and with the route as name and call same steps by step:
Here's what I ended up using myself. I made a mock version of the router by extending it and overriding the methods with a blank method to prevent it from invoking any further logic when being called:
Note that
sinon.js
is used above to create the spy, along withunderscore.js
to provide thesize
function.There is a very good tutorial about testing backbone:
http://tinnedfruit.com/2011/04/26/testing-backbone-apps-with-jasmine-sinon-3.html
When I'm testing a backbone router, what I care about is that the routes I provided are invoking the functions I specify with the correct arguments. A lot of the other answers here aren't really testing that.
If you need to test the functionality of some routes, you can test those functions by themselves.
Assuming you have a simple router:
Here's how I do it: