Test Driving Client-side Development with Jasmine & CoffeeScript
Introduction
As the development of our new cloud based Social CRM system has progressed we have watched the amount of JavaScript in our repository grow. Much of this code is jQuery or jQueryUI and is entirely related to the presentation layer. There are various methods and tools for automated user-interface testing available to modern web application developers but they can feel very heavyweight.
For logic in our JavaScript code we wanted a fast and lightweight framework that can make our client-side testing as painless and enjoyable as possible. That’s a tall order, and one that required a couple ingredients to achieve.
The Ingredients: CoffeeScript & Jasmine
CoffeeScript: “It’s just JavaScript”
CoffeeScript’s golden rule should be reason enough for skeptics to give it a shot. After a few minutes hacking some CoffeeScript and a short compilation later you’ll have nicely formatted, easily debuggable, pure JavaScript. You can even throw a --watch switch on the coffee compiler so that your .coffee files are compiled into .js files as you save them, automatically.
A few things to enjoy about CoffeeScript
- Significant whitespace means less
{}, optional;, improved readability and help fending off other code smells. It also means that you can clearly define more complex objects.
e.g.,
1 2 3 4 | |
- Operators which help eliminate typical JavaScript operator confusion like
is,isntandof - New Operators like
?:(Elvis!) andin - List comprehensions
- Default values for function arguments
- Simple class definitions- never type ”prototype” again, unless you’re into that kind of thing
- String variable interpolation
- Support for a REPL
- JavaScript Lint compliant generated code
It is also worth noting that CoffeeScript is never required to be packaged, deployed or run on the client-side, however. There is never any run-time interpretation of CoffeeScript.
The expense of CoffeeScript
- An extra installation step
- An extra compilation step
- If you choose to version compiled JavaScript, redundant files in your code repository
CoffeeScript: “It’s just JavaScript.”
This bears repeating because it really is the most important aspect of CoffeeScript! It means that it can be used with any existing JavaScript library. We’ve chosen a behavior-driven development (BDD) framework like Jasmine to make our lives easier in this case.
As a general rule, wherever you can write JavaScript, you can (more) easily write CoffeeScript!
Jasmine
Jasmine is a JavaScript testing framework that lifts great features from some other well-known and established frameworks like ScrewUnit and RSpec. It’s lightweight and can be run headless in your favorite continuous integration server. Jasmine supports testing asyncronous code and has extensible reporters for custom test reports to fit your needs.
The syntax Jasmine offers is relatively simple and readable, too. But like many other robust JavaScript frameworks, multiple and nested function callbacks are the rule, not the exception. If you begin to test-drive some jQuery code you’ll soon find yourself neck deep in )}; anonymous function callback hell.
Mixing in CoffeeScript’s pleasant syntactical and semantic improvements can help pull us out of it.
CoffeeScript & Jasmine Taste Great Together!
First, let’s take a look at a simple and small Jasmine spec written in CoffeeScript.
1 2 3 4 5 6 | |
That is very readable but it’s mostly Jasmine that’s responsible for that fact in this simple case, not CoffeeScript. Next we will take a look at a slightly more involved Jasmine suite aimed at testing some jQuery code to see the power CoffeeScript adds to our recipe.
Let’s test-drive a bit of jQuery that updates the background color of a div on a click event. Our Jasmine suite with a single spec might look like this:
1 2 3 4 5 6 7 8 | |
Against which we might write this passing jQuery CoffeeScript code:
1
| |
(Note: we’re binding with the live event handler attachment in this short example because we’re appending the div in our spec- after document.ready() has fired.)
Without CoffeeScript our jQuery code would look something like this:
1 2 3 4 5 | |
Not bad, but it certainly lacks the elegance and readability that our CoffeeScript one-liner has!
Now let’s say we’d like to add a form with a named set of radio button inputs which update a span with the value of the selection to our div.
Our test code now becomes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | |
We’ve refactored our DOM manipulations to beforeEach and afterEach blocks and wrapped a spec regarding #my-form only in its own nested suite. This might seem like overkill for a single spec, and it probably is, but when you start writing many specs it really cleans up the test report readability. Clean test reports make it easier to recognize and fix broken tests faster and easier, which is what test-driving is all about.
Finally, our production code under test bloats to the following:
1 2 3 4 5 | |
Not bad! This was a very simple example, but I hope it clearly illustrates the potential that the combination of CoffeeScript and Jasmine have for reducing client-side testing overhead.
Enjoy!
CoffeeScript brings to the table an improved, clear syntax and some powerful semantic features over JavaScript all while remaining, “just JavaScript.” Jasmine offers an elegant behavior-driven development domain-specific language for testing and the extensibility to support your working environment. Adding one to the other is very easy, and the result is just too good to deny!