5

EDIT: after asking the question, i'm now editing this to elaborate on my findings.

My app is modularized using directives. I'm writing my directives such that they (1) create their own scope (2) use templateUrl, and (3) do most of the logic and server data fetching in their controller.

The question is how to unit test it, using Mocha with Karma.

Lior
  • 40,466
  • 12
  • 38
  • 40

1 Answers1

7

a test is written for each directive. Since the directive uses templateUrl, I used html2js. the html key should be included as a module - that puts the template into the templateCache.

Then, I compiled the directive, and run the link function with rootScope. I had issues with getting the template html - solved using $digest. Had data binding issues, solved through understanding. All documented it below.

code below,

Directive:

 angular.module('myApp')
 .directive('productThumb', function(){
    return {
     restrict: 'AE',
     scope: true,
     templateUrl: 'partials/directives/product-thumb.html',
     // controller does most of the work
     controller: ProductThumbController 

   }
}) ;

describe("Unit: Testing Directives", function() {
var elm, scope, linkFn;
beforeEach(
  module('ogApp','partials/directives/product-thumb.html') // puts product-thumb.html 
                                                          // into templateCache
);


beforeEach(inject(function($rootScope, $compile) {
    elm = angular.element('<product-thumb></product-thumb>');
    scope = $rootScope;
    linkFn = $compile(elm);
    scope.$digest(); // have to digest to bring html from templateCache
    console.log('post compile',elm.html());// <== the html here still have {{}}
}));

it('should show a thumb',function() {
    inject(function($controller)  {
        linkFn(scope); // <== this will create a new scope (since our directive creates 
                       // new scope), runs the controller with it, and bind 
                       // the element to that new scope
        scope.$digest();
        console.log('post link',elm.html());// <== the html is bound 

        // inject test data (controller sets up an $on handler for addProductData event)
        scope.$broadcast('addProductData',{title:"TEST DISPLAY NAME", 
                                          productId: "123", mainImageUrl: "TEST.JPG"});
        scope.$digest();
        expect(elm.find('H5').text()).to.equal("TEST DISPLAY NAME"); // <=== success 
    });
});
demisx
  • 7,217
  • 4
  • 45
  • 43
Lior
  • 40,466
  • 12
  • 38
  • 40
  • 1
    Hey Lior, I just want to say, thank you. I was trying to test an angular.js directive making use of templateUrl (instead of template) and I was trying to avoid hitting the actual template. I used a very similar variant of your answer, only difference being that I didnt use html2js; instead I injected $templateCache and made it return a string, and that worked perfectly for me. Once again, thank you! – yanhan Jul 15 '13 at 08:20
  • only problem I'm having with this is where the partial template is located. how can you know which path to use? –  May 02 '14 at 16:47
  • The path is relative to application root, e.g. where the main `app.js` resides. – demisx Oct 03 '14 at 04:29