Trouble unit-testing directives that use templateUrl
angularjs, gruntjs, javascript, karma-runner, unit-testing
Solution
The problem
When `templateUrl` is specified, templates are fetched using `$http` (even for cached templates, which `$http` serves from the `$templateCache`). For that reason, there needs to be a $digest cycle for the `$http`'s promise to be resolved with the template content and processed by the directive.
The solution
Since promises get resolved during a $digest cycle (and since we are outside of an "Angular context"), we need to manually invoke `$rootScope.$digest()` before evaluating our assertions. Thus, the last test should be modified like this:
it("should render cached templates", function() {
var element = $compile('<hello-world2></hello-world2>')($rootScope);
$rootScope.$digest(); // <-- manually force a $digest cycle
expect(element.text()).toBe(tmplText);
});
See, also, this short demo.
Problem
I'm having trouble unit-testing directives that make use of `templateUrl`. There's this awesome tutorial about AngularJS testing [1] and it even has a Github repo that goes with it [2] So I forked it [3] and made the following changes: On `directives.js` I created two new directives: ``` .directive('helloWorld', function() { return { restrict: 'E', replace: true, scope:{}, template: '<div>hello world!</div>', controller: ['$scope', function ($scope) {}] } }) .directive('helloWorld2', function() { return { restrict: 'E', replace: true, scope:{}, templateUrl: 'mytemplate.html', controller: ['$scope', function ($scope) {}] } }) ``` and I changed `test/unit/directives/directivesSpecs.js` so that it loads a template into $templateCache and then added two more tests for the new directives: ``` // // test/unit/directives/directivesSpec.js // describe("Unit: Testing Directives", function() { var $compile, $rootScope, $templateCache; beforeEach(angular.mock.module('App')); beforeEach(inject( ['$compile','$rootScope', '$templateCache', function($c, $r, $tc) { $compile = $c; $rootScope = $r; //Added $templateCache and mytemplate $templateCache = $tc; $templateCache.put('mytemplate.html', '<div>hello world 2!</div>'); }] )); //This was already here it("should display the welcome text properly", function() { var element = $compile('<div data-app-welcome>User</div>')($rootScope); expect(element.html()).to.match(/Welcome/i); }); //Added this test - it passes it("should render inline templates", function() { var element = $compile('<hello-world></hello-world>')($rootScope); expect(element.text()).equal("hello world!"); }); //Added this test - it fails it("should render cached templates", function() { var element = $compile('<hello-world2></hello-world2>')($rootScope); expect(element.text()).equal("hello world 2!"); }); }); ``` The last test fails because Angular won't compile the template like it should. ``` $ grunt test:unit Running "karma:unit" (karma) task INFO [karma]: Karma v0.10.10 server started at http://localhost:9876/ INFO [launcher]: Starting browser Chrome INFO [Chrome 35.0.1916 (Linux)]: Connected on socket ChISVr0ZABZ1fusdyv3m Chrome 35.0.1916 (Linux) Unit: Testing Directives should render cached templates FAILED expected '' to equal 'hello world 2!' AssertionError: expected '' to equal 'hello world 2!' Chrome 35.0.1916 (Linux): Executed 18 of 18 (1 FAILED) (0.441 secs / 0.116 secs) Warning: Task "karma:unit" failed. Use --force to continue. Aborted due to warnings. ``` I'm pretty sure this was supposed to work. At least, it's very similar with the solution proposed by @SleepyMurth on [4]. But I feel I reached the limit of understanding what's going wrong with my current knowledge of AngularJS. HELP! :-) [1] http://www.yearofmoo.com/2013/01/full-spectrum-testing-with-angularjs-and-karma.html [2] https://github.com/yearofmoo-articles/AngularJS-Testing-Article/ [3] https://github.com/tonylampada/AngularJS-Testing-Article [4] Unit Testing AngularJS directive with templateUrl