Testing Backbone routers

With the shift of application code to the client, we are continually seeing more single page web applications. But they come with a drawback. Since we are keeping the users on the same page, we are losing the natural ability of tracking steps through the URL changes.

Routers in Backbone are a solution to this problem. They allow the definition of routes inside your JavaScript code, giving back the feel of a web page to your rich web application.

Defining a new router

Suppose that we want our application to support the URL routes to display different types of investment:

  • /investments/good: To show only a list of the good investments
  • /investments/bad: To show only a list of the bad investments
  • /investments/all: To show a list of all the investments

Normally this would be handled on the server, but with Backbone, we can define how to handle these routes in JavaScript on the browser. There is one catch though, for this to work it needs to use hash the URL fragments (#/investments). So all the above URLs would actually be (on our development server) like this http://0.0.0.0:8000#/investments/good.

It is possible to make Backbone use the new History API, and support actual URLs, but this topic is out of the scope of this book.

Back to the implementation of our router, we can see that all these routes deal with investments. So we can start by creating a new InvestmentRouter, with its source and spec file.

At the spec file we can start by expecting it to be a Backbone router:

describe("InvestmentsRouter", function() {
  var router;

  beforeEach(function() {
    router = new InvestmentsRouter();
  });

  it("should be a Backbone Router", function() {
    expect(router).toEqual(jasmine.any(Backbone.Router));
  });
});

Which in the code translates to a familiar Backbone component declaration:

(function (Backbone) {
  var InvestmentsRouter = Backbone.Router.extend();
  this.InvestmentsRouter = InvestmentsRouter;
})(Backbone);

Defining routes

So how do we go on implementing these routes?

One approach we could take is to keep the router files as simple as possible, letting them handle the URLs and triggering events so that the application can handle the user requests.

To better understand what it means, let's see a spec regarding the '/investments/good' route:

describe("InvestmentsRouter", function() {
  var router, observer;

  beforeEach(function() {
    router = new InvestmentsRouter();
    observer = jasmine.createSpy();
  });

  it("should route '/investments/good'", function() {
    router.on('route:goodInvestments', observer);

    Backbone.history.loadUrl('/investments/good')

    expect(observer).toHaveBeenCalled();
  });
});

Let's see what this spec does:

  • First, it uses the familiar events infrastructure to add an observer to a route:goodInvestment event:
    router.on('route:goodInvestments', observer);
  • Then, we use Backbone to simulate a URL request:
    Backbone.history.loadUrl('/investments/good'),
  • And finally, we expect that our observer was called:
    expect(observer).toHaveBeenCalled();

To implement this on the router is a matter of adding a new entry to a routes object:

var InvestmentsRouter = Backbone.Router.extend({
  routes: {
    'investments/good': 'goodInvestments'
  }
});

We define a route by a matching pattern and a name, in this case investments/good and goodInvestments respectively.

This is how you test and write routers.

Using routers

I bet you are curious about how we could integrate this into the application. Here is a snippet showing how that could be done:

this.router = new InvestmentsRouter();
this.router.on('route:goodInvestments', function () {
  this.applicationView.showGoodInvestments();
}, this);

Backbone.history.start();

The last line is important; it tells Backbone to start listening for URL changes, effectively enabling the Routers.

Routers should only route

There is a common mistake that Backbone beginners do trying to drive the application development from routes. This is a common pattern in web applications that require a new request to an URL for each action the user does. But that is no longer the case. You are developing a rich web application, something that is much more like a native application.

So, drive your code from your views, you can always add routes later.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.60.63