AngularJS for jQuery Developers – Part 3: Modules

In part 1 we talked about Angular JS compared to jQuery, direction instead of manipulation. Then in part 2 we reviewed that AngularJS wants you to be able to do virtually everything with JavaScript, including test.

AngularJS for jQuery Developers – continued

Let’s get down to some coding shall we? Our original Angular JS file looked like this:

While it feels like we might be far away from our original topic, AngularJS for jQuery developers, we are just about to dive into the heart of it, how to make test part of our regular development. As a refresher, let’s take a second to look at what we have in our angular module..

ng-app tells the angular engine that this block contains an angular application.
ng-init runs some initialization code. Here it creates our trivial model, the variable named name.
{{ name }} is a handlebars like template substitution. The angular engine replaces the double braces with the results of the expression. You could just as easily have put {{ 1 + 2 }} inside the code and it would have evaluated the expression and put the number 3 into the document and rendered the answer in the browser. (Try it if you like).

Finally, the <input> tag is perhaps the most interesting. After specifying a text field, we use the attribute, ng-model. This binds the input element to the model.

But what if we want to do something more complex? Chances are we want to create a controller.

Making our first controller

First, we need to remove the ng-init and introduce the ng-controller directive.

The HTML File or VIEW Code

Here is the html file, updated to use the most trivial controller possible:

So what changed? First, we moved the ng-app to the <html> tag. Now we replaced the ng-init with the ng-controller directive and told it which controller to look for.

Also, I moved the script calls to the end of the <body> tag which is fairly common with Boostrap applications (I’m thinking ahead). It runs just as well with the scripts at the top as the bottom, but putting them at the end prioritizes the page load.

This script also demonstrates a problem we will come back to later to address. Namely, we get a FUCO – a Flash of Unformated COntent. The template expression {{ name }} is briefly visible until the controller script runs.

The Controller Code

The controller code is overly simplified. In fact it is too simple. Why? Because it puts all of our data and functions into the global scope. We don’t want that. However, we’ve already taken a lot of time on peripheral topics and as much as I would love to talk about scope, here let’s just stay on task, getting the simplest possible controller to run.

As you can tell, the controller MyCtrl is passed a parameter named $scope. The angular framework creates $scope and passes it to the controller. The scope of $scope is the block where the controller is active. If we assign any values to any members of $scope inside our controller code, those members will show up as variables inside the body block. Hence the name in the ng-model attribute is referring to the $scope.name inside our controller.

If you want to make Javascript functions available to your HTML page, you would assign those to the $scope variable as well inside your controller.

You could then call {{ mySquare(2); }} to print the number 4 in your document. Trivial, but you get the point. At this point we are not concerned with the complexity of the functions, just the complexity of the relationships of how things fit together.

To test this you load the file into your web browser and look at it. I use MAMP so I am using a genuine apache webserver. In my experience loading from a file does not always work and can cause more problems then it is worth. Besides, MAMP pretty closely imitates my target environment, an inexpensive shared linux host like those available from (1and1, Dreamhost, and A Small Orange).

Despite the fact this javascript controller is a tad simple, now is a great time to introduce the idea of testing. Notice that our “controller” has no idea of the HTML document structure. That means it should be easy to test this functionality independent not only of the browser, but of the application itself. In short, we should be able to test it as an isolated unit.

So how would we go about doing that?

To answer that question we are going to touch three technologies:

  1. Jasmine
  2. Node.JS
  3. NPM

Hello Jasmine

Jasmine is a nifty unit test framework for Javascript. What makes it nifty is that it lets you write JavaScript tests with Javascript. Do you sense a theme here?

By focusing on one language we just might be able to make our lives easier… maybe.

We are going to look at Jasmine 1.3.1. Jasmine 2.0 is in development but none of the tutorials I had found worked with it so I am sticking with 1.3.1.

There are probably many ways to do this, but here is how I did it. I found this tutorial: How Do I Jasmine. It refers to a stand alone version of the library. I wanted to learn Jasmine before I got into node.js and npm. It turns out the standalone version of Jasmine is a little hard to find. At the time of writing this, I located the files on Github.com/pivotal/jasmine under the Distribution Tab.

When you download the library and unpack the zip file you get the following:

The SpecRunner.html is an html file that loads the source files and and the specification files (test suites). It then runs the Javascript tests against the source files and displays the results in your browser.

The output looks like this:

Jasmine_Spec_Runner

The SpecRunner.html file looks like this:

So let’s review. You write your javascript controller. You then write a test suite for that functionality. You include both the controller file and the test suite (called a spec) in the ScriptRunner.html file and the simple act of loading this document will test your function.

Let’s try it.

A Trivial Test File for a Trivial Function

So how do we write test scripts? By using three key Jasmine functions:

  • describe()
  • it()
  • expect()

These functions will be the backbone of your testing tools. The describe() function creates a scope for your testing, and will group a number of tests into one logical block. The it() function logically handles a single test or specification. The expect() function tests the results of your functions to make sure they behaved as expected.

Here is a prototypical Jasmine script:

Let’s break this down.

describe is a function that takes a meaningful label and associates it with an anonymous function. This manages Javascript’s scope (scope is a really big deal in Angular development). Then comes the test. The it() function also takes a meaningful label and it is attached to another anonymous function. This is the test. The expect() function determines whether or not a test passes or fails.

In our first example, the test passes. If a test fails (say edit the expects() to be different) and this is what you get:

Jasmine_Spec_Runner-2

Failing a test immediately raises the red flag.

The Big Idea

The big idea is that if you consistently test your software, you can catch bugs before they are hard to find. Expanding your test suite as you develop will make it easier to implement with confidence. As we expand our modules functionality we are going to also expand our suite of tests.

Controller Test

So how do we test our simple controller?

Copy the Jasmine 1.3.1 folders into your project. We want the SpecRunner.html file in the root folder. Source files go into the src directory, Spec files go in the Spec directory.

Now let’s write a test for MyCtrl. Since it does one thing, we only need one test. Create a file called MyControllerSpec.js and enter the following code:

This test file contains a describe() function call which groups together all the tests. It contains an it() function call to define our first specification.

Now why are we declaring a scope variable? Because angular will not be calling our module, our test code will. So we have to create the context. One of the biggest challenges we will deal with later is how to integrate all the dependencies from angular. Just trust for now that the smart people at Google figured all of this out and it is possible.

Finally, we expect(scope.name).toBe("World-Controller"). It almost reads like english does it not?

Try it out.

Running Your Test

Edit the SpecRunner.html file to look like this:

The source files are included before the test files.

If you load SpecRunner.html into your browser you would see…

Jasmine_Spec_Runner-4

This is just about the most trivial test you could run. One function. One specification. We are testing to see if our controller function sets the scope member name to be a certain string.

If something went wrong (say the name string was different) then you would see:

JasmineFailedTest

Go ahead and edit MyController.js and try it out. Or change the specification to expect a different string. Either one will cause the test to file.

This is great and all… but do I have to load SpecRunner.HTML?

You now have an environment where you could play around all day learning Jasmine. You can add more complexity to MyCtrl and you can write more tests. Have at it.

However, loading and reloading the SpecRunner.html by hand is hardly ideal. If we want an automated build process, manually executing tests is a problem. How do we solve that?

Enter Node.JS

I won’t waste your time on how to install NodeJS. (I do everything on a Mac, so my examples will reflect that). Please install it then continue.

To make sure you have node.js open a terminal and run

You should get a version very similar to the one shown in the example. What are we going to do with nodejs? We are going to set up jasmine tests we can run from the command line. So see how this works, run a trivial JavaScript using node.

Create file is called alive.js

Yup, it is a one line Javascript file that writes a single message to the console. Let’s run it with node. To do that enter the command:

Not terribly exciting, but you get the idea. Node.js can execute javascript outside the browser! How cool is that?

Well, it’s about to get a lot more interesting…

NPM – The Node Package Manager

Like many other scripting languages, Node operates on the idea of packages, external bits of code you can include into your runtime environment. PHP has PEAR, Python comes with a host of powerful packages. NodeJs includes a utility called npm. Npm allows you to install packages for nodejs.

You can find a vast library of packages at the website npmjs.org. Nearly all packages come with instructions on how to install them. There are two ways to install packages.

Global Installation

Using the -g argument will require the use of sudo, or at least you need to be running with root level capability on most *nix installations. Why? Because this will install the package for ALL users.

Local Installation

Or, you can install modules locally, so they are only available in your project, on your account.

In this case, it matters where you run the npm command because the package will be installed inside your project directory, into the node_modules subdirectory. This can be good if you want to have different modules that do similar things for different projects.

Now, what if we could find a command line version of Jasmine?

Turns out there are lots and lots of them. The one we are interested in is jasmine-node. It can be found at: https://github.com/mhevery/jasmine-node. To install it run

You need to use the -g option otherwise the you have to do a lot of work to make this run properly from a local installation.

To use Jasmine with Node.js we also have to make a couple of key changes to both our controller and our spec file. Basically, it is time to make our controller a real module and tell our script to require it.

Feasts and Fits: JavaScript / NodeJS and Modules

Once upon a time, a consultant once taught me certain words are “feast” words. He meant that some words have so many meanings attached to them that no one can be sure what anyone is talking about when they use those words. A great feast word is quality. MVC has become very feast like – it means different things to different people.

Module has become another feast word.

Just google “JavaScript” and “Modules” together and you will likely come across the excellent tutorial on JavaScript module patterns, however this will not explain how NodeJS handles modules.

Basically, NodeJS uses different rules. NodeJS is not a browser so it behaves differently than javascript running in a browser. It turns out the runtime environment for a language can have a very powerful if subtle impact on the language itself and it’s behavior. For example, if there is no HTML document to render, how do you include other files in your application?

Please check out Node.js, Require and Exports for more details, but here’s the core idea. In a browser environment, we create modules to achieve a level of isolation because JavaScript makes everything global if it can (not completely true, but true enough).

Node.JS on the other hand inherently restricts scope to the file level. This means our test script can not access MyCtrl because it is in a different file. Put another way, ScriptRunner.html made our test file aware of MyCtrl because the document included it which put it into the global scope. With Node.js (a command line environment) we need to be more explicit.

In short, we need require() and we need module.exports to indicate which JavaScript files have access to which modules. So Let’s update our JavaScript source file:

The key here is that we added that last line. module.exports makes MyCtrl available to other modules (files), such as our test file. I feel compelled to let you know that how module.exports is used makes a difference, but you can see the above mentioned tutorial for a great explanation. I want to get on with running a command line test suite.

Next, we have to tell our test spec to require our controller.

At the top of our file we added the call to require(). Now from the command line we can run:

Voila! We can now run test scripts in a batch file! Wow, that was a long time in coming. Getting a module that we can test using a batch file. But we got there.

AngularJS for jQuery Developers : Recap

So with AngularJS you isolate your functionality into a standalone module. Jasmine provides a nice behavior driven library we can use to write test specifications for our code. Using NodeJS and its package manager we can automate our testing.

We have covered a lot of ground, but we are still not where we want to be. AngularJS for jQuery Developers is supposed to help you use angular – but we took a detour to talk about test. Because Angular test uses so many different technologies, we needed to touch each of those to get an understanding of what they are and where the come from. Now that we have done that, we can move onto the next part of the process.

Completely automating test with Karma, and starting to explore more complex controllers.

Part 4 – Karma, Karma, Karma Cameleon

Leave a Reply

Your email address will not be published. Required fields are marked *