Thursday, March 17, 2016

Typescript tips & testing with Mochai & Chai

I describe how to setup a testing environment for Typescript with Mocha and Chai, using Atom as my editor and node.js for the Typescript transpiler/compiler.

This article uses Windows 7, but most of it applies to Linux and OSX as well.

To setup a test environment for testing Typescript code with Mocha and Chai, I installed:
- node.js https://nodejs.org/
- the Typescript transpiler package inside node https://www.npmjs.com/package/typescript

I use nodejs v4.1.0 but the Typescript transpiler is probably fine with other previous versions.

To install or update the typescript package on node:
> npm install -g typescript
C:\Users\User\AppData\Roaming\npm\tsc -> C:\Users\User\AppData\Roaming\npm\node_modules\typescript\bin\tsc
C:\Users\User\AppData\Roaming\npm\tsserver -> C:\Users\User\AppData\Roaming\npm\node_modules\typescript\bin\tsserver
typescript@1.8.9 C:\Users\User\AppData\Roaming\npm\node_modules\typescript

To know the latest version of Typescript compiler package available on node:

> npm view typescript version
1.8.9

You can check the versions installed with the terminal commands:

for node:
> node -v
v4.1.0

to view the node packages installed globally installed on your node.js:

> npm list --depth=0
C:\Users\User\AppData\Roaming\npm
├── bower@1.5.2
├── elm-oracle@1.1.1
├── tsd@0.6.5
├── typescript@1.8.2
└── typings@0.7.8

for the typescript transpiler installed as the command line utility, the command is "tsc"
> where tsc.exe
C:\Program Files (x86)\Microsoft SDKs\TypeScript\1.8\tsc.exe
> tsc -v
1.8.2

For the node tsc:
> where tsc
C:\Users\User\AppData\Roaming\npm\tsc
C:\Users\User\AppData\Roaming\npm\tsc.cmd
> tsc -v
Version 1.8.2

I also use Atom with the Typescript plugin to edit Typescript code https://atom.io/packages/atom-typescript . Be aware that the atom typescript plugin uses the latest version of the compiler directly from the development repository, see

https://github.com/TypeStrong/atom-typescript/blob/master/docs/faq.md#which-version-of-typescript-does-atom-typescript-use

"Which version of TypeScript does atom-typescript use?
It uses ntypescript which is just a build of Microsoft/Master. This means it's the latest and greatest of the TypeScript goodness. There is a possibility that in the future it will move to TypeScript nightlies but our current automation is working well."

Versions of Typescript differ greatly in features, so in doubt, use the "tsc" command to compile your code from the command line/terminal, you'll know exactly which version of typescript is used.

The compiler options are listed here:
https://github.com/Microsoft/TypeScript/wiki/Compiler-Options

The typescript compiler uses either the options you specify on the command line or a file called tsconfig.json. I recommend using that file, it makes compilation easier, specially with multiple files. The Atom plugin too uses it to compile your files when you save them in the editor or press F6.

the doc for tsconfig.json is located here:
https://github.com/Microsoft/TypeScript/wiki/tsconfig.json

The tsc compiler looks for the tsconfig.json file in the current directory and up the parent directories until it finds the tsconfig.json file.

------------------------------------------------------------------------
The tsconfig.json file for this simple test project is:

{
    "compilerOptions": {
        "removeComments": true,
        "sourceMap": true
    },
    "files": [
        "mocha.d.ts",
        "chai.d.ts",
        "test.simpletypescript.ts"
    ]
}
------------------------------------------------------------------------

The compiler options are optional, they are here just to show how to use them. The "removeComments" option removes the comments in the output js file. It is practical to reduce the size of the js file for deployment. The "sourceMap" option generates the source map to help debugging with the browser. Check the available options here

The TypeScript Language Specification is at
https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md

The version at the time of this writing is "Version 1.8 January, 2016". Decorators/annotations (for Angular2) have been added in 1.5 and other features are added with each release, so keep an eye on this document.

To keep it simple here, instead of using the "typings" node package (see the note at the end of the article), I just downloaded the definition files for mocha and chai. you can search for the d.ts files your project requires with this page http://definitelytyped.org/tsd/

https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/mocha/mocha.d.ts
https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/chai/chai.d.ts

I copied them in the same directory as my source file, as shown in the "files" option of the tsconfig.json file above.

For the example, I have an index.html file which sets up and run mocha, and test.simpletypescript.ts, which contains the test code using chai.

------------------------------------------------------------------------
index.html:

<html>
<head>
  <meta charset="utf-8">
  <title>Mocha Tests</title>
  <link href="https://cdn.rawgit.com/mochajs/mocha/2.2.5/mocha.css" rel="stylesheet" />
</head>
<body>
  <div id="mocha"></div>

  <script src="https://cdn.rawgit.com/jquery/jquery/2.1.4/dist/jquery.min.js"></script>
  <script src="https://cdn.rawgit.com/mochajs/mocha/2.2.5/mocha.js"></script>
  <script src="https://cdn.rawgit.com/chaijs/chai/2.3.0/chai.js"></script>

<!--
The BDD interface provides describe(), context(), it(), before(), after(), beforeEach(), and afterEach().
"context() is just an alias for describe(), and behaves the same way; it just provides a way to keep tests easier to read and organized.
-->

<!-- if not present: "test.simpletypescript.ts:6 Uncaught ReferenceError: describe is not defined" in the web console -->
  <script>mocha.setup('bdd')</script>
  <script src="test.simpletypescript.js"></script>

  <script>
    mocha.checkLeaks();
    mocha.globals(['jQuery']);
    mocha.run();
  </script>
</body>
</html>
------------------------------------------------------------------------
test.simpletypescript.ts:

var expect = chai.expect; // MUST have that line to compile

describe('Simple Mocha Test', function() : void {
  console.log("Simple Mocha Test in TS");
  it('true should be true', function() : void {
    expect(true).to.be.true;
  });

  it('1 should not be true', function() : void {
    expect(1).to.not.be.true;
  });
});
------------------------------------------------------------------------
Opening the index.html file in your browser should show:

passes: 2 failures: 0 duration: 0.19s

Simple Mocha Test
true should be true ‣
1 should not be true

Another way to deal with definition files is to "import" them in the source code like this:
------------------------------------------------------------------------
test.simpletypescript.ts:

/// <reference path="mocha.d.ts"/>
/// <reference path="chai.d.ts"/>

var expect = chai.expect; // MUST have that line to compile

describe('Simple Mocha Test', function() : void {
  console.log("Simple Mocha Test in TS");
  it('true should be true', function() : void {
    expect(true).to.be.true;
  });

  it('1 should not be true', function() : void {
    expect(1).to.not.be.true;
  });
});
------------------------------------------------------------------------
and to remove them from the tsconfig.json file:

{
    "compilerOptions": {
        "removeComments": true,
        "sourceMap": true
    },
    "files": [
        "test.simpletypescript.ts"
    ]
}


------------------------------------------------------------------------

I prefer having them in the tsconfig.json file, should I have to modify them, I do it only in the tsconfig.json file, not in every single source file. Moreover, the project dependencies are clear when the definition files are only in the tsconfig.json file.
I hope this will help to get started with Typescript testing with Mocha and Chai in the browser.

Keep typescripting.

Notes:

TSD and TYPINGS:

When working with external javascript libraries/frameworks, we need to add the *.d.ts definition files with the ambient declarations. Until recently the node "tsd" package was used to download the d.ts files. It has been deprecated in favor of the "typings" package. tsd and typings use the same definition files from DefinitelyTyped https://github.com/DefinitelyTyped/DefinitelyTyped , which holds almost all defintion files you'll ever need. If not, you can always write your own.

Deprecation notice:
https://github.com/DefinitelyTyped/tsd/issues/269
https://github.com/DefinitelyTyped/tsd
"DEPRECATED: TSD is deprecated, please use Typings and see this issue for more information."

Typings:
https://github.com/typings/typings


Typescript extension for Visual Studio:

You can also install the Typescript compiler extension for Visual Studio 2103 or 2015
http://www.typescriptlang.org/#Download

Even if you don't install Visual Studio, the Typescript compiler will be installed and you can invoke it  on the command line with "tsc". If you have the VS extension installed, you'll get a second "tesc" compiler on your system, and chances are that the VS one will be invokde instead of your node compiler. So check you Windows path and tsc version when compiling to avoid pulling your hair out. I had 3 different versions of the compiler at some point: the one used by atom, the node package and the VS one. All different versions with significant different features. To disable the Visual Studio compiler extension, remove the typescript environment variable entry in the windows PATH. That will leave the way open to the node package compiler.