AngularJS testing algorithms using Karma, Jasmine and ngHtml2JsPreprocessor: template not loaded

I am testing a custom AngularJS directive using Karma + Jasmine and the ngHtml2JsPreprocessor plugin to serve my directive template, but I don’t understand why my directive seems to be unable to access the template (the compiled element is empty). I defined templateUrl in the directive as follows:

 templateUrl: 'templates/angular/mywidget.html' 

my Karma configuration is as follows (its corresponding part):

  basePath: '../../main/webapp/static/', files: [ {pattern: 'libs/angular/angular.js', watch: false}, {pattern: 'libs/angular-resource/angular-resource.js', watch: false}, {pattern: 'libs/angular-mocks/angular-mocks.js', watch: false}, {pattern: 'libs/angular-ngkit/js/ngkit.js', watch: false}, {pattern: 'libs/jquery/dist/jquery.js', watch: false}, 'templates/angular/*.html', 'js/angular/**/*.js', '../../../test/js/spec/angular/*.js' ], preprocessors: { 'templates/angular/*.html': ['ng-html2js'] }, ngHtml2JsPreprocessor: { moduleName: 'templates' }, browsers: [ 'PhantomJS' ], plugins: [ 'karma-phantomjs-launcher', 'karma-jasmine', 'karma-ng-html2js-preprocessor' ], 

and in my test:

 beforeEach(module('templates')); beforeEach(module('ngResource')); beforeEach(module('mywidget')); 

The "fun" part is that if I test the template cache, the templates are downloaded and compiled:

 beforeEach(inject(function(_$templateCache_) { var template = _$templateCache_.get('templates/angular/mywidget.html'); })); 

there is a pattern! Why can't my directive use it? (it works fine in the browser). If I replace templateUrl with inline template in my directive, it will be displayed correctly in the test ... but I have to use an external template, it is unacceptable to insert it into a string ... I'm stuck !! Any smart idea?

UPDATE (what I have tried so far):

  • writing a new directive without logic (to exclude that the problem was in the implementation) is simple:

    angular.module('modulename', []). directive('foo', function() { return { templateUrl: 'path/to/template.html' } });

  • simplify the contents of the template to:

    <div>hello world</div>

  • change the path to the template

  • change template name

  • change the location of the karma configuration file

  • removes additional dependencies such as "ngResource" and similar

  • reinstalling all the dependencies of the bars (and clearing the cache)

  • reinstall all npm packages

  • run tests from the command line (I ran the test in Intellij Idea using the Karma plugin)

  • Tipping your fists on the table, throwing sequences of Fibonacci blasphemy that would kill dad if he listened to him!

(the latter, as a rule, leads me to a solution ... but not this time)

UPDATE 2:

I got around the problem by defining my directive like this:

 directive('mywidget', function($templateCache) { var config = {}; // directive definition (where you define "link", "restrict"...) var templateUrl = 'templates/angular/mywidget.html'; var cachedTemplate = $templateCache.get(templateUrl); if (cache) { config.template = cachedTemplate; } else { config.templateUrl = templateUrl; } return config; }); 

Using this trick, my directive gets visualization properly in tests. This moment sounds like an error in AngularJS ... it cannot somehow load the template from the cache. I am extremely disappointed: (

+7
angularjs karma-runner jasmine karma-jasmine
source share
2 answers

YEAAAAAAAAAAAH !!! I finally solved this crazy problem !!! The problem was that I used different versions of angular dependecies (angular -mocks, angular -resource ...), it turned out that if you use, say, angular 1.2.27, then you MUST also use angular -mocks 1.2.27 , angular -resource 1.2.27, etc., because otherwise conflicts may occur, similar to the ones I came across. Of course, I was not going to use different versions, but somehow, installing my dependencies through bower, I get these libraries "without alignment".

+4
source share

Try adding a compiled element to the document body with

 angular.element(document.body).append(element); 

You can put it in a beforeEach block:

 beforeEach(function() { inject(function(_$compile_, _$rootScope_) { var compile, element, rootScope, scope; compile = _$compile_; rootScope = _$rootScope_; scope = rootScope; element = angular.element('<hello-directive></hello-directive>'); compile(element)(scope); angular.element(document.body).append(element); scope.$apply(); }); }); 
+1
source share

All Articles