3
votes

I am trying to unit test an Angular Components and templates with Karma Jasmine. I'm using ng-html2js Testing component controller is achieved but not template I'm referencing this Git Repository as part of this.The karma-conf file is same as the one in above repo.

Folder structure

|   .editorconfig
|   .jshintrc
|   gulpfile.js
|   index.html
|   karma.conf.js
|   package.json
|
+---app
|   |   app-constants.js
|   |   app-routes.js
|   |   app.js
|   |   
|   +---components
|   |   |   about-component.js
|   |   |   footer-component.js
|   |   |   header-component.js
|   |   |   home-component.js
|   |   |   
|   |   \---shared
|   +---services
|   |       endpoint-service.js
|   |       
|   \---templates
|           about-template.html
|           footer-template.html
|           header-template.html
|           home-template.html
|           
\---tests
    |   app.spec.js
    |   
    +---components
    |       endpoint-service.mock.js
    |       footer-component.spec.js
    |       header-component.spec.js
    |       home-component.spec.js
    |       
    +---services
    |       endpoint-services.spec.js
    |       
    \---templates
           home-template.spec.js

Component

angular.module("app").component('headerComponent', {
    templateUrl: 'app/templates/header-template.html'
});

Template

<header>
    <nav class="navbar navbar-inverse">
        <div class="container-fluid">
            <div class="navbar-header">
                <a class="navbar-brand" href="#!/">Header Text</a>
            </div>              
        </div>
    </nav>
</header>

Spec

'use strict';
describe('Component: headerComponent', function () { 
    beforeEach(module('errorlogger'));
    beforeEach(module('templates'));
    var element;
    var scope;
    beforeEach(inject(function ($rootScope, $compile) {         
        scope = $rootScope.$new();          
        element = angular.element('<header-component></header-component>');         
        scope.$apply(function () {
            $compile(element)(scope);
        });         
    }));

    it('should render the header text', function () {
        var title = element.find('a')[0];
        expect(title).toBeTruthy();
        expect(title.text()).toBe('Header Text');
    });
});

Error in console (I'm using karma-spec for reporting)

Component: headerComponent
    × should render the title text (1160ms)
        Error: [$compile:tpload] Failed to load template: app/templates/header-template.html (HTTP status: undefined undefined)
        http://errors.angularjs.org/1.6.4/$compile/tpload?p0=app%2Ftemplates%2Fheader-template.html&p1=undefined&p2=undefined
            at node_modules/angular/angular.js:66:12
            at handleError (node_modules/angular/angular.js:19992:20)
            at processQueue (node_modules/angular/angular.js:16832:37)
            at node_modules/angular/angular.js:16876:27
            at Scope.$digest (node_modules/angular/angular.js:17971:15)
            at ChildScope.$apply (node_modules/angular/angular.js:18269:24)
            at Object.<anonymous> (tests/components/header-component.spec.js:16:9)
            at Object.invoke (node_modules/angular/angular.js:5003:19)
            at Object.WorkFn (node_modules/angular-mocks/angular-mocks.js:3173:20)
        Error: Declaration Location
            at window.inject.angular.mock.inject (node_modules/angular-mocks/angular-mocks.js:3136:25)
            at Suite.<anonymous> (tests/components/header-component.spec.js:7:13)
            at tests/components/header-component.spec.js:2:1

karma.conf file

files: [
        'node_modules/jquery/dist/jquery.js',
        'node_modules/angular/angular.js',
        'node_modules/angular-ui-router/release/angular-ui-router.js',
        'node_modules/angular-mocks/angular-mocks.js',
        'app/app.js',
        'app/services/*.js',
        'app/components/*.js',
        'app/**/*.js',
        'app/templates/*.html',
        'tests/app.spec.js',
        'tests/components/header-component.spec.js'         
        //'tests/components/*.spec.js'
        //'tests/**/*.js'
],
preprocessors: {
  'app/templates/*.html': 'ng-html2js',
  'app/**/!(*.mock|*.spec).js': ['coverage']
},

ngHtml2JsPreprocessor: {
  // strip this from the file path
  stripPrefix: 'app/',
  // create a single module that contains templates from all the files
  moduleName: 'templates'
},

Am I missing anything here?

1
Can you create a plunker/fiddle/pen? or could you share the folder structure that you are using?Gaurav
One more thing, by looking at the error it looks like that the template path that you have provided doesn't match with the absolute path of the template. Said so, the rule that I follow is that the template path should be traversable from the location where my 'index.html' resides(this could be different from project to project and config to config).Gaurav
edited the questionNikhilGoud
Here everything looks good to me. But in your spec I see that you have not included your 'headerComponent''s module i.e the app module. One more thing when you type title.text() here title is assumed a jqLite or jquery element and not an HTML element.Gaurav

1 Answers

1
votes

It looks like you have missed the module reference in your spec file:

'use strict';
describe('Component: headerComponent', function () { 
    // beforeEach(module('errorlogger')); // <-- Is this needed?
    beforeEach(module('app'));  // <-- Add this
    beforeEach(module('templates'));
    var element;
    var scope;
    beforeEach(inject(function ($rootScope, $compile) {         
        scope = $rootScope.$new();          
        element = angular.element('<header-component></header-component>');         
        scope.$apply(function () {
            $compile(element)(scope);
        });         
    }));

    it('should render the header text', function () {
        //var title = element.find('a')[0];  // <-- Chnage this
        var title = element.find('a');  // <-- To this
        expect(title.text()).toBe('Header Text');
    });
});

Also, modify your karma.conf file to : (change the files section as in your case you can include all the js files)

files: [
        'node_modules/jquery/dist/jquery.js',
        'node_modules/angular/angular.js',
        'node_modules/angular-ui-router/release/angular-ui-router.js',
        'node_modules/angular-mocks/angular-mocks.js',
        'app/**/*.js',
        'app/**/*.html',
        'tests/**/*.spec.js',
], 
preprocessors: {   
    'app/templates/*.html': 'ng-html2js',   
    'app/**/!(*.mock|*.spec).js': ['coverage'] 
},

ngHtml2JsPreprocessor: {
    // strip this from the file path   
    //stripPrefix: 'app/', // <-- Not needed in your case.  
    // create a single module that contains templates from all the files   
   moduleName: 'templates' 
}