Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing routers in backbone.js properly?

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?

like image 219
Industrial Avatar asked Feb 09 '12 17:02

Industrial


People also ask

Is Backbone js still used?

Backbone. Backbone has been around for a long time, but it's still under steady and regular development. It's a good choice if you want a flexible JavaScript framework with a simple model for representing data and getting it into views.

How does Backbone js work?

Backbone. js gives structure to web applications by providing models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing API over a RESTful JSON interface.

Is Backbone js frontend or backend?

Front-End MVC frameworks (Backbone, Angular, etc) all rely on a backend service to provide the data that, say Backbone, would then use as its model. You could have an entire MVC pattern on the backend that accepts requests and spits out some JSON for a frontend MVC framework to use.


1 Answers

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 a Backbone.history.start({ pushState: true });

    describe('app.Router', function () {          var router = app.router, pushStateSpy;          it('has a "home" route', function () {             expect(router.routes['']).toEqual('home');         });          it('triggers the "home" route', function () {             var home = spyOn(router, 'home').andCallThrough();             pushStateSpy = spyOn(window.history, 'pushState').andCallFake(function (data, title, url) {                 expect(url).toEqual('/');                 router.home();             });             router.navigate('');             expect(pushStateSpy).toHaveBeenCalled();             expect(home).toHaveBeenCalled();             ...         });     });   

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:

it('triggers the "home" route', function () {     var home = spyOn(router, 'home').andCallThrough();      if (Backbone.history._hasPushState) {         pushStateSpy = spyOn(window.history, 'pushState').andCallFake(function (data, title, url) {             expect(url).toEqual('/');             router.home();         });         router.navigate('', {trigger: true});         expect(pushStateSpy).toHaveBeenCalled();         expect(home).toHaveBeenCalled();      } else if (Backbone.history._wantsHashChange) {         var updateHashSpy = spyOn(Backbone.history, '_updateHash').andCallFake(function (loc, frag) {             expect(frag).toEqual('');             router.home();         });         router.navigate('', {trigger: true});         expect(updateHashSpy).toHaveBeenCalled();         expect(home).toHaveBeenCalled();     } }); 

If you are on IE6, good luck.

like image 70
ggozad Avatar answered Oct 08 '22 04:10

ggozad