Jonathan's Page

Jasmine & ExtJS' MVC: A Love Story

Commentsajax, bdd, code, extjs, html, jasmine, java, javascript, selenium, sencha, tdd, tech, testing, unit testing, user interface, web2 min read

I've been looking for a way to perform unit tests on my new project's UI code. The projects I worked on before were practically prepackaged and handed to me — Java has a pretty mature testing and build suite: JUnit and Maven. My current project is 99% JavaScript, and there isn't a defacto test suite for that. Googling around has led me to several testing tools, such as Selenium and JSpec. I even began digging deeper into some of them, but then I discovered Jasmine, and that Sencha developers use Jasmine. It was a sign.

So, with Jasmine downloaded, I began playing with it and trying its examples. I loved it. Pure JavaScript solution with no external dependencies; I could simply hit the test page and off the tests go. I'm sure with a little more digging it would work in a offline/build/cli environment with PhantomJS or node.js. The only hurdle I had left was how (and what) I wanted to test. Not every file/class in this UI stand alone, or the application state. How would I want to simulate the server? So many things to sort out before I was satisfied that I had a solution.

Then I had an idea. What if the tests ran under their own version of Ext.Application? My main app.js file was simple: it defined the "Application", its namespace, its path, the controllers and the launch method, which, for me, only initiated the login sequence. Basically, my idea was to copy the app.js to app-test.js, then copy index.html to test.html (this application is using the ExtJS4 MVC project layout).

So, here's my folder structure. It will look a little familiar as I've based this example on the documentation's example layout.

Folder Structure

So, we have the jasmine package under app-test/lib, and mock data under app-test/mock and all the test suites ("specs") under app-test/specs.

index.html and test.html look very similar, except that test doesn't include the loading markup and loads the jasmine scripts and app-test.js instead of app.js.

Those familiar with either ExtJS or Jasmine can probably see where I'm going with this. Jasmine doesn't start automatically. It has a bootstrap method that you call to run the tests and show the output. The Jasmine examples always show the test-runner.html with a script block in the body that runs as soon as the browser hits that block. This isn't what we want for this application. Not all of the resources and code will be loaded, at least not consistently at this point. So we have the app-test.js define the Application in "test mode." Maybe a visual is better in this case.

This is the main entry point and the app.js.


Now this is what goes into test.html and app-test.js:


Next, what about those pesky server calls? Lets reroute those to our mock directory. In my application all Ajax calls use a url in a config for the host. This allows us to change the host without deploying to a new server. So, because of this, its super easy to detect a server call: its prefixed with the config value of the host and I've set the mock config object above to have the host set to "test:", so here is my hook:

In summation, what does this get us? We now have a way to isolate anything we want in the application and test the heck out of it. We can test integration of components/controllers/models, or individual components.

Bam. mike drop