Testing CoffeeScript with Jasmine

We all know how important it is to test our code, but how should we approach that when we’re writing our code in CoffeeScript?

Well I’ve been using the Jasmine JavaScript testing library from Pivotal Labs to handle this. Here’s how.

Scenario

For this scenario, we’ll be writing tests for a simple Calculator object. The Calculator should be able to add, subtract, multiply, and divide two numbers.

Setup

To begin, let’s make sure our environment is set up.

I’ve set up my sample project as follows:

Our sample project structure.

In our initial project we have:

SpecRunner.html
Our HTML file that will execute our tests.
js
Folder containing our compiled JavaScript code.
js/src
Folder containing our CoffeeScript source.
spec
Folder containing our compiled JavaScript specifications.
spec/jasmine
Folder containing the Jasmine library files.
spec/src
Folder container the CoffeeScript specifications.

You can grab the initial project files from my GitHub repo.

The SpecRunner.html will be pretty similar from project to project. Looking at the HTML (gist), you can see lines 10 – 14.

<code>&lt;!-- include source files here... --&gt;
&lt;script src="js/calculator.js"&gt;&lt;/script&gt;

&lt;!-- include spec files here... --&gt;
&lt;script src="spec/calculatorSpec.js"&gt;&lt;/script&gt;
</code>

At the start of this block we load the source files. In our scenario, this will be our compiled calculator JavaScript file.

The second block is where we load our compiled specification files.

Once the Spec Runner has been updated, simply load it in your browser. Without defining any specifications or our calculator files, it’s good to see the tests pass.

Our first test passes

First Specification

Now that we have Jasmine wired up, let’s start writing our specification.

Let’s make sure our simple calculator can add:

<code># calculatorSpec.coffee

describe 'Calculator', -&gt;

    it 'can add two positive numbers', -&gt;
        calculator = new Calculator()
        result = calculator.add 2, 3
        expect(result).toBe 5
</code>

I love that CoffeeScript reads like English. Even if you have never seen CoffeeScript before, you can see that this specification describes a calculator and that it should be able to add two positive numbers.

The test itself creates a new calculator instance, gets the result of adding 2 and 3 then asserts an expectation that 2 + 3 should be 5.

Let’s get CoffeeScript watching our spec/src folder to get it to compile the CoffeeScript specifications.

  > coffee -c -w -o spec spec/src & coffee -c -w -o js js/src 

Once our spec is built, refresh the browser. BOOM! It blows up.

Our test fails.

Hmm, the error says something about not being able to find a variable called Calculator. Well of course it can’t find it, we haven’t created it yet!

Let’s do that now.

<code># calculator.coffee

class @Calculator
</code>

We refresh our browser and it still fails.

Our test fails again.

This failure is complaining about an undefined function, add. Let’s write that now.

<code># calculator.coffee

class @Calculator
    add: (x, y) -&gt;
        x + y
</code>

Save it, refresh the browser and voila! It passes.

Lovely green tests.

Finish This Up

Ok, we’ve been through an entire red-green cycle. I don’t see anything to be refactored at this time. Let’s flesh out the rest of our spec file.

calculatorSpec.coffee

<code>describe 'Calculator', -&gt;

    it 'can add two numbers', -&gt;
        calculator = new Calculator()
        result = calculator.add 2, 3
        expect(result).toBe 5

    it 'can subtract two numbers', -&gt;
        calculator = new Calculator()
        result = calculator.subtract 5, 3
        expect(result).toBe 2

    it 'can multiply two numbers', -&gt;
        calculator = new Calculator()
        result = calculator.multiply 3, 4
        expect(result).toBe 12

    it 'can divide two numbrs', -&gt;
        calculator = new Calculator()
        result = calculator.divide 12, 4
        expect(result).toBe 3
</code>

Save it and refresh the browser. We see that we have failures for our subtract, multiply and divide just as we should have expected.

Our test fails again.

Let’s get it to pass by updating our Calculator class.

<code># calculator.coffee

class @Calculator
    add: (x, y) -&gt;
        x + y

    subtract: (x, y) -&gt;
        x - y

    multiply: (x, y) -&gt;
        x * y

    divide: (x, y) -&gt;
        x / y
</code>

Save it and refresh once more. Ah, there they are, passing tests.

Passing tests again.

Refactoring?

So, looking at our specification we can see some duplication. Each test is creating a new instance of our calculator. Let’s refactor that out into a beforeEach block. This will ensure that our calculator object is instantiated anew before each test runs.

<code># calculatorSpec.coffee

describe 'Calculator', -&gt;
    calculator = null

    beforeEach -&gt;
        calculator = new Calculator()

    it 'can add two numbers', -&gt;
        result = calculator.add 2, 3
        expect(result).toBe 5

    it 'can subtract two numbers', -&gt;
        result = calculator.subtract 5, 3
        expect(result).toBe 2

    it 'can multiply two numbers', -&gt;
        result = calculator.multiply 3, 4
        expect(result).toBe 12

    it 'can divide two numbrs', -&gt;
        result = calculator.divide 12, 4
        expect(result).toBe 3
</code>

Let’s save and refresh to make sure our refactoring did not cause problems.

Still green.

You can view the completed sample on GitHub in my repo.

Tagged: ,

  • Mathieu Brouwers

    Good tutorial, finally seem to get Jasmine working rightfully with CoffeeScript, 2 annoying thing were the indents don’t follow in a copy paste and the ‘- >’ are translated to ‘- & g t ; ‘
    Thanks!