2014-11-22 104 views
12

我试图测试我的响应拦截器,但我很难搞清楚如何模拟$窗口对象。这里是我的代码拦截器:角度茉莉花测试响应拦截器

'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 +重定向情况的任何帮助?

回答

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

非常感谢您的回答。它帮助我理解了一些我不知道的东西。但是,我仍然遇到'Expected'http:// localhost:8080/context.html'为'http://dev-accounts.domain.dev:3000/oauth/authorize ...'的错误。我认为这与'$ window.location.href'有关,它总是返回'http:// localhost:8080/context.html'。有任何想法吗? – lkartono 2014-11-25 12:20:46

+0

你在什么浏览器中运行测试? – user2943490 2014-11-25 12:26:34

+0

我正在使用PhantomJs – lkartono 2014-11-25 12:27:15

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然后用户被重定向到登录页面。

茉莉花规格为同是:

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错误。