Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

unit testing angular directives templateUrl (include requirejs and ng-html2js

I am working on a not-yet-huge angular app. I have got a problem with karma unit testing. To make a long story short, I am using angular with requirej. My tests run well if I keep my template embedded in my directive. But as this app will be huge, it will not scale. But when I move the template and load it in my directive with templateUrl, I can not get rid of one of the following errors (depending on how I modify the conf):

  1. (initial error) "Unexpected request: GET path/to/mytpl.html"

  2. "ReferenceError: Can't find variable: angular". This error occurs with different config:

    • when I put {pattern: 'path/to/mytpl.html', included: false} in my karma.conf and add a requirejs's define path/to/mytpl.html in my test file (this is the way I would like that to work).
    • when I put path/to/mytpl.html in my karma.conf then all my template return this error (whether I am using ng-html2-js preprocessor or not).
  3. "Error: [$injector:modulerr] Failed to instantiate module templates due to: Error: [$injector:nomod] Module 'templates' is not available!". I saw that karma-ng-html2js-preprocessor could be use to create a module that will contains all templates, but it never worked.

NB: I do not use FQN in karma.conf, I use it here to be consistent. I do not think that matters, but I prefer to precise it

I saw someone putting each 'path/to/mytpl.html': {deps: ['angular']} in the shim section of their test-main.js. But it does not work for me and that solution will not scale.

like image 640
jibe Avatar asked Oct 31 '22 18:10

jibe


1 Answers

I had the same problem and found solution in the following article. I guess your problem is in wrong karma or requireJS config, in particular base path setup. In case your directive templateUrl is relative and that url can't be resolved correctly against karma base path or requireJS base path, then you need to work out this issue.

Let's assume your directive has 'app/directive/myDirective.html' value for templateUrl. Then:

  1. Check if your html file is properly included into files section of karma config, pay attention to included:false setting:

    files: [
        //...
        { pattern: 'path_to_directive/myDirective.html', included: false },
        //...
    ],
    

    of course you can use a wild card chars like * or **, but for troubleshooting purposes I would start with a full path value. According to the value of basePath in karma config, 'path_to_directive' will or won't be the same as path in your app.

    Ex: if karma base path is one level up from you app root, then your 'path_to_directive' = 'some-folder/app/directive/myDirective.html'

  2. Make sure you can get your file from the browser. Go to http://localhost:karma_port/base/path_to_directive/myDirective.html.js

    While doing this test pay attention to:

    • base prefix in the url (karma serves all files from that virtual path and adds this prefix to all urls)
    • '.js' at the end of your url
  3. Once you get file in step 2, you'll see the actual module code, created by html2js preprocessor. It should look something like this:

    angular.module('module_path/myDirective.html', []).run(function($templateCache) {
        $templateCache.put('module_path/myDirective.html',
        //...
    
  4. Make sure module_path is 'app/directive/'. If not then you have 2 options:

    • module_path has some prefix => simply remove it by adding the following to karma config:

      ngHtml2JsPreprocessor: { stripPrefix: 'modulePrefix' }

    • module_path is shorter => add missing part:

      ngHtml2JsPreprocessor: { prependPrefix: 'missingPart' }

    Restart karma and make sure 'module_path' in step 3 is 'app/directive/'

  5. Make sure you have added angular dependency for your template module (check test-main.js which is basically config file for requireJS). Also keep in mind, that value in shim section will be resolved according to baseUrl value in your test-main.js file. For simplicity, I'll assume that requireJS can get the file from 'requirejs_path/myDirective.html' path.

    shim: {
        //..
        'requirejs_path/myDirective.html': { deps: ['angular'] },
        //..
    }
    
  6. Make sure you have included your template as a dependency to your test and also don't forget to load the module:

    define(['requirejs_path/myDirective.html', 'angular-mocks', '...'], function () {
    
        describe('test suite', function() {
            //...
            beforeEach(module('app/directive/myDirective.html'));
            //...
        });
    });
    

I hope by completing these 6 step you'll get a working test. Good luck.

like image 133
davidoff Avatar answered Nov 08 '22 05:11

davidoff