TypeScript unit testing with Visual Studio 2012, jasmine, backbone, sinon, require and testem on Windows 7

This blog is a starting point for those who are just getting into TypeScript development (like all of us I guess), and need a workable unit testing framework.

While my initial preference was to try and integrate TypeScript with Chutzpah, I ran across a few issues where changes to TypeScript files were not being picked up by the Test Discoverer.  Unit testing therefore with Chutzpah will need to wait until official support has been added.

The full solution used for this walkthrough can be downloaded from skydrive (TypeScriptSampleApp.zip) here.

UPDATE 10th October 2012:

Many thanks to Jim Newbery, over at tinnedfruit for this excellent tutorial, which has been the reference that I have been working from.  I have just updated the download to include tests from Part 1, Part 2, and Part 3.

Software Pre-requisites

This walkthrough uses the following software:

  • TypeScript : Download the installation media (for Windows) here.
  • Node.js
    • Node.js is a platform built on Chrome’s JavaScript runtime for building fast, scalable network applications.
    • It is a pre-requisite for testem, and can be downloaded here.
  • Jasmine.js :
    • Jasmine is a behaviour-driven development framework for testing JavaScript code.
    • The github wiki site is here.
  • Underscore.js:
    • Underscore.js is a pre-requisite for Backbone.js, and can be found here.
  • Backbonejs:
    • Backbone.js is a popular JavaScript library that gives structure to web applications.
    • The home page is here.
  • Sinon.js:
    • Sinon.js is a mocking and spying framework for JavaScript testing.
    • The home page is here.
  • Require.js:
    • Require.js is a JavaScript file and module loader.
    • It can be downloaded from here.
  • Testem:
    • Testem is a test runner from Toby Ho which provides an auto-re-run-on-save for test driven development.
    • Toby’s blog post on testem, including links is here.

TypeScript Setup

The TypeScript installation process is straight-forward, simply download the installation .msi from and run it.

Create a new TypeScript Project

From within Visual Studio, create a new project using the HTML Application with TypeScript template.

TypeScript_newProject

Project Structure

Testem will run unit-tests found in a particular directory, and by default it is the current directory that testem is launched from.

Unfortunately, this will cause errors when JavaScript library files and includes are in different directories.  For this reason, I have structured my project as follows:

\  (root directory)

  • This is the base directory of the project.
  • The following files should be present here:
  • testem.yml
    • this is the testem configuration file, and points to the various directories as below.
  • SpecRunner.html
    • This is the standard Jasmine SpecRunner.html file from the source, and has been modified as per the various directories below.
    • Note that I have included this file for manual debugging purposes.

\lib

  • the lib directory will contain all required JavaScript library downloads ( except for jasmine ).
  • I have had problems with the Testem runner if the jasmine.js files are in this directory.
  • the following files should be present in this directory:
    • backbone.js
    • require.js
    • sinon-1.4.2.js
    • underscore.js

\lib\jasmine

  • this folder will house the jasmine.js downloads – and are used only for manual de-bugging purposes.
  • As mentioned before, having these files in the parent \lib directory will cause problems with testem.

\test

  • this folder contains TypeScript testing files

\tests\sub_folder

  • This folder contains more TypeScript testing files – it is here simply to test that Testem can traverse sub-folders when looking for tests.

\modules

  • This folder contains the TypeScript .d.ts modules that are referenced in the tests.
  • As your project grows, you will be updating the module files to provide better type safety for external JavaScript libraries
  • The following files should be present in this directory:
    • Backbone.d.ts
    • Jasmine.d.ts
    • require.d.ts
    • sinon.d.ts

A screenshot of the Directory structure from Visual Studio is as follows:

TypeScript_VisualStudio_snapshot

Running Testem

Once testem is installed, simply fire up a command prompt, and change to the root directory of your project.

Before we run testem, lets have a look a the testem.yml file a the base of the project directory:

framework: jasmine
src_files:
- lib/require.js
- tests/**/*.js
  • Note that we are using jasmine as the testing framework.
  • src_files points to the directories in which to find tests, as well as javascript files that are required for each run.
    • by using lib/require.js, we can inject further required javascript files into our tests as dependencies.
    • tests/**/*.js specifies that all javascript files in the tests directory, and any sub-directories will be scanned for tests.
Fire up testem by running testem on the command line.

You should see testem start, and then show “Waiting for runners…”

TypeScript_testem_1

Now fire up a browser, and type in the url shown in the top-left-hand corner of testem.  In this case, it’s http://localhost:7357

Congratulations, your unit tests should now run.

TypeScript_testem_2

And the testem runner:

TypeScript_testem_3

Anatomy of a test

Lets have a quick look at the code of a sample test.

Firstly, we need to include references to our modules in order for TypeScript to allow us to compile our tests:

/// <reference path="../modules/Jasmine.d.ts" />
/// <reference path="../modules/require.d.ts" />
/// <reference path="../modules/Backbone.d.ts" />

TypeScript Modules

As your project matures, and the list of functions you are using extends, you will need to update these module files with function signatures that match any function or property that you are accessing from and external library.

If we look at Jasmine.d.ts, we will notice that it has function signatures that cover the describe, it, expect, beforeEach and afterEach functions:

// module for Jasmine

declare module describe {
    export function(testDescription: string, f: Function) : any ;
}

declare module it {
    export function(testDescription: string, f: Function) : any ;
}

declare module expect {
    export function (actual: any): any;
}

declare module beforeEach {
    export function (f: Function): any;
}

declare module afterEach {
    export function (f: Function): any;
}

The test itself:

Lets now have a look at the code for a standard jasmine unit test:

describe("Jasmine_ModelTests:", function () {
    it("should pass a simple test", function () {
        expect("test").toEqual("test");
    });
});

Pretty self-explanatory.

Using require.js in tests that target further frameworks:

The following test is using backbone.js as a framework, and therefore needs to include underscore.js and backbone.js as test dependencies:

require(["lib/underscore.js","lib/backbone.js"], function () {
    describe("Jasmine_ModelTests_with_require:", function () {
        it("should pass a simple test with backbone", function () {
            var model = new Backbone.Model({
                name: "myName",
                title: "myTitle"
            });

            expect(model.get("name")).toEqual("myName");
            expect(model.get("title")).toEqual("myTitle");
        });
    });
});

Note here the first line of the test is a call to require to load both underscore.js and backbone.js before the test begins.

TypeScript require function call structure

One important thing to note here is the structure of the function call.
According to require.js documentation, the function call should be as follows (outlined in red):

require(["lib/underscore.js", "lib/backbone.js"], function (underscore, backbone) {
    // underscore and backbone are now fully fledged namespaces
});

Note that this convention will allow code within the require block to use underscore as a namespace, and backbone as a name space as follows:

var model = new backbone.Model({
                name: "myName",
                title: "myTitle"
            });

Unfortunately, this will break TypeScript’s auto-completion and Intellisense, as it cannot find a reference to backbone in any of the module definitions.

For this reason, it is better for TypeScript to use the function call without specifying namespaces, as follows:

require(["lib/underscore.js","lib/backbone.js"], function () {

});

Finally

The purpose of this blog has just been to get an automated unit testing framework running with TypeScript.
My understanding of the TypeScript language annotations, as well their use – will grow in time, so I would welcome any comments or suggestions that you have in this regard.

Have fun,
– Blorkfish.

Advertisements

3 Responses to TypeScript unit testing with Visual Studio 2012, jasmine, backbone, sinon, require and testem on Windows 7

  1. Sop Killen says:

    Just wondering,
    isn’t the code completion on backbone broken because you don’t specify what type the backbone argument is?

    Haven’t tested this, but maybe if you had something like:
    require([“lib/underscore.js”,”lib/backbone.js”], function (underscore: Underscore, backbone: Backbone) ?

  2. Would have been nice if were included testr,js for mocking require js modules. https://github.com/mattfysh/testr.js

  3. Pingback: TDD in typescript | DiscVentionsTech

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: