Angular Jasmine测试反应拦截器

时间:2014-11-22 02:36:42

标签: angularjs testing jasmine response interceptor

我正在尝试测试我的响应拦截器,但我很难搞清楚如何模拟$ window对象。这是我的拦截器代码:

'use strict';

angular.module('Domain.handlers')

.config(function($httpProvider) {
  $httpProvider.responseInterceptors.push('UnauthorizedInterceptor');
})

.factory('UnauthorizedInterceptor', function($q, $injector, $window, ENV) {
  return function(promise) {
    var success = function(response) { return response; };
    var error   = function(response) {
      if (response.status === 401) {
        $window.location.href = ENV.account + '/oauth/authorize?client_id=' + ENV.clientId + '&redirect_uri=' + ENV.app + '/oauth/callback&response_type=token';
      }
      return $q.reject(response);
    };
    return promise.then(success, error);
  };
});

这是我的规格:

'use strict';

describe('Domain.handlers.response', function() {
  var UnauthorizedInterceptor,
      httpProvider,
      $httpBackend,
      $http,
      token = '123456789';

  beforeEach(module('Domain.handlers', function($httpProvider) {
    httpProvider = $httpProvider;
  }));

  beforeEach(inject(function(_UnauthorizedInterceptor_, _$httpBackend_, _$http_) {
    UnauthorizedInterceptor = _UnauthorizedInterceptor_;
    $httpBackend = _$httpBackend_;
    $http = _$http_;
  }));

  describe('UnauthorizedInterceptor', function() {
    it('should be defined', function() {
      expect(UnauthorizedInterceptor).toBeDefined();
    });

    describe('HTTP status', function() {
      describe('is 200 OK', function() {
        it('should return a 200 status', function() {
          $httpBackend.expectGET('http://api.domain.com/clients').respond(200, {});
          $http.get('http://api.domain.com/clients');
          $httpBackend.flush();
        });
      });

      describe('is 401 Unauthorized', function() {
        it('should redirect to accounts.domain.com', inject(function($window) {
          $httpBackend.expectGET('http://api.domain.com/clients').respond(401, {});
          $http.get('http://api.domain.com/clients');
          expect($window.location.href).toEqual('http://accounts.domain.com/oauth/.....');
          $httpBackend.flush();
        }));
      });
    });
  });
});

我有一个:Expected 'http://localhost:8080/context.html' to equal 'http://accounts.domain.com/oauth/.....'。有关如何正确模拟$ window对象的更多帮助,或者更一般地说如何测试401 +重定向情况?

2 个答案:

答案 0 :(得分:14)

您应该使用more recent syntax构建拦截器定义。您的URL构造也应该在服务中,以便在测试中很容易被模拟。

.factory('UnauthorizedInterceptor', function($q, $window, OtherService) {
  var service = {
    responseError: handleUnauthorized
  };

  return service;

  function handleUnauthorized(rejection) {
    if (rejection.status === 401) {
      $window.location.href = OtherService.getUnauthorizedRedirectURL();
    }
    return $q.reject(rejection);
  }
});

这样做可以让你像其他工厂一样进行测试,而不必担心$http拦截器的内部实现,或者必须使用$httpBackend模拟响应。

describe('Domain.handlers.response', function() {
  var $window,
      UnauthorizedInterceptor,
      OtherService,
      redirectUrl = 'someUrl';

  beforeEach(module('Domain.handlers'));

  beforeEach(function () {
    $window = { location: { href: null } };

    module(function($provide) {
      $provide.value('$window', $window);
    });
  });

  beforeEach(inject(function(_UnauthorizedInterceptor_, _OtherService_) {
    UnauthorizedInterceptor = _UnauthorizedInterceptor_;
    OtherService = _OtherService_;

    spyOn(OtherService, 'getUnauthorizedRedirectURL').andReturn(redirectUrl);
  }));

  describe('UnauthorizedInterceptor', function() {
    it('should be defined', function() {
      expect(UnauthorizedInterceptor).toBeDefined();
    });

    it('should have a handler for responseError', function () {
      expect(angular.isFunction(UnauthorizedInterceptor.responseError)).toBe(true);
    });

    describe('when HTTP 401', function () {
      beforeEach(function () {
        var rejection = { status: 401 };
        UnauthorizedInterceptor.responseError(rejection);
      });

      it('should set window location', function () {
        expect($window.location.href).toBe(redirectUrl);
      });
    });

    describe('when not HTTP 401', function () {
      beforeEach(function () {
        var rejection = { status: 500 };
        UnauthorizedInterceptor.responseError(rejection);
      });

      it('should not set window location', function () {
        expect($window.location.href).not.toBe(redirectUrl);
      });
    });
  });
});

答案 1 :(得分:4)

这是responseError拦截器和相应的jasmine规范的一个例子。

angular.module('interceptorDemo').factory('redirectInterceptor', ['$q', '$window', function($q, $window) {
    'use strict';

    function handleUnauthorizedAccess(config) {
        if (401 === config.status) {
            $window.location = '/signIn/';
        }
        return $q.reject(config);
    }

    return {
        responseError: handleUnauthorizedAccess
    };
}]);

拦截器拦截ajax请求,如果请求失败,则如果状态代码为401则将用户重定向到signIn页面。

Jasmine规范同样如下:

describe('redirectInterceptor specs', function() {

    var redirectInterceptor, $q;

    beforeEach(module('interceptorDemo'));

    beforeEach(function() {
        $window = {
            location: {
                href: null
            }
        };

        module(function($provide) {
            $provide.value('$window', $window);
        });
    });

    beforeEach(inject(function(_redirectInterceptor_, _$q_) {
        redirectInterceptor = _redirectInterceptor_;
        $q = _$q_;
        spyOn($q, 'reject');
    }));

    describe('redirectInterceptor specs', function() {
        it('should redirect to signIn page for unauthorized access', function() {
            var response = {
                status: 401,
                config: {}
            };
            var promise = redirectInterceptor.responseError(response);
            expect($window.location).toBe('/singIn/');
            expect($q.reject).toHaveBeenCalled();
        });

        it('should not redirect to signIn page for error code other than unauthorized access', function() {
            var response = {
                status: 404,
                config: {}
            };
            var promise = redirectInterceptor.responseError(response);
            expect($window.location).toEqual({
                href: null
            });
            expect($q.reject).toHaveBeenCalled();
        });

    });
});

我们已经监视$ q,所以我们也可以测试拒绝被调用401错误。