How to Test Directives That Use templateUrl

While it’s no problem testing directives that use inlined templates, testing directives that use templateUrl is not so straightforward. Fortunately with html2js-preprocessor it’s easy to get your tests working again with just a few lines of code!

Install the Preprocessor

Templates need to be compiled to javascript for karma to be able to use them. To do this we’ll need to install the html2js preprocessor as a developer dependency.

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

To enable preprocessing simply add this to your karma conf:

preprocessors: {
    //location of templates
    'app/views/**/*.html': 'html2js'
},

Fixing the Template Cache

AngularJS maintains a cache of all html files it has converted into angularjs templates. The caches object keys are the urls of the template files as downloaded from the server. Because our urls will differ in the testing folder from the runtime folder, we have a problem.

When AngularJS tries to load the template it will never be found because it will try to access it from 'views/templates/directive-tmp.html', but the path to the template is currently 'app/views/templates/directive-tmp.html'.

Using the preprocessor we just installed we can change the path of the cached template files to match the original url. Add this to your karma conf file:

ngHtml2JsPreprocessor: {
    // strip app from the file path
    stripPrefix: 'app/'
},

Add the Templates Location

We’ll also need to add the location of the html templates to the karma conf file so that we can load it from our test.

files: [
'app/bower_components/angular/angular.js',
'app/bower_components/angular-animate/angular-animate.js',
'app/bower_components/angular-route/angular-route.js',
'app/bower_components/angular-mocks/angular-mocks.js',
'app/scripts/*.js',
'app/scripts/**/*.js',
'test/mock/**/*.js',
'test/spec/**/*.js',

//location of templates
'app/views/**/*.html'
],

Include the Template in Your Test

Finally, you’ll need to include the template file in your unit test:

beforeEach(module('views/templates/directive-tmp.html'));

Sweet, now your directive unit tests should work!

Share Button
  • Zach Wolfe

    Great post! Just added this to my test suite!

  • http://www.simplewebapp.de mindreframer

    thx! had this solved by adjusting cachedIdFromPath:

    ngHtml2JsPreprocessor: {

    cacheIdFromPath: function(filepath) {

    // we want our view to begin with "/views"

    return filepath.replace("app/", "/");

    }

    },

    • https://github.com/dchacke Dennis C. Hackethal

      What about using

      ngHtml2JsPreprocessor: {
      // strip app from the file path
      stripPrefix: ‘app’
      }

  • Ben Smith

    When using Karma v0.10 you dont need to add the preprocessors as this will case an Warn Pre-processor “Ng-html2js” is not registered!

    This is because this preprocessors have been refactored into a plugin. So now you just add

    plugins : [
    ....
    'karma-ng-html2js-preprocessor'
    ...
    ]

    and this should work correctly now

  • Hugo

    made my day!

  • http://www.vidul.com/ Vidul Petrov

    Thank you, very helpful post!

  • https://github.com/dchacke Dennis C. Hackethal

    Freaking amazing. Thank you so much for this post. After three hours of trying to solve this, your post finally pointed me in the right direction.

    For me, personally, what threw me off was the fact that I had to load all html files in `app/views`, and it seems I also needed to strip the “app” prefix. Both now make sense.

    What I find particularly elegant about your solution is that you define the path of the directive’s template as loadpath for a module. This seems to ensure that you always only load the views you need for a specific test.

    I’m surprised it’s so hard to test directives that don’t have inline templates. I hope the Angular team will figure something out to make this easier.