Angular Jasmine test response interceptor
angularjs, interceptor, jasmine, response, testing
Solution
You should structure your interceptor definition using the more recent syntax. Your URL construction should also be in a service so that it can easily be mocked in tests.
.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);
}
});
Doing so will let you test it just like any other factory without having to worry about the internal implementations of `$http` interceptors, or having to mock responses with `$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);
});
});
});
});
Problem
I'm trying to test my response interceptor but I have a hard time figuring out how to mock the $window object. Here is my interceptor code : ``` '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); }; }); ``` And here is my spec : ``` '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(); })); }); }); }); }); ``` I've got a : `Expected 'http://localhost:8080/context.html' to equal 'http://accounts.domain.com/oauth/.....'`. Any help on how to mock properly the $window object or more generally how to test a 401 + redirection case?