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

I am working on a not yet huge angular application. I have a problem with testing karma modules. In short, I use angular with requirej. My tests work well if I keep my template built into my directive. But since this application will be huge, it will not scale. But when I move the template and load it into my directive using templateUrl , I cannot get rid of one of the following errors (depending on how I change the conf):

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

  • "ReferenceError: Cannot find variable: angular". This error occurs with a different configuration:

    • when I put {pattern: 'path/to/mytpl.html', included: false} in my karma.conf and add requirejs define path/to/mytpl.html in my test file (so I would like it to work) .
    • when I put path/to/mytpl.html in my karma.conf, then my whole template returns this error (whether I use the ng-html2-js preprocessor or not).
  • "Error: [$ injector: modulerr] Failed to create module templates due to: Error: [$ injector: nomod]" Template "modules are not available!" I saw that karma can be used to create a module that will contain all the templates -ng-html2js is a preprocessor, but it never worked.

NB: I do not use FQN in karma.conf, I use it here to be consistent. I don’t think it matters, but I prefer to clarify it.

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

+5
source share
2 answers

After fixing this problem for a while and using this time to improve my knowledge and expand my application, I found a solution.

Brief methodological recommendation: since the karma-ng-html2js preprocessor or the karma-html2js preprocessor seem to be working on some other projects, and as they are mentioned in the white paper, I tried a lot (almost all, I think) of the possible combination configuration for running one of them in my test environment. Without success, I came to the conclusion: I have to quit them and find another way.

The solution came from grunt-html2js. Just adding a basic setup to the grunt setup and running grunt, it will generate a module containing all my templates - maybe I will parse it later in more meaningful modules. But from here the work is almost complete. Then I just had to:

  • say that the karma for working with the file has other external tools file: [ {pattern: 'path/to/mytplmodule.js', included: false}, ...]
  • register the path in my conf request for path: [ 'templates' : 'path/to/mytplmodule', ...] tests path: [ 'templates' : 'path/to/mytplmodule', ...]
  • mask it while still requiring conf for tests so that it doesn't load before angular shim: [ 'templates' : 'angular', ...]
  • load this module into the test file define(['templates',...], function(){...});
  • get the template of the tested template beforeEach(module('path/to/mytpl.html'));
  • add a step to your grunt configuration to make it automatically generated before running the tests.

It's all!

There is a drawback to this approach; it requires extraction or mockery of all templates of other directives used in the proven directive. This can be boring as the number of directives grows. But I prefer this at the moment, as it is not invasive for application code. Maybe later, especially when I turn on javascript compilation in my process, I also moved it from the test to the application.

0
source

I had the same problem and found a solution in the next article. I think your problem is in the wrong karma or requireJS config, in particular in setting the base path. In case your templateUrl directive is relative and that the URL cannot be resolved correctly with respect to the karma base path or the requireJS base path, you need to solve this problem.

Suppose your directive has the value "app / directive / myDirective.html" for templateUrl. Then:

  • Check if your html file is included in the karma configuration files section correctly, pay attention to the false value included:

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

    Of course, you can use wild card characters such as * or **, but for troubleshooting I would start with the full path value. According to the basePath value in the karma configuration, path_to_directive will or will not be the same as the path in your application.

    Ex: if the base path of karma is at the same level as your application root, then your folder is' path_to_directive '=' /app/directive/myDirective.html

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

    When performing this test, pay attention to:

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

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

    • module_path has some prefix => just remove it by adding the following to your karma configuration:

      ngHtml2JsPreprocessor: { stripPrefix: 'modulePrefix' }

    • module_path is shorter => add the missing part:

      ngHtml2JsPreprocessor: { prependPrefix: 'missingPart' }

    Restart karma and verify that "module_path" in step 3 is "app / directive /"

  • Make sure you add the angular dependency for your template module (check test-main.js, which is basically the configuration file for requireJS). Also keep in mind that the value in the strip section will be resolved according to the value of baseUrl in the test-main.js file. For simplicity, I assume that requireJS can get the file from the path "requirejs_path / myDirective.html".

     shim: { //.. 'requirejs_path/myDirective.html': { deps: ['angular'] }, //.. } 
  • Make sure that you include your template depending on your test, and also do not forget to download the module:

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

I hope that by going through these 6 steps you will get a working test. Good luck.

+2
source

Source: https://habr.com/ru/post/1200855/


All Articles