Next, navigate your browser to http://localhost:8000/index.html, and you should see a congratulations message. Also open http://localhost:8000/SpecRunner.html; the page should contain a sample spec running green.

You should also find a Cakefile in the root directory. This is a very simple CoffeeScript file that you can use to automatically compile all the .coffee files we're going to write. It assumes that you have CoffeeScript installed as a globally available Node module, and you can refer to this page for instructions. Alternatively, you can use tools like CodeKit or Livereload to accomplish the same result.

To run the cake task, just type cake compile. This task will keep running. You can watch for changes every time you save, but you may need to restart the script if you add new files.

Step 1 - The Restaurant Model

Namespacing

Using Backbone means we're going to create models, collections and views. Therefore, having a namespace to keep them organized is a good practice, and we can do that by creating an app file and a relevant spec:

We just need to create a class on the window namespace to make it globally available--we'll will worry about the namespace in the second part. Now, our specs should pass. Refresh /SpecRunner.html, and the specs should pass.

Validations

As I said before, we will use Backbone Validations for client side validation. Let's add a new describe block to models/restaurant_spec.coffee to express our expectations:

We define an empty attributes object that will be modified in every expectation. Each time we will set only one attribute with an invalid value, thus testing the thoroughness of our validation rules. We can also use an afterEach block to avoid a lot of repetition. Running our specs will show 6 failures. Once again, we have an extremely concise and readable implementation, thanks to Backbone validations:

Our specs will now pass, and with these changes in place, we have a quite solid Restaurant model.

The Restaurants Collection

Because we want to manage a list of restaurants, it makes sense to have a RestaurantsCollection class. We don't know yet how complicated it needs to be; so, let's focus on the bare minimum requirements by adding a new describe block to the models/restaurant_spec.coffee file:

Backbone provides an extensive list of methods already defined for a collection, so our work here is minimal. We don't want to test methods defined by the framework; so, we just have to make sure that the collection uses the right model. Implementation-wise, we can append the following few lines to models/restaurant.coffee:

What we really care about is the #restaurant-form and the #restaurants table. The input elements use a conventional pattern for their names (entity[attribute]), making them easily processable by most back-end frameworks (especially Rails). As for the table, we are leaving the tbody empty, as we will render the content on the client with Hogan. In fact, we can add the template we're going to use right before all other <script> tags in the <head>.

Being a Mustache template, it needs the correct text/mustache type and an id we can use to retrieve it from the DOM. All the parameters enclosed in {{ }} are attributes of our Restaurant model; this simplifies the rendering function. As a last step, we can add a remove icon that, when clicked, deletes the corresponding restaurant.

The Restaurants View Class

As previously stated, we have two core view components: the restaurants list and the restaurant form. Let's tackle the first by creating both the directory structure for views and the needed files:

Fixtures are a simple way to import HTML fragments in our tests without having to write them inside the spec file itself.

It looks like a lot of code, but this is a standard start for a view spec. Let's walk through it:

We begin by instantiating an object that holds some restaurant data. As suggested by the Backbone documentation, it's a good practice to feed a Backbone app the data it needs directly in the markup to avoid a delay for the user and an extra HTTP request when the page opens.

We create an invisible table element without appending it to the DOM; we don't need it for user interaction.

We define a beforeEach block where we instantiate a RestaurantsCollection with the data we created before. Doing it in a beforeEach block guarantees that every spec will start with a clean slate.

We then instantiate a RestaurantsView class and pass both the collection and the invisible table in the initializer. The object keys, collection and el, are default Backbone methods for a View class. They identify the container where the view will be rendered and the data source used to populate it.

The specs simply check that everything we assume in the beforeEach block is true.

Running our tests throws an error because the RestaurantsView class is not yet defined. We can easily get everything to green by adding the following content to views/restaurant.coffee:

class Gourmet.Views.RestaurantsView extends Backbone.View

We don't need to override or change the constructor defined by the Backbone.View prototype because we instantiated the view with a collection and an el attribute. This single line is enough to get our specs green; it will, however, do pretty much nothing from the end result point of view.

Assuming there are restaurants added to the collection, the view class should render them on the page as soon as the page loads. Let's translate this requirement into a spec that we can add at the bottom of the views/restaurant_spec.coffee file:

it "should render the the view when initialized", ->
expect($(invisible_table).children().length).toEqual 3

We can test the number of children (<tr/> elements) that the invisible table needs to have, considering that we have defined a sample dataset of three restaurants. This will result in a red spec because we haven't even started working on rendering. Let's add the relevant piece of code to the RestaurantsView class:

...the real benefit is the possibility to work effectively on testable pieces of functionality that follow predictable patterns.

You will see this pattern very frequently in a Backbone application, but let's break it into pieces:

The template function isolates the templating logic we use inside the application. We're using mustache templates compiled through Hogan, but we could've used Underscore or Mustache itself. All of them follow a similar API structure; so, switching would not be difficult (albeit a bit boring). In addition, isolating the template function gives a clear idea of which template a view uses.

The render function empties the el (note that @$el is a cached, jQuery wrapped version of the element itself made available by default by Backbone), iterates on the models inside the collection and render the result, and appends it to the element. This is a naive implementation, and you may want to refactor it to append just once instead of doing it at every loop.

Finally, we call render when the view is initialized.

This will make our spec green and will give us a minimal amount of code useful to actually show it on the page. Let's open index.html and add the following:

We're basically replicating the default dataset and the setup needed to get the app running. We're also doing it inside the HTML file because this code is useful only in this static version of the app.

Refresh the page and behold! The restaurants table will be populated with results.

Next, we need to handle what happens when we add or remove a restaurant from the collection. It's important to remember that the form is just one possible way to act on the collection; we could also have push events from other users, for example. Therefore, it is essential that this logic is separated in a clean and independent manner.

What do we expect to happen? Let's add this specs to the views/restaurants\_view\_spec.coffee file (right after the last one):

it "should render when an element is added to the collection", ->
@restaurants_collection.add
name: 'Panjab'
postcode: 'N2243T'
rating: 5
expect($(invisible_table).children().length).toEqual 4
it "should render when an element is removed from the collection", ->
@restaurants_collection.pop()
expect($(invisible_table).children().length).toEqual 2

In essence, we add and remove a restaurant to the collection, expecting our table to update itself accordingly. Adding this behavior to the view class requires a couple of lines in the initializer, as we can leverage on Backbone events on the collection:

We can re-render the whole table using the collection in the current state (after an element has been added or removed) because our rendering logic is pretty simple. This will make our specs to pass.

When you now open the index.html file, you will see that the remove icon on each table row doesn't do anything. Let's spec out what we expect to happen at the end of the views/restaurants\_view\_spec.coffee file:

When clicking on an element with class .remove, the view calls the removeRestaurant function and passes the jQuery event object. We can use it to get the id of the element and remove the relevant model from the collection. We already handle what happens when removing an element from the collection; so, this will be enough to get the spec to green.

In addition, you can open index.html and see it in action in the browser.

The Restaurant Form Class

We now need to handle the user input when using the form to add a new restaurant:

Once again, let's remember to add the JavaScript compiled version of the view to index.html and both compiled versions to SpecRunner.html.

It's a good time to introduce fixtures, a piece of functionality made available by Jasmine-jQuery, because we will be dealing with the form markup. In essence, fixtures are a simple way to import HTML fragments in our tests without having to write them inside the spec file itself. This keeps the spec clean, understandable, and can eventually lead to reusability of the fixture among multiple specs. We can create a fixture for the form markup:

The jasmine.getFixtures().fixtures_path attribute change is needed as we have a custom directory structure that differs from the library default. Then, in the beforeEach block, we load the fixture and define an @invisible_form variable that targets the form we just imported. Finally, we define an instance of the class we're going to create, passing in an empty restaurants collection and the @invisible_form we just created. As usual, this spec will be red (the class is still undefined), but if we open restaurant_form.coffee we can easily fix it:

class Gourmet.Views.RestaurantForm extends Backbone.View

Next, we need to think about our spec's structure. We have two choices:

Using Backbone means we're going to create models, collections and views. Therefore, having a namespace to keep them organized is a good practice

We can spy on the form content with jasmine and mock it.

We could manually change the content of the fields and then simulate a click.

Personally, I favor the first approach. The second would not eliminate the need for proper integration testing, but it would increase the complexity of the spec.

Jasmine spies are quite powerful, and I encourage you to read about them. If you come from a Ruby testing background, they're very similar to RSpec's mocks and feel very familiar. We do need to have an idea of the pattern we are going to implement, at least with broad strokes:

The user enters data in the form.

When he presses save, we get the form content in a serialized form.

We transform that data and create a new restaurant in the collection.

If the restaurant is valid, we save it, otherwise we will display validation errors.

As said before, we're going to mock the first step, and we'll do so by defining a new describe block where we instantiate an object that represents a well formed, valid data structure coming from a form.

At the end, we define a spy on the serializeArray method for our form. That means that if we call @restaurant_form.$el.serializeArray(), we already know that it's going to return the object we created above. This is the mocking facility we needed; it simulates the user input we need to test with. Next, we can add some specs:

In the first spec, we verify that our RestaurantForm class has a method that parses the data from the form. This method should return an object that we can feed to the restaurant collection. In the second spec, we mock the previous method because we don't need to test it again. Instead, we focus on what happens when the user clicks 'Save'. It will probably trigger an event that calls a save function.

We should tweak the second spec's mock to return invalid data for a restaurant in order to verify that the restaurant doesn't get added to the collection. In the third spec, we verify that this also triggers validation errors in the form. The implementation is somewhat tricky:

This is a good practice to make sure that we use the fake server only where we need to, minimizing interference with the rest of the test suite.

Let's see each function:

We have an events hash that binds the user's mouse click to a save function.

The save function parses the data (more on that below) in the form and creates a new restaurant. We call the validate function (available by Backbone and defined by Backbone-validations). It should return false when the model is valid, and an error object when it's invalid. If valid, we add the restaurant to the collection.

The two 'parse' functions are needed to extract the attribute names from the form and create an object in the desired Backbone-ready format. Bear in mind that this complexity is needed because of the markup. We could change it, but this is a good example of how you could work on top of an existing form to enhance it.

The handleErrors function iterates over the errors object and finds the corresponding input fields, adding the .error class when appropriate.

Running the specs now shows a reassuring series of green dots. To have it running in the browser, we need to extend our initialize function:

There's only one caveat: for now you can't delete a restaurant that you added because we rely on the id attribute to target the correct model in the restaurants collection (Backbone needs a persistence layer to assign it). This is where you would add, depending on your needs, a real back-end--like a Rails server or a LocalStorage adapter.

Step 3 - Testing server interaction

Even though we're on a server-less environment, we can take advantage of a couple of extra libraries that let us wire up our application for a server deploy. As a proof of concept, we will assume to be working on top of a Ruby on Rails stack.

To use Backbone with a Rails application, we need to have an additional adapter for syncing; Backbone doesn't provide that by default (it's a server agnostic tool). We can use the one included in the Backbone-rails project.

Next, we need to include it both in index.html and SpecRunner.html, right after the script that requires Backbone itself. This adapter takes care of executing all the asyncronous requests we need, provided that we setup our Restaurant model and our RestaurantsCollection with the right URLs.

How are we going to test this? We can use Sinon.js, a very powerful JavaScript mocking library that is also able to instantiate a fake server object that will intercept all XHR requests. Once again, we can simply:

Don't forget to add it to the SpecRunner.html file right after Jasmine.

Now we can start thinking about the server API. We can assume it follows a RESTful architecture (a direct consequence of choosing Rails as a backend) and uses the JSON format. Because we're managing restaurants, we can also assume that the base URL for every request will be /restaurants.

We can add two specs to the models/restaurant_spec.coffee file to make sure that both collection and model are properly setup:

...
it "should have default attributes", ->
expect(ritz.attributes.name).toBeDefined()
expect(ritz.attributes.postcode).toBeDefined()
expect(ritz.attributes.rating).toBeDefined()
it "should have the right url", ->
expect(ritz.urlRoot).toEqual '/restaurants'
...
it "should use the Restaurant model", ->
expect(restaurants.model).toEqual Gourmet.Models.Restaurant
it "should have the right url", ->
expect(restaurants.url).toEqual '/restaurants'

To implement this, we need to define two methods on the Restaurant model and the RestaurantsCollection class:

Decoupling our Backbone application from the server side makes it just another client.

This is what is needed to setup server integration. Backbone will take care of sending the correct Ajax requests. Fore example, creating a new restaurant triggers a POST request to /restaurants with the new restaurant attributes in JSON format. As these requests are always the same (that is guaranteed by the rails_sync adapter), we can reliably test that interaction on the page will trigger those requests.

Let's open the views/restaurants_spec.coffee file and setup Sinon. We will use its fakeServer facility to check the requests sent to the server. As a first step, we have to instantiate a sinon server in a beforeEach block. We will also need to make sure to restore the normal functionality right after running our specs. This is a good practice to make sure that we use the fake server only where we need to, minimizing interference with the rest of the test suite.

We can easily inspect @server.requests, an array of all the XHR requests made in the test. We check protocol and URL of the first request and ensure it matches with the expectation. If you run the spec, it will fail because our current logic simply removes the restaurant from the collection without deleting it. Let's open views/restaurants.coffee and revise the removeRestaurant method:

By calling destroy, we effectively trigger the DELETE request, making our spec pass.

Next up, the restaurant form. We want to test that every time a form with valid data is submitted, a POST request is sent to the server with the correct data. We will also refactor our tests to isolate valid and invalid attributes in two variables; this will reduce the amount of repetition that we already have. For clarity, here is the full Form submit block from views/restaurant\_form\_spec.coffee:

Instead of simply adding the restaurant to the collection, we call the create method to trigger the server save.

Conclusion

If you have never worked with Backbone and Jasmine before, this is lot to digest, however the real benefit is the possibility to work effectively on testable pieces of functionality that follow predictable patterns. Here are some suggestions on how to improve from here: