Sunday, December 8, 2013

Running Karma Tests for TypeScript Node.js Code in WebStorm 7

After getting up and running with TypeScript Node.js development in WebStorm, I was pretty confident that I had everything set up and ready to go for my next project, I wanted to write some tests and realized I had no idea how to do that. I've just worked out a nice solution and my initial googling didn't come up with anything so I've decided it's worth a post.

My searches started out well, I found this blog post which goes through testing JavaScript using Karma and Jasmine and shows off some neat WebStorm integration, but this was written with "vanilla" JavaScript in mind, so even though it works with transpiled TypeScript, it doesn't work with Node.js modules. The reason is because it's running in a browser, so you can't pull in node modules using CommonJS-compiled TypeScript code. I briefly experimented with using AMD as the module system and getting the browser to use RequireJS, but that would have required me to have two different transpilations of my TypeScript code, and I couldn't get it to work anyway.

After a bit of poking around, I'm almost certain that "the way" to run jasmine Node.js tests is to use jasmine-node in place of the built-in Karma support in WebStorm. I figured I would just run jasmine-node from the terminal and deal with an un-integrated test runner, but I really wanted to be able to debug through my code while the tests were running. The way I've done this before was to use node-inspector, so I started searching around for a way to get that working with jasmine-node, and I found this StackOverflow question. The answer points out that jasmine-node is just an alias for a normal Node.js app, so I figured I would just add that as a Node.js run/debug configuration, and surprise surprise everything worked perfectly.

For posterity, here are all the steps I took:
  1. Create a new empty WebStorm project.
  2. Make a simple TypeScript file that we can test:
  3. // File: Roster.ts
    export class Person {
     constructor(public name:string) {}
    }
    

  4. Add the TypeScript file watcher, fix it by adding "--module commonjs" to the arguments.
  5. Add karma-jasmine as an external library as shown in the JetBrains blog post video so that autocomplete and code generation work for the test spec files.
  6. Get the jasmine TypeScript definitions from DefinitelyTyped.
  7. Make a simple test, referencing the TypeScript code and jasmine definitions:
  8. // File: test/PersonSpec.ts
    /// 
    /// 
    
    import p = require("../Person");
    
    describe("suite", () => {
     it("should be true", () => {
      expect(true).toBe(true);
      var person = new p.Person("Joe");
      expect(person.name).toBe("Joe");
     });
    });
    

  9. Make a new Node.js run configuration to run the tests, use the node_modules\jasmine-node\lib\jasmine-node\cli.js file as the JavaScript file (this can be either local or globally installed via npm), and the test folder as the application parameters.
  10. I also suggest making another run configuration that is identical except for having an additional "--autotest" application parameter before the test folder. This will run in the background and continually re-run tests whenever a change is detected in the source code.
Now when you want to run tests or debug through the test, you can just use one of these new run configurations.

Thursday, December 5, 2013

Following Along with the WebStorm 7 Demonstration Video

As I mentioned in my last post, I was thinking about starting a new project using Node.js, and this video for the new features in WebStorm 7.0 caught my eye:



It looks like a very slick IDE and I was looking forward to trying it out, but I ran into a whole lot of little problems when I tried to follow along. I'm pretty sure I've figured most of them out now, so I thought I'd try to go through the entire video and explain how to follow along with it.

First things first - making Roster.ts (0:00 - 0:30). This demonstrates the automatic compilation of TypeScript, so you'll first need to make sure TypeScript is properly set up. The file is created using the alt-insert shortcut, which lets you type in the type of file to create followed by the name of the file. When you first create a TypeScript file, you'll get a prompt about adding a File Watcher, which is what will automatically compile your TypeScript into JavaScript (along with a map file so you can debug through the TypeScript code). The first problem I encountered was that I had installed TypeScript 0.8 via an executable a while ago, so even though I installed the latest version (0.9.1-1) using npm, the file watcher was using the 0.8 version that was stored in a different location. Make sure you check that the watcher is pointing to the right file by running the compiler with the -v flag which will print out the version number. The second problem I encountered was that I kept getting the error "error TS5037: Cannot compile external modules unless the '--module' flag is provided." After a bit of module confusion as I mentioned in my last post, I realized that since we are writing Node.js code, we should specify that tsc should use the CommonJS module system, which you can do by editing the file watcher and adding --module "commonjs" to the arguments. With that confusing diversion dealt with, I was able to write up the Roster.ts file with the autocomplete working as it shows in the video. One small comment is that in the video they use a capital-cased String rather than a lower-case string, but that is easily changed.

Next is server.ts (0:30 - 1:43). This file uses some Node.js packages, so there are two "hidden" things to set up here. Firstly, you'll need to make a package.json file that sets up dependencies for the app. This example only uses express and cors, and we don't need to be strict about the version, so you can use the following file:
{
    "name": "application-name",
    "version": "0.0.1",
    "dependencies": { "express": "*", "cors": "*" }
}


Now you just need to run "npm install" from your project directory to pull in the required libraries. There are a few other ways to do this, you could just npm install the packages individually or use the Node.js and NPM settings, but keeping it in the package.json file means that we will be able to install the project in other places easily.

The second piece of setup is DefinitelyTyped, which is a set of files that contains the definitions for many different npm packages, so that we can compilate and use code completion for those packages. This can be downloaded or added as a git submodule using their github repo, or we can pull in individual definitions by going to the JavaScript -> Library settings and Downloading from the TypeScript community stubs section. I prefer to use a git submodule so that it's easy to update the definitions. I do like the idea of the community stubs, but as far as I can tell you need to copy and paste the file (renaming it in the process) into your projects main directory structure before you can use them properly, and that's too much work for me.

With this setup done, the creation of the server.ts file goes about as well as it shows in the video but there are some hidden tricks. I'm not entirely sure, but I think the magic that translates "ref" into "/// <reference path=""/>" is a custom Live Template, which I was able to add by making "ref" an abbreviation for "/// <reference path="$END$"/>". The extra "find relative references" magic can be conjured by using ctrl-space (possibly twice), which will bring up the list of relevant files. The next trick which automatically inserts a variable for "new jb.Roster()" is called Extract Variable, and can be accessed using ctrl-alt-v. One thing I couldn't get working was the explicit typing for ExpressApp/ExpressServerRequest etc., which I guess has had a change in name since the video was made. The IDE is smart enough to infer the type from the context so it's not a big deal. And for server.ts's final trick ... I guess it's some more Live Templates that are converting "get!" and "post!" to some pre-built function skeletons.

"Debug Node with ease" (1:43 - 1:58) really is as easy as they show (as long as you have the right npm packages installed), but "Test REST services" (1:58 - 2:30) is a bit trickier. The first thing to note is the "Enter action or option name" dialog which you can summon using ctrl-shift-a and use to find just about anything - in this case "test rest" opens up the REST client. Before it works as shown in the video you'll probably need to change the port and path and ensure that you've added the "content-type: application/json" header. Once that is sorted out though, take some time to play around with the pain-free TypeScript debugging, it really is pretty amazing when you think about it.

Now we get to the client side, the file app.ts starts out as a pretty standard AngularJS app, written with the assistance of the auto-completion and templates we've seen before (2:30 - 3:25). AngularJS is an awesome framework for client-side code but I'm not going to go into it here, if you want more information check out their website. The only note I have for this section is that my version of app.ts had a compilation error "The property 'message' does not exist on value of type 'AppCtrl'", which was easily fixed by adding message as a public variable on the class (public message:string;).

The next file that is created is a HTML file, but one that is created using "Emmet live templates" (3:25 - 3:40). This is something I have never seen before, but it looks like a bunch of shortcuts that expand into full HTML, nifty! It looks like it takes the best part of Jade - not needing to write HTML - with the added benefit of producing HTML rather than the sometimes confusing Jade markup. These are configured as Live Templates, so the usage and configuration is the same as the "ref" template we saw earlier. Find relative references also works inside script tags, so that is a few more keystrokes you can save here. But wait, what is this bower_components folder and where does it come from? This is another technology I've never seen before, but my minimal research leads me to believe that it is basically npm but for client side libraries. You create a bower.json file, specify the libraries you want to install, then run "bower install" to pull the files into your project (after installing it using "npm install -g bower"). This example only uses angular and angular-resource, so we can use the following (strangely familiar) file:
{
    "name": "application-name-client",
    "version": "0.0.1",
    "dependencies": { "angular": "*", "angular-resource": "*" }
}


Now the files can be found, and we can start putting some AngularJS into the HTML (3:40 - 3:55). As hinted at in the video, there is auto-complete for Angular directives, but it requires a plugin. To install it, go to the Plugins section of the settings, browse the repositories, and search for and install the AngularJS plugin. After restarting, the auto-completion should be working as shown in the video. I'm not sure what is converting "bi" to "{{}}" but I'm just going to assume its another custom template and move on.

The next part demonstrates how to start a debugger on the client as well as the server (3:55 - 4:25), which is pretty easy to follow along with but you might need to install the ExtensionJetBrains IDE Support Chrome extension. After a small change, we realize that the app dependencies aren't loaded correctly, so there is a bit of a detour to go an install that package, which is again easy to follow (4:25 - 4:45).

Next is some demonstrations on how to use browserify, which is yet again something I had to look up. A high level outline is that it looks like something that lets us write CommonJS/Node.js style require/export code in client-side code. Browserify can parse this code and use it to generate a bundled javascript file that can be included in the html. I'm not sure why this would be preferred over compiling TypeScript using the AMD module and using RequireJS to load the dependencies, but it does look pretty easy. The video shows a few different ways to call browserify (4:45 - 5:40), you can do it by running an interative terminal (alt-minus), or apparently through a "simpler command window", but I couldn't find that. You can also set up a file watcher that will detect when a change is made to app.js and automatically run browserify on it, similar to how JavaScript is created whenever you modify a TypeScript file. This is also easy to follow as long as you pause the video quite a bit so you can actually see what's being clicked on. With the bundle generated, we can now run and inspect our code.

The rest of the video is some code that you'll need to know a bit about AngularJS to understand, but it all works as shown (5:40 - 6:50), and that pretty much wraps up the video! Two things I still don't understand are how to get the camel-case expansion to work (e.g. RR => RosterResource), and what that "jump-to" shortcut is or what it's doing, but I'm sure I'll figure that out eventually.

Now to work on a real project in WebStorm!