2014-11-22 178 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錯誤。