Testing Templated AngularJS Directives

AngularJS is awesome!

I’ve been spending a lot of time lately learning and building applications using the AngularJS framework. I’m definitely not an expert yet, but I’m having a lot of fun! It’s a great framework and I really like how they’ve made testing a first-class feature.

Templates with directives

Recently I had to create a directive that required a non-trivial amount of HTML. Instead of doing this as an inline string in the directive, it was a lot easier to work with a separate template file. Setting up the directive this way using the templateUrl property was trivial. This worked great, but I ran into an issue when I went to run tests against the directive. The template wasn’t being loaded into the template cache when karma executed my tests cases. It turns out this is something you need to do yourself in order to test externalthese templates.

There are a few different ways to accomplish this loading of the directive template into the template cache for testing. One way is to load the file using an http request and add it to the directly to the template cache in your test file. This method is a little verbose and seemed cumbersome to do every time I needed to test a directive with a template. I am guessing that there are a few more directives I will need to test in the future.

Using karma-ng-html2js-preprocessor

Luckily there was another option that seemed a lot more elegant. If you’re using karma to run your tests then you can configure it to automatically compile your templates to javascript and put them in the template cache. You just need to add the magical karma plug-in: karma-ng-html2js-preprocessor karma to your project with npm:

Adding karma-ng-html2js to your project using npm

    npm install karma-ng-html2js-preprocessor -save-dev

Adding ng-html2js to your karma.config

Once you have this installed you need to add it as a preprocessor in your karma.config:

    preprocessors: {
        'src/app/directives/**/*.tpl.html': ['ng-html2js']
    },
    ngHtml2JsPreprocessor: {
        stripPrefix: 'src/app/',
        moduleName: 'your.templates'
    }

A couple of notes about this configuration block:

  • This block goes in the config.set({}) section of your karma.config.

  • You have to add the plugin as a karma preprocessor (preprocessors section) and set the configuration options for the plugin (ngHtml2JsPreprocessor section).

    • Provide the location of your directive templates in the definition of your preprocessor. In this case my templates end in *.tpl.html and are in the my src/apps/directives folder (and all sub-folders).
  • Setup the plug-in options in the ngHtml2JsPreprocessor section.
    • The stripPrefix allows you to account for differences between the path you defined for the preprocessor and the templateUrl path you set in the directive (both of which are relative to a different base directory). In this case my templateURL references directives/my-directive/my-directive.tpl.html and the preprocessor is loading src/app/directives/my-directive/my-directive.tpl.html into the cache. This path is used to identify the template in the cache. When you go to test the directive it tries to load the template in the cache based on your templateUrl, which has a different path than the one you just loaded with the preprocessor. This mismatch will keep your template from being found. The stripPrefix will remove beginning characters from your templateUrl path when the preprocessor places your template in the cache. In this case it strips off ‘src/app’ from the path so that the directive will be able to find it in the cache. There is also a preprendPrefix which works as you would expect and a cacheIdFromPath function you can supply to create a custom mapping for the cache.

    • The moduleName option allows you to set the module name that will be created by ngHtml2Js.

Important safety tip: Don’t forget to add the directive templates path to the list of files that karma loads into the browser. In this case I needed to add the following to my karma.config file in the files section:

    'src/app/directives/**/*.tpl.html'

Loading the templates module in your test fixture

Next you will need to load your compiled templates module into your test file:

    'use strict';

    describe("awesomeTemplateTest', function () {

        beforeEach(module('your.templates'));

        it('should do something awesome', function() {
            ...
        });

        ...

That’s it! Now every time you want to test a directive with a template in your application just make sure to load the compiled template module at the begining of the test fixture.

Enjoy!

3 thoughts on “Testing Templated AngularJS Directives

  1. Hi David, Thanks so much. Your explanation of the strip-prefix helped me finally figure out why our team’s tests weren’t working. This is a great article. You should consider submitting a few of these paragraphs as PR’s for the readmes in the actual ng-html2js-preprocessor amd karma-ng-html2js-preprocessor Github repos, as they don’t explain the reasoning behind strip- and append-prefix. Thank you again.

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