ABCD.ca
ABCD.ca

Reputation: 2495

Why does $httpBackend.flush() result in unexpected request?

If I add the flush() call it gives me "Error: Unexpected request: GET templates/createAccountWithAcme.html". Why on earth is it telling me about a view template and how can I avoid this? This is an Ionic Framework (v 1.0.0 RC2 – AngularJS) project.

EDIT: Previously, I mistakenly omitted the $httpBackend.when or $httpBackend.whenGET call which I've tried. Same error with updated code:

EDIT 2: More details: This is an Ionic Framework project, (v1.0.0 RC2) which uses ui-router. When I tried removing all other tests, I still got the error but noticed the template it complained about was the last one defined in the UI router config (In Ionic the router is $stateProvider). If I added a dummy state to the end of the state definitions it then became THAT one that the test complained about. So I decided the router must be trying to load in the templates which my test wasn't expecting. I've posted a fix.

describe('foo', function() {
  var $http, $httpBackend;
  $http = void 0;
  $httpBackend = void 0;
  $http = null;
  $httpBackend = null;
  beforeEach(module('acme'));
  beforeEach(inject(function($injector) {
    $http = $injector.get('$http');
    $httpBackend = $injector.get('$httpBackend');
    $httpBackend.whenGET('http://www.google.com').respond({});
  }));
  it('should have parsed genres', function() {
    console.log('foo');
    $http({
      method: 'GET',
      url: 'http://www.google.com'
    }).then(function(response) {
      console.log('success: ', response);
    }, function(error) {
      console.log(error);
    });
    $httpBackend.flush();
  });
});

Upvotes: 2

Views: 3841

Answers (3)

zayquan
zayquan

Reputation: 8062

I have seen similar issues with unexpected get requests for HTML when unit testing directives that include other directives in their templates.

The general solution I/we employed was to add some build steps that 'compile' (sort of) all of the project's HTML templates into a single JS file, and then include that JS file in the list of javascript included in karma.conf.js. Now, when the directive loads and makes a request to the template cache for the template, the template will already be loaded (because your JS was included via karma.conf.js), and then no unexpected GET request!

Note also this is generally a good thing to do as part of your build process so your client browsers are not making N extra HTTP requests for HTML templates.

If you are on a node.js based project, you can use ng-htmljs to convert all templates to js. Their docs explain the problem a little better as well : https://www.npmjs.com/package/ng-html2js. This is also conveniently wrapped by grunt - https://www.npmjs.com/package/grunt-html2js, and by gulp - https://www.npmjs.com/package/gulp-ng-html2js.

The node.js grunt solution in more detail:

GruntFile.coffee:

grunt.initConfig
  html2js:
    test:
      src: ['all/my/html_templates/**/*.html']
      dest: 'app/.tmp/templates.js'
    options:
      base : 'app/'
      module: 'myAppTemplates'
      singleModule: true
      htmlmin:
        collapseWhitespace: false
        collapseBooleanAttributes: true
        removeCommentsFromCDATA: true
        removeOptionalTags: true

grunt.registerTask 'test', [
  ...
  'html2js:test'
  'karma:unit'
  ...
]

And in Karma.conf.js:

files: [
  ...
  'app/.tmp/templates.js'
],

And don't forget in your test to include your template module:

beforeEach module 'myAppTemplates'
#or if you are using browserify:
beforeEach window.angular.mock.module 'myAppTemplates'

Upvotes: 1

ABCD.ca
ABCD.ca

Reputation: 2495

I ended up whitelisting all the html templates:

beforeEach ...

//this line solves it
$httpBackend.whenGET(/templates/.*/).respond(200, '');

$httpBackend.whenGET('http://www.google.com').respond({});

...

Upvotes: 3

What you have to do is mock your request in your beforeEach clause:

 beforeEach(inject(function($injector) {
    $http = $injector.get('$http');
    $httpBackend = $injector.get('$httpBackend');
    $httpBackend.whenGet('http://www.google.com')
    .respond('Some return');
  }));

And when you execute .flush() the promise of the get method will be solved

Upvotes: 0

Related Questions