Error: Unexpected request: GET views/partials/* for a nested directive even when using html2js in karma/jasmine unit test

All we need is an easy explanation of the problem, so here it is.

I am using Karma and Jasmine for unit testing for my angularjs application.
I have a directive’s(say Directive A) template in which another directive(say Directive B) is getting rendered, although it is working fine in application but test case fails to render the Directive B’s template.
Following is the error I get :-

    Error: Unexpected request: GET views/partials/directiveb.html
Expected GET https://my-sandbox.app.com/123456

Below is the directive A’s code :-

angular.module('myApp')
  .directive('directiveA', function (myservices, myOtherServices) {
    return {
        controller: function(){
        /* ... controller function ... */
        },
        templateUrl: '/views/partials/directivea.html',
        restrict: 'E',
        link: function postLink(scope, element, attrs) {
        /* ...link function... */
        }
    };
  });

Directive A’s template :-

<div>
    <div class="col-md-12">
        <h4>We <strong>Need</strong></h4>
        <div directive-b some-attribute=="true"></div>
    </div>
    <div directive-b some-attribute=="false"></div>
</div>

Directive A’s test case :-

'use strict';

describe('Directive: directiveA', function () {

    // load the directive's module
    beforeEach(module('myApp'));
    beforeEach(module('template-module'));

    var element, appId, reqResponse, scope, dscope, reqUrl, $httpBackend, $compile;
    beforeEach(inject(function ($rootScope, _$httpBackend_) {
        scope = $rootScope.$new();
        $httpBackend = _$httpBackend_;
        appId = "123456";
        reqUrl = "https://my-sandbox.app.com/" + appId;
        reqResponse = {}
    }));

    it('should Pass', inject(function (_$compile_) {

        $httpBackend.expect('GET', reqUrl).respond(reqResponse);
        $compile = _$compile_;
        element = angular.element('<directive-a/>');
        element = $compile(element)(scope);
        scope.$digest();
        $httpBackend.flush();

        dscope = element.scope();

        expect(dscope.myVar).toBe(true);
    }));

});

Karma config file :-

// Karma configuration
// http://karma-runner.github.io/0.12/config/configuration-file.html
// generator-karma 0.8.2

module.exports = function(config) {
  config.set({
    autoWatch: true,
    basePath: '../',
    frameworks: ['jasmine'],
    preprocessors: {
        'app/views/**/*.html': 'html2js'
    },
    ngHtml2JsPreprocessor: {
        stripPrefix: "app",
        moduleName: "template-module"
      },

    // list of files / patterns to load in the browser
    files: [
      'bower_components/angular/angular.js',
      'bower_components/angular-mocks/angular-mocks.js',
      'bower_components/angular-animate/angular-animate.js',
      'bower_components/angular-cookies/angular-cookies.js',
      'bower_components/angular-resource/angular-resource.js',
      'bower_components/angular-route/angular-route.js',
      'bower_components/angular-sanitize/angular-sanitize.js',
      'bower_components/angular-touch/angular-touch.js',
      'bower_components/angular-strap/dist/angular-strap.min.js',
      'bower_components/angular-strap/dist/angular-strap.tpl.min.js',
      'bower_components/ng-file-upload/angular-file-upload-shim.min.js',
      'bower_components/ng-file-upload/angular-file-upload.js',
      'bower_components/jquery/dist/jquery.js',
      'app/scripts/**/*.js',
      'test/mock/**/*.js',
      'test/spec/**/*.js',
      'app/views/**/*.html'
    ],

    // list of files / patterns to exclude
    exclude: ['test/spec/e2e/*'],

    // web server port
    port: 8080,

    browsers: ['PhantomJS'],

    // Which plugins to enable
    plugins: [
     // 'karma-chrome-launcher',
      'karma-phantomjs-launcher',
      'karma-jasmine',
      'karma-ng-html2js-preprocessor'
    ],

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

    colors: true,

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

    // Uncomment the following lines if you are using grunt's server to run the tests
    //proxies: {
    //  '/': 'http://localhost:9000/'
    // },
    // URL root prevent conflicts with the site root
    // urlRoot: '_karma_'
  });
};

NOTE : I am already using html2js for $templateCache, and still I am getting this issue.

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

The directive A’s template URL is /views/partials/directivea.html. This doesn’t cause an HTTP GET to be executed because the template is stored in the cache by the preprocessor:

  ngHtml2JsPreprocessor: {
    stripPrefix: "app",
    moduleName: "template-module"
  }

But there is a GET request executed for views/partials/directiveb.html. Note the difference with the first URL: it doesn’t have a leading /. The template cache has an entry for the partial, but its URL in the cache is /views/partials/directiveb.html, not views/partials/directiveb.html.

Make sure you consistently use absolute or relative paths, and depending on your choice, strip the app prefix or the app/ prefix in the preprocessor configuration.

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply