【问题标题】:Angular Jasmine test response interceptorAngular Jasmine 测试响应拦截器
【发布时间】:2014-11-22 02:36:41
【问题描述】:

我正在尝试测试我的响应拦截器,但我很难弄清楚如何模拟 $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 + 重定向案例的任何帮助?

【问题讨论】:

    标签: angularjs testing jasmine response interceptor


    【解决方案1】:

    您应该使用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);
          });
        });
      });
    });
    

    【讨论】:

    • 非常感谢您的回答。它对我理解一些我不知道的东西有很大帮助。但是,我仍然遇到同样的错误Expected 'http://localhost:8080/context.html' to be 'http://dev-accounts.domain.dev:3000/oauth/authorize...。我认为这与$window.location.href 有关,它总是以某种方式返回http://localhost:8080/context.html。有什么想法吗?
    • 您在哪个浏览器中运行测试?
    • 好的,PhantomJS 有很多奇怪的地方——你可能需要提供一个模拟的 $window 对象。用这个更新了答案。
    【解决方案2】:

    这里是 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,则用户被重定向到登录页面。

    同样的茉莉花规格是:

    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 错误调用了拒绝。

    【讨论】:

      猜你喜欢
      • 2020-12-18
      • 2022-10-14
      • 2018-12-05
      • 1970-01-01
      • 1970-01-01
      • 2021-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多