Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test directives that use templateUrl and controllers?

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.

like image 925
Lior Avatar asked Jun 20 '13 21:06

Lior


1 Answers

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 
    });
});
like image 114
Lior Avatar answered Nov 15 '22 08:11

Lior