3

I'm trying to test an angularJS directive that uses a templateURL. For the life of me I can't get the compiler to actually load the templateURL, even when it has been put into the templateCache. I realize karma preprocesses all the template contents and creates modules for each that preloads the templateCache, but I expected that this would have been equivalent.

Here is a http://jsfiddle.net/devshorts/cxN22/2/ that demonstrates whats going on.

angular.module("app", [])
.directive("test", function(){
    return {
        templateUrl:"some.html",
        replace:true
    }
});

//--- SPECS -------------------------

describe("template url test", function() {
    var element,  scope, manualCompiledElement;

    beforeEach(module('app'));

    beforeEach(inject(function($rootScope, $controller, $compile, $templateCache){
        $templateCache.put("some.html", "<div>hello</div>");

        scope = $rootScope.$new();

        element = $compile(angular.element('<test></test>'))(scope);

        manualCompiledElement = $compile(angular.element($templateCache.get('some.html')))(scope);

        scope.$digest();        
    }));

    it("has hello", function() {
        expect(element.text()).toContain('hello');
    });

    it("template cache has contents", function(){
        expect(manualCompiledElement.text()).toContain('hello');
    });       
});

What am I missing?

devshorts
  • 8,572
  • 4
  • 50
  • 73
  • Well, I was never able to figure this out. I switched over to use karma and everything works fine now. – devshorts Jun 20 '13 at 21:58
  • 1
    I'm about to give up - it's something about template cache + jasmine. I can get it to work with just a template. Note you were missing `restrict: 'E'` in your directive. By default it's `restrict: 'A'` and you were using it in the context of an element and not an attribute. Since you got it working I won't waste any more time. – Jesus is Lord Oct 30 '13 at 20:01
  • 1
    Thanks for giving it a shot @WordsLikeJared. I'm not sure what the karma preprocessor is doing different (it looked nearly identical to me), but using karma was the right choice anyways since it provided other functionality that came in handy. That, and everyone uses it for this purpose. Better to swim with the current I guess – devshorts Oct 30 '13 at 20:36

2 Answers2

2

I realise you no longer necessarily need to know, but it looks to me like there are two problems contributing to this.

The first was pointed out by @Words-Like-Jared. You are defining the directive as restricted to attributes (default) but using it as an element. So you need restrict: 'E'.

The second problem is that your template is never actually retrieved and your compile/link never completes. The request for the contents of the template within the directive are asynchronous so a digest on the root scope is needed to resolve the promise and return them, similar to this answer for another question.

When you perform your manual compilation, the results are not asynchronous and the template is retrieved immediately. Actually the compilation in your manual compilation doesn't do a lot as you are compiling the contents of your template, which doesn't have any directives in.

Now at the end of your beforeEach where you use

$scope.$digest()

you are digesting on the current scope and its children. When you use $rootScope.$digest() or $scope.$apply() you will perform a digest across all scopes. So changing this to

$rootScope.$digest()
// or
$scope.$root.$digest()

in the line after your compilation means both of your tests will now pass. I have updated the fiddle here.

Community
  • 1
  • 1
Andyrooger
  • 6,748
  • 1
  • 43
  • 44
1

Here is a variation of the solution in coffeescript

expect = chai.expect;
app = angular.module('TM_App')

app.directive "test", ()->
  templateUrl:"some.html",
  replace    :true


describe '|  testing | templateUrl',->
  element = null

  beforeEach ->
    module('TM_App')

  beforeEach ->
    inject ($compile,$rootScope, $templateCache)->
      $templateCache.put "some.html", "<div>hello {{name}}</div>"
      scope       = $rootScope.$new();
      element     = $compile('<test/>')(scope);
      scope.name = 'John'
      scope.$digest()

  it "has hello", ()->
    expect(element.text()      ).to.equal 'hello John'
    expect(element[0].outerHTML).to.equal '<div class="ng-binding">hello John</div>'
Dinis Cruz
  • 4,161
  • 2
  • 31
  • 49