Installing Jasmine is just a matter of downloading the latest Jasmine zip file, copying the library and CSS file into your application, and modifying the included SpecRunner.html file to include your source code and spec files. I’ve pushed the entire example that I’m about to discuss to our Github repository, in case you want to follow along or try things out. In particular, you may want to take a look at my customized SpecRunner.html. It’s a bit long and my changes are not really relevant to the examples I’m going to cover, so I won’t take up space by including the source code here. The point is that the setup for Jasmine is very easy, and you can use the vanilla SpecRunner they include if you don’t want to bother with more extensive customizations.
The one thing I will mention is that I’ll be using a slightly modified version of the ExtJS application configuration file from that of the live application. One reason for this is that I need to kick off the Jasmine spec runner once ExtJS is ready to go. The other reason is that I often will configure my tests to use mock data (such as static .json files), while the live application would probably be using real server URLs for loading data. My app_jasmine.coffee file looks like:
A Basic Initial Spec
To start with, I’d just like to confirm that the application actually started up correctly and that it’s set up as I expect it to be. This BasicTest spec confirms a few high-level things about my application: is ExtJS 4 set up, is my application set up, and are my DeftJS injections set up?
Jasmine is a BDD (Behavior-Driven Development) testing framework. As such, it uses “expectations” instead of the assertions you’d see in a unit testing framework like JUnit. I can see what BDD is trying to get at (make the actual tests read more like requirement statements, and push people to define the spec first and then write the tests), but honestly I don’t see it being fundamentally different from “test-driven development”. Maybe I’m just new to it, or maybe it’s just because I use pretty much the same approach in my unit and integration tests. But that’s a digression.
However you slice it, BDD expectations work pretty much the same way that assertions do. So as you can see above, I’m just confirming, at a high level, that the application is set up the way I think it should be set up.
A More Complex Spec
OK, so great. The app seems to be set up correctly. Let’s get to something with a bit more meat. The application has a top-level tab panel as it’s main view, and an associated DeftJS ViewController to go along with it. Just so you have a visual reference, here’s what the application looks like while running:
For tests involving the tab panel and its view controller, I’ll need to do some set up and clean up for each spec that runs. Jasmine lets us do this using beforeEach() and afterEach() functions:
With the setup and cleanup for the rest of the tests out of the way, I’ll start by confirming that the view and view controller are being created correctly:
Now I can move on to testing some actual behavior. One of the cool things about DeftJS ViewControllers is that they allow the view components themselves to be pretty “dumb”. The important behavior should be handled by the ViewController. In this case, I’ve got a simple method in my MainController class that will change the title on one of the tab panels:
So I’ll create a spec that makes sure this title-changing behavior works correctly:
You can see that it’s quite simple to test the behavior of ViewControllers with this kind of approach. Since a lot of code for an ExtJS application will be view-related, this takes care of a large category of testing. But what about non-view-related behavior? And what about things that trigger asynchronous activity, which is commonplace in HTML RIAs?
For example, I have a CompanyStore in my application. The store acts as a backing collection for a data grid of companies, and it loads this data asynchronously from the server. I also have a simple method in CompanyStore that will filter the loaded collection of Company objects based their “industry” property. Since filtering is such a simple task in ExtJS, it’s a small method:
The trick here is that I have to wait for the JSON data to load and the store to be populated before I can test my filterIndustry() method. Jasmine allows for this with its waitsFor() and runs() helper functions:
Basically, I’m saying “wait until the store’s collection of Companies is no longer empty, and then go on and run some additional code. In this case, that means set up the filter and then check to make sure it correctly filtered out any Companies that aren’t in the Manufacturing industry.
Running the Specs
Tests aren’t any good unless you can, you know, run them. Jasmine specs are executed right in your browser; you just load up the URL for your SpecRunner.html file. When I run the specs we just created, the output looks like this:
Hooray, they pass! I can now have a beer. Bring on the Lagunitas IPA. Or better yet, the mind-blowing Lagunitas Sucks (if there is any left in existence).