7

I am trying to test a Directive which uses external template. I tried all the following solutions with no luck:

I created a test directive (a simple div) and tested it using an inline 'template' and external 'templateUrl'. The inline solution works while the external doesn't:

   angular.module('AdUnit').directive('actionButton',function($location){
        return{
            scope:{
                actionName: '@'
            },
            restrict: 'E',
            //template: "<div ng-click='click()'>action button</div>",
            templateUrl: '/staticfiles/adunit/html/directives/actionButtonTemplate.html',
            controller: ['$scope', function($scope){
                $scope.click = function(){
                    $scope.$emit('ACTION_CLICK', $scope.actionName);
                }
            }]

        }
    });



    describe("Unit: Testing action button directive", function() {
    var elm, scope, linkFn;
    beforeEach(
        module('AdUnit')
    );

    beforeEach(module('/staticfiles/adunit/html/directives/actionButtonTemplate.html'));

    beforeEach(inject(function($rootScope, $compile) {
        elm = angular.element('<action-button action-name="post-action-0"></action-button>');
        scope = $rootScope;
        linkFn = $compile(elm);
        linkFn(scope);
        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() {

            console.log('post link',elm.html());// <== the html is bound

            expect(elm.text()).toBe("action button");

    });
});

My Karma config file:

  module.exports = function(config) {
  config.set({

    // base path, that will be used to resolve files and exclude
    basePath: '',


    // frameworks to use
    frameworks: ['jasmine'],


    // list of files / patterns to load in the browser
    files: [
        'http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js',
        'http://ajax.googleapis.com/ajax/libs/angularjs/1.2.5/angular.min.js',
        'http://ajax.googleapis.com/ajax/libs/angularjs/1.2.5/angular-route.js',
        'http://code.angularjs.org/1.0.6/angular-mocks.js',
        '../html/*.html',
        '../html/directives/*.html',
        '../js/adUnit.js',
        '../js/controllers/*.js',
        '../js/directives/*.js',
        '../js/services/*.js',
        '../*.js',
         '../**.*.js',
         '**/*.tests.js'
    ],

    preprocessors : {
        '../html/**/*.html': ['ng-html2js']
    },

     /* ngHtml2JsPreprocessor: {
          'AdUnit': '/staticfiles/adunit/html/directives/actionButtonTemplate.html'
          *//*moduleName: '/staticfiles/adunit/html/directives/internalPlayerTemplate.html'*//*
      },*/

    // list of files to exclude
    exclude: [

    ],


    // test results reporter to use
    // possible values: 'dots', 'progress', 'junit', 'growl', 'coverage'
    reporters: ['progress'],


    // web server port
    port: 9876,


    // enable / disable colors in the output (reporters and logs)
    colors: true,


    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,


    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,


    // Start these browsers, currently available:
    // - Chrome
    // - ChromeCanary
    // - Firefox
    // - Opera (has to be installed with `npm install karma-opera-launcher`)
    // - Safari (only Mac; has to be installed with `npm install karma-safari-launcher`)
    // - PhantomJS
    // - IE (only Windows; has to be installed with `npm install karma-ie-launcher`)
    browsers: ['Chrome'],


    // If browser does not capture in given timeout [ms], kill it
    captureTimeout: 60000,


    // Continuous Integration mode
    // if true, it capture browsers, run tests and exit
    singleRun: false
  });
};

I keep getting the following error:

Failed to instantiate module /staticfiles/adunit/html/directives/actionButtonTemplate.html due to:
Error: [$injector:nomod]

Any help will be appreciated!

EDIT: @MK Safi's answer solved my problem. I was missing the following:

 ngHtml2JsPreprocessor: {
     'moduleName': 'Templates',

     // Function that transforms the path to look exactly like
     // you have it in templateUrl in your Angular code
     //
     // Mine looks like this
     cacheIdFromPath: function(filepath) {
         return filepath.match(/\/staticfiles\/adunit\/html\/directives\/.*\.html/);
     }
  },

and before each test:

 beforeEach(module('Templates'));

it is important for the regular expression to point to the same path as the directive's "templateUrl", since html2js will cache those templates using this path (see html2js for more details about that)

2
  • I don't use karma nor htm2js (testem and grunt-angular-templates here), but if html2js creates a templateCache attached to a module like app, you just need to import that module into the test with module() Commented Jan 12, 2014 at 12:12
  • I am loading the module like you said: beforeEach(module('/staticfiles/adunit/html/directives/actionButtonTemplate.html')); (see in my code example). I also see the wrapped html template downloaded as js file on network sniffing Commented Jan 12, 2014 at 12:50

1 Answer 1

7

I have this setup correctly in my tests and your setup looks right, except for a few things.

Make the following changes to your Karma config file:

ngHtml2JsPreprocessor = {
  'moduleName': 'Templates',

  // Function that transforms the path to look exactly like 
  // you have it in templateUrl in your Angular code
  //
  // Mine looks like this
  cacheIdFromPath: function(filepath) {
    return filepath.match(/views\/.*/)[0]
  }
}

Then in your test's beforeEach include the Templates module that you specified in your Karma config above: module('Templates')

beforeEach(function() {
  module('Templates')
})
Sign up to request clarification or add additional context in comments.

8 Comments

no luck... I added: ngHtml2JsPreprocessor: { 'moduleName': 'Templates', // Mine looks like this cacheIdFromPath: function(filepath) { return filepath.match(/html\/.*/)[0] } }, and the beforeEach(function() { module('Templates') }). I see the html templates loaded as js files. I now get: Unexpected request: GET /staticfiles/adunit/html/directives/actionButtonTemplate.html No more request expected
@Yaniv Your templateUrl in your directive is this '/staticfiles/adunit/html/directives/actionButtonTemplate.html'. But your cacheIdFromPath function probably returns this: 'html/directives/actionButtonTemplate.html'. They don't match. Make them match.
This is finally working. Thanks man!! One last question - this is only worked for me with hard coded cacheIdFromPath: cacheIdFromPath: function(filepath) { return "/staticfiles/adunit/html/directives/internalPlayerTemplate.html" }. How can I refer the regex to match exactly what "templateUrl" points to (for all directives...)
You're welcome! Re: your other question. You could console.log(filepath) inside cacheIdFromPath and program your cacheIdFromPath to handle all cases. My guess is having the following return value in your cacheIdFromPath function might do it: return filepath.match(/\/staticfiles\/adunit\/html\/.*/)[0]
Great. What I did not understand is the "[0]" in the end of the regular expression. I removed it and now it works for all directive templates under "directives" library: cacheIdFromPath: function(filepath) { return filepath.match(/\/staticfiles\/adunit\/html\/directives\/.*\.html/); }
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.