Unit Testing in javascript is usually pretty straightforward. You pick a framework like Jasmine or QUnit, you write some tests, and you run them in your browser or in something headless like PhantomJS.

I prefer Jasmine, due solely to exposure, for my test framework. I prefer PhantomJS for running my tests because it is fast and can be done from the terminal, or other browser-less environments like your SSH-to-your-server.

Durandal+Jasmine presents two challenges to the standard setup here.

Promises, of the Q variety at least, always run asynchronously (meaning they will be on the next tick no matter what). We don't want to muck with the internals of Q and make the promises synchronous, because that would invalidate our test results.

The framework that Durandal provides is under-equipped to handle these problems. At the time I am writing this, it actually has a severe problem that causes several tests to break: different test groups are all run in the same context, and pollute each other!

The first problem is easy enough to solve. Jasmine natively has some tools for handling async tests, but they are awkward and require a lot of biolerplate. Derick Baily has written an excellent plugin for Jasmine called Jasmine.Async which wraps it up nicely.

The second problem is a bit trickier.

Organizing our code

All of the code I am about to show you assumes your test directory looks like this:

I organize them this way because once it's set up, I don't need to change anything in the lib folder. The tests are what I care about, so I want them seperate and visible. We will cover what each of these files is in turn.

Creating a 'Spec' file for PhantomJS

PhantomJS runs its tests from a Javascript file, commonly called the spec file. Our spec file needs to load Jasmine, Jasmine.Async, any non-AMD code our app requires (in my case the asbolutely wonderful SugarJS and the Q library), configure RequireJS and Durandal, and finally run our tests. I am also going to be using the special jasmine.console-reporter provided by the Durandal test framework, with a few personal modifications.

I split the spec file in to two parts, because adding javasscript to the page via Phantom's javascript API is clunky. I just use spec.js to order the instructions, and I use spec.html to setup the environment.

Basically, this file tells Phantom to locate all of the test specs in the parent directory. Then it creates a promise for each test that loads the spec.html, connects the console-reporter, requires the durandalHarness (more on this later), and run the tests. Then it chains all the promises together, and runs the whole thing.

The script tags are pretty straightforward. They are running from phantom, so they are relative to the current directory. For our project code, we have to back out and go into the source folder. Note here that these paths are written as if source directly contains your Durandal code, and this is probably not the case. Adjust your paths accordingly.

the require.config might look a bit confusing. The baseUrl needs to be the app directory so that all the string dependencies in your Durandal modules have the same "relativity" they would as if they were running normally in your browser. But then we need to be able require in our tests, so we need paths to go up and back into the tests directory.

Finally, we create runTests() that the durandalHarness will call once Durandal has finished its app.start() process.

This is basically going to mirror your main.js file. You need to have Durandal install the plugins so that your code that interacts with them will behave the same way its going to behave in the real-world. You can add any additional configuration you need before calling runTests().

Our environment is setup now. We can write a test, and run it from the terminal. Here is an example test, just to give you an idea.