0

I have the following Karma/Jasmine test of an Angular directive that contains a templateUrl:

describe("topbar Directive", function() {

    var scope,element;

    beforeEach(module('app'));
    beforeEach(module('app/directives/topbar.html'));

    var title = 'This is the title';

    beforeEach(inject(function ($rootScope,$compile) {
        console.log(1)
        var formElement = angular.element('<div top-bar title="\'' + title + 
                '\'" on-close="modalCancel()"></div>');
        console.log(2)
        scope = $rootScope.$new();
        console.log(3)
        element = $compile(formElement)(scope);
        console.log(4)
        scope.$digest();
        console.log(5)
    }));


    it("should have a title", function() {
        console.log(6)
        expect(element.find('title')).toEqual(title);
    })

});

The test result doesn't print console.log(5) and throws an exception. What could be the problem?

15 01 2017 12:36:53.239:INFO [karma]: Karma v1.3.0 server started at http://localhost:9876/
15 01 2017 12:36:53.242:INFO [launcher]: Launching browser PhantomJS with unlimited concurrency
15 01 2017 12:36:53.248:INFO [launcher]: Starting browser PhantomJS
15 01 2017 12:36:54.770:INFO [PhantomJS 2.1.1 (Windows 8 0.0.0)]: Connected on socket /#0Ml05I-NApeqvN5wAAAA with id 22588553
LOG: 1
LOG: 2
LOG: 3
LOG: 4
LOG: 6
PhantomJS 2.1.1 (Windows 8 0.0.0) topbar Directive should have a title FAILED
        Error: Unexpected request: GET assets/app/directives/topbar.html
        No more request expected (line 1245)
        $httpBackend@test/libs/angular/angular-mocks.js:1245:90
        sendReq@test/libs/angular/angular.js:10558:21
        serverRequest@test/libs/angular/angular.js:10268:23
        processQueue@test/libs/angular/angular.js:14792:30
        test/libs/angular/angular.js:14808:39
        $eval@test/libs/angular/angular.js:16052:28
        $digest@test/libs/angular/angular.js:15870:36
        test/directives/topbar.test.js:19:16
        invoke@test/libs/angular/angular.js:4523:22
        workFn@test/libs/angular/angular-mocks.js:2439:26
        loaded@http://localhost:9876/context.js:151:17
        undefined
        Expected ({ length: 0, prevObject: ({ 0: HTMLNode, length: 1 }), context: undefined, selector: 'title' }) to equal 'This is the title'.

UPDATE

I'm loading templates with ng-html2js karma plugin

In karma.conj.js:

preprocessors: {
    'app/directives/*.html': 'ng-html2js'
},
ngHtml2JsPreprocessor: {
    stripPrefix: 'assets/'
},

And this is the directive I'm testing, note templateUrl

angular.module('app').
directive("topBar", function() {
      return {
        restrict: "AE",        
        scope: {        
            title: '='
        },
        templateUrl: "assets/app/directives/topbar.html",
        link: function (scope, element, attrs) {
            scope.modalClose = function () {
                // ... some code
            }
        }
      }
});
ps0604
  • 1,227
  • 23
  • 133
  • 330

1 Answers1

0

Angular unit tests can't do real requests.

All templateUrl templates should be mocked with

$templateCache.put('assets/app/directives/topbar.html', ...topbar.html contents...)

prior to the action that requests them ($compile call in this case).

Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • I'm using `ng-html2js` that is already loading the template in the cache. – ps0604 Jan 15 '17 at 17:48
  • You've excluded it from the question, while it is the most relevant part here. Essentially it should do the thing as described above.Since it should be **assets/app/directives/topbar.html** and not **app/directives/topbar.html**, I would expect that this is the problem. – Estus Flask Jan 15 '17 at 17:52
  • If I add `console.log($templateCache.get('app/directives/topbar.html'));` I can see that the template is loaded. . – ps0604 Jan 15 '17 at 17:54
  • Because requested url is `assets/app/...`, not `app/...`. These are two different urls. I don't use html2js but I guess you need [`prependPrefix`](https://github.com/karma-runner/karma-ng-html2js-preprocessor#configuration) option. – Estus Flask Jan 15 '17 at 17:56
  • if I change `app/...` to `assets/app/...` then console.log 1 to 5 are`NOT` printed, meaning that the module that declares the template fails. – ps0604 Jan 15 '17 at 18:35
  • Because `assets/app/directives/topbar.html` and `app/directives/topbar.html` are not the same things. They are different strings and different templates. You load `assets/app/directives/topbar.html` template in a directive and not `app/directives/topbar.html`. You have `app/directives/*.html` file paths and you need these templates to become `asset/app/directives/*.html` Angular templates. This is achievable with `prependPrefix` option. – Estus Flask Jan 15 '17 at 18:36
  • how exactly is `prependPrefix` used in this scenario? – ps0604 Jan 15 '17 at 18:40
  • This is ng-html2js specific question, and I'm not aware of details, but I guess it is something like `preprocessors: { 'app/directives/*.html': 'ng-html2js' }, ngHtml2JsPreprocessor: { prependPrefix : 'assets/' }`. Basically it should become `assets/app/directives/topbar.html` Angular module with `$templateCache.put('assets/app/directives/topbar.html',...)` (you can check this in Karma temp dir output). – Estus Flask Jan 15 '17 at 19:05
  • doesn't work with `prependPrefix : 'assets/'` :( without `prependPrefix` at least the template is loaded... – ps0604 Jan 15 '17 at 20:16
  • Without `assets/` it is the wrong template that can't help you with testing. 'doesn't work' is quite vague. Sorry, can't help you with that, the problem lacks [MCVE](http://stackoverflow.com/help/mcve) and cannot be replicated. The solution is what was said above *Basically it should become assets/app/directives/topbar.html Angular module with $templateCache.put('assets/app/directives/topbar.html',...) (you can check this in Karma temp dir output)*. Debugging Karma is often looks like digging through generated JS files that are loaded in browser. – Estus Flask Jan 15 '17 at 20:25
  • the problem is that the `assets` directory doesn't exist. I need to prepend it in the directive to `templateUrl` because it's a requirement of the Play framework to find any files in the server, but when I append it to the template name with `prependPrefix` the karma plugin doesn't find it because the `assets` directory doesn't exist. the solution was to append manually the template in `$templateCache`. – ps0604 Jan 15 '17 at 21:08
  • This is a question specific to ng-html2js. The documentation isn't clear enough. You can try to play with `cacheIdFromPath` option, but it looks like [`prependPrefix` should already do that](https://github.com/karma-runner/karma-ng-html2js-preprocessor/blob/master/lib/html2js.js#L37-L39). You can try to open the issue in ng-html2js repo or just do this manually with `$templateCache.put` if you're out of time. – Estus Flask Jan 15 '17 at 21:15