Search code examples
angularjsunit-testingjasminehttpbackend

AngularJS Unit tests broken after $httpBackend decorator


So I had a situation where we had to hit a "restful" service not under our control, where in order to get json back from the service on a GET call, we have to pass Content-Type="application/json" in the header. Only problem is that Angular strips the Content-Type from request headers on a GET. I found a blog post that suggested using a decorator on $httpBackend that allows us to intercept the call before it is sent and add back the content type:

angular
.module('MyApp')
.decorator('$httpBackend', [
  '$delegate', function($delegate) {
      return function() {
          var contentType, headers;
          headers = arguments[4];
          contentType = headers != null ? headers['X-Force-Content-Type'] : null;
          if (contentType != null && headers['Content-Type'] == null)
            headers['Content-Type'] = contentType;

          return $delegate.apply(null, arguments);
      };
  }]);

so, that works beautifully! Now our problem is that it has broken all unit tests where we used the mock $httpBackend service. The only error we get is "undefined".

Ex. unit test method:

it('should return service.model.error if service returns an exception code from EndProject', 
 inject(function($httpBackend) {
      var mockResponse = sinon.stub({ 'exception': 'Unable to retrieve service data' });
      $httpBackend.whenPUT(this.endProjectUrl).respond(mockResponse);
      var data;
      this.service.EndProject().then(function(fetchedData) {
           data = fetchedData;
      });

      $httpBackend.flush();
      expect(data.error.state).toBe(true);
      expect(data.error.message).toEqual('Unable to retrieve service data');
 }));

PhantomJS 2.1.1 (Mac OS X 0.0.0) projectService EndProject should return service.model.error if service returns an exception code from EndProject FAILED undefined /Users/mlm1205/Documents/THDSource/bolt-projects/html_app/src/app/components/services/project/projectService.spec.js:213:41 invoke@/Users/mlm1205/Documents/THDSource/bolt-projects/html_app/bower_components/angular/angular.js:4560:22 workFn@/Users/mlm1205/Documents/THDSource/bolt-projects/html_app/bower_components/angular-mocks/angular-mocks.js:2518:26


Solution

  • While I marked estus's answer as the solution, based purely on what my question was...in the end, ultimately it wasn't the end result we went with. In a case of not seeing the forest through the trees, the simplest solution was to add an empty data element to the $http call's config. I had tried it before and it didn't work (or so it seemed), but after playing with it again, it did in fact work and we were able to remove the decorator from the application.

    return $http.get(getItemInformationUrl + params, { dataType: 'json', data: '', headers: {'Content-Type': 'application/json'} }).then(getItemInformationCompleted).catch(getItemInformationFailed);