How to Test an AngularJS Directive

Written by

After working with Backbone, Meteor, AngularJS and Ember (however, I have not dived deep into Ember yet), I feel that AngularJS is prepared the best for Test Driven Development (TDD). It truly makes it a cinch removing all excuses to not use tests in your application!

I have had the pleasure of focusing on testing within an AngularJS client application recently and lost a small amount of time testing a directive. The issue revolved around the template being located as an external html file as opposed to being included within the directive itself. There were a couple of head scratching errors that @amscotti and I had whilst seeking a solution but here’s a suggested approach.

AngularJS

Tools

We will start from scratch, but it won’t take long to get up and running if we use Yeoman. In fact there are a few libs I can recommend using:

sudo npm install -g yo grunt-cli bower karma

Two yeoman generators you may find useful are:

sudo npm install -g generator-angular generator-karma

(thanks to @amscotti for the heads up on these).

An alternative to the manual installation routine above is to use the awesome Boxen, read more on this here.

Create the project

mkdir directive-example && cd $_
yo angular

Here is a further list of AngularJS generators

Configure Karma

Open the karma.conf.js file and make the following changes (any changes to this file require you to restart Karma):

Base path

To enable Karma to use the correct template path and have the directive load template file you will need to change the basePath:

basePath = 'app';

File patterns

Amend the paths to reflect the newly defined basePath:

files = [
  JASMINE,
  JASMINE_ADAPTER,
  'components/angular/angular.js',
  'components/angular-mocks/angular-mocks.js',
  'scripts/*.js',
  'scripts/**/*.js',
  'views/**/*.html',
  '../test/mock/**/*.js',
  '../test/spec/**/*.js'
];

Compiling templates

Templates need to be compiled to javascript otherwise you will get a parse error on running Karma. The html2js preprocessor is the solution and simply requires adding the following to your karma.conf.js (this is based on you storing template files within a directory in views):

preprocessors = {
  'views/**/*.html': 'html2js'
};

Auto watch

This is a really cool part of Karma where you can enable watching files and then auto executing tests as you develop:

autoWatch = true;

Optional

I use PhantomJS to run the Angular tests as opposed to relying on a browser such as Chrome.

Change the browser for running tests to PhantomJS:

browsers = ['PhantomJS'];

Create a directive

yo angular:directive albums

Start Karma

To start Karma which will also auto run the tests when we update the files use:

karma start

You should now see that two tests have been executed successfully:

Executed 2 of 2 SUCCESS (0.284 secs / 0.015 secs)

Create a failing test

(Our list is sourced from the crazy talented Busdriver!)

Let’s fix the first error we see:

Error: No module: views/templates/albums.html

Build a simple template

mkdir -p app/views/templates
touch app/views/templates/albums.html

Our test is still failing, let’s add the new template to the albums.js directive, change the line of code declaring the template to:

templateUrl: 'views/templates/albums.html',

The test will still fail as we are not creating a list within the template. Let’s do that now by adding the following to the albums.html:

<ul><li></li></ul>

And update the albums.js directive as follows:

Word! The test passes. Let’s add another test to check the first album in the list has the correct title.

it("should display the correct album title for the first item in the albums list", function() {
    var list = element.find('li');
    expect(list.eq(0).text()).toBe('Memoirs of the Elephant Man');
});

The test fails. Let’s add the title attribute to the directives scope in albums.js:

Sweet, the test’s are passing again.

All the source to this project can be found on Github.


Potential errors and solutions

Spawn error solution

Set an env variable to your ~/.profile or ~/.bash_profile.

which phantomjs
export PHANTOMJS_BIN='YOUR_PATH_TO_PHANTOMJS'
~/.profile to reload

Missing mocks error solution

bower install angular-mocks

Useful links

Comments