Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 4b7b565

Browse files
committed
fix($http): immediatelly increment $browser's outstandingRequestCount
This allows protractor to more reliably detect when all outstanding requests have been completed. Fixes #13782 Closes #13862
1 parent 5a3504a commit 4b7b565

File tree

3 files changed

+175
-13
lines changed

3 files changed

+175
-13
lines changed

src/ng/http.js

+26-11
Original file line numberDiff line numberDiff line change
@@ -375,8 +375,8 @@ function $HttpProvider() {
375375
**/
376376
var interceptorFactories = this.interceptors = [];
377377

378-
this.$get = ['$httpBackend', '$$cookieReader', '$cacheFactory', '$rootScope', '$q', '$injector',
379-
function($httpBackend, $$cookieReader, $cacheFactory, $rootScope, $q, $injector) {
378+
this.$get = ['$browser', '$httpBackend', '$$cookieReader', '$cacheFactory', '$rootScope', '$q', '$injector',
379+
function($browser, $httpBackend, $$cookieReader, $cacheFactory, $rootScope, $q, $injector) {
380380

381381
var defaultCache = $cacheFactory('$http');
382382

@@ -955,25 +955,23 @@ function $HttpProvider() {
955955
return sendReq(config, reqData).then(transformResponse, transformResponse);
956956
};
957957

958-
var chain = [serverRequest, undefined];
958+
var requestInterceptors = [];
959+
var responseInterceptors = [];
959960
var promise = $q.when(config);
960961

961962
// apply interceptors
962963
forEach(reversedInterceptors, function(interceptor) {
963964
if (interceptor.request || interceptor.requestError) {
964-
chain.unshift(interceptor.request, interceptor.requestError);
965+
requestInterceptors.unshift(interceptor.request, interceptor.requestError);
965966
}
966967
if (interceptor.response || interceptor.responseError) {
967-
chain.push(interceptor.response, interceptor.responseError);
968+
responseInterceptors.push(interceptor.response, interceptor.responseError);
968969
}
969970
});
970971

971-
while (chain.length) {
972-
var thenFn = chain.shift();
973-
var rejectFn = chain.shift();
974-
975-
promise = promise.then(thenFn, rejectFn);
976-
}
972+
promise = chainInterceptors(promise, requestInterceptors).then(serverRequest);
973+
promise.finally(completeOutstandingRequest);
974+
promise = chainInterceptors(promise, responseInterceptors);
977975

978976
if (useLegacyPromise) {
979977
promise.success = function(fn) {
@@ -998,6 +996,8 @@ function $HttpProvider() {
998996
promise.error = $httpMinErrLegacyFn('error');
999997
}
1000998

999+
$browser.$$incOutstandingRequestCount();
1000+
10011001
return promise;
10021002

10031003
function transformResponse(response) {
@@ -1010,6 +1010,21 @@ function $HttpProvider() {
10101010
: $q.reject(resp);
10111011
}
10121012

1013+
function chainInterceptors(promise, interceptors) {
1014+
while (interceptors.length) {
1015+
var thenFn = interceptors.shift();
1016+
var rejectFn = interceptors.shift();
1017+
1018+
promise = promise.then(thenFn, rejectFn);
1019+
}
1020+
1021+
return promise;
1022+
}
1023+
1024+
function completeOutstandingRequest() {
1025+
$browser.$$completeOutstandingRequest(noop);
1026+
}
1027+
10131028
function executeHeaderFns(headers, config) {
10141029
var headerContent, processedHeaders = {};
10151030

src/ng/httpBackend.js

-2
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ function $HttpBackendProvider() {
5555
function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
5656
// TODO(vojta): fix the signature
5757
return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
58-
$browser.$$incOutstandingRequestCount();
5958
url = url || $browser.url();
6059

6160
if (lowercase(method) == 'jsonp') {
@@ -158,7 +157,6 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
158157
jsonpDone = xhr = null;
159158

160159
callback(status, response, headersString, statusText);
161-
$browser.$$completeOutstandingRequest(noop);
162160
}
163161
};
164162

test/ng/httpSpec.js

+149
Original file line numberDiff line numberDiff line change
@@ -1869,6 +1869,155 @@ describe('$http', function() {
18691869
});
18701870

18711871

1872+
describe('$browser\'s outstandingRequestCount', function() {
1873+
var $http;
1874+
var $httpBackend;
1875+
var $rootScope;
1876+
var incOutstandingRequestCountSpy;
1877+
var completeOutstandingRequestSpy;
1878+
1879+
1880+
describe('without interceptors', function() {
1881+
beforeEach(setupServicesAndSpies);
1882+
1883+
1884+
it('should immediately call `$browser.$$incOutstandingRequestCount()`', function() {
1885+
expect(incOutstandingRequestCountSpy).not.toHaveBeenCalled();
1886+
$http.get('');
1887+
expect(incOutstandingRequestCountSpy).toHaveBeenCalledOnce();
1888+
});
1889+
1890+
1891+
it('should call `$browser.$$completeOutstandingRequest()` upon response', function() {
1892+
$httpBackend.when('GET').respond(200);
1893+
1894+
expect(completeOutstandingRequestSpy).not.toHaveBeenCalled();
1895+
$http.get('');
1896+
expect(completeOutstandingRequestSpy).not.toHaveBeenCalled();
1897+
$httpBackend.flush();
1898+
expect(completeOutstandingRequestSpy).toHaveBeenCalledOnce();
1899+
});
1900+
1901+
1902+
it('should call `$browser.$$completeOutstandingRequest()` upon error', function() {
1903+
$httpBackend.when('GET').respond(500);
1904+
1905+
expect(completeOutstandingRequestSpy).not.toHaveBeenCalled();
1906+
$http.get('');
1907+
expect(completeOutstandingRequestSpy).not.toHaveBeenCalled();
1908+
$httpBackend.flush();
1909+
expect(completeOutstandingRequestSpy).toHaveBeenCalledOnce();
1910+
});
1911+
1912+
1913+
it('should properly increment/decrement `outstandingRequestCount` '
1914+
+ 'upon error in transformRequest',
1915+
inject(function($exceptionHandler) {
1916+
expect(incOutstandingRequestCountSpy).not.toHaveBeenCalled();
1917+
expect(completeOutstandingRequestSpy).not.toHaveBeenCalled();
1918+
1919+
$http.get('', {transformRequest: function() { throw new Error(); }});
1920+
1921+
expect(incOutstandingRequestCountSpy).toHaveBeenCalledOnce();
1922+
expect(completeOutstandingRequestSpy).not.toHaveBeenCalled();
1923+
1924+
$rootScope.$digest();
1925+
1926+
expect(incOutstandingRequestCountSpy).toHaveBeenCalledOnce();
1927+
expect(completeOutstandingRequestSpy).toHaveBeenCalledOnce();
1928+
1929+
$exceptionHandler.errors = [];
1930+
})
1931+
);
1932+
});
1933+
1934+
1935+
describe('with interceptors', function() {
1936+
var requestInterceptorCalled;
1937+
var responseInterceptorCalled;
1938+
1939+
1940+
beforeEach(module(function($httpProvider) {
1941+
requestInterceptorCalled = false;
1942+
responseInterceptorCalled = false;
1943+
1944+
$httpProvider.interceptors.push(function($q) {
1945+
return {
1946+
request: function(config) {
1947+
requestInterceptorCalled = true;
1948+
return config._requestError ? $q.reject() : config;
1949+
},
1950+
response: function() {
1951+
responseInterceptorCalled = true;
1952+
return $q.reject();
1953+
}
1954+
};
1955+
});
1956+
}));
1957+
beforeEach(setupServicesAndSpies);
1958+
1959+
1960+
it('should properly increment/decrement `outstandingRequestCount` '
1961+
+ 'upon error in request interceptor',
1962+
function() {
1963+
expect(incOutstandingRequestCountSpy).not.toHaveBeenCalled();
1964+
expect(completeOutstandingRequestSpy).not.toHaveBeenCalled();
1965+
expect(requestInterceptorCalled).toBe(false);
1966+
1967+
$http.get('', {_requestError: true});
1968+
1969+
expect(incOutstandingRequestCountSpy).toHaveBeenCalledOnce();
1970+
expect(completeOutstandingRequestSpy).not.toHaveBeenCalled();
1971+
expect(requestInterceptorCalled).toBe(false);
1972+
1973+
$rootScope.$digest();
1974+
1975+
expect(incOutstandingRequestCountSpy).toHaveBeenCalledOnce();
1976+
expect(completeOutstandingRequestSpy).toHaveBeenCalledOnce();
1977+
expect(requestInterceptorCalled).toBe(true);
1978+
}
1979+
);
1980+
1981+
1982+
it('should properly increment/decrement `outstandingRequestCount` '
1983+
+ 'upon error in response interceptor',
1984+
function() {
1985+
expect(incOutstandingRequestCountSpy).not.toHaveBeenCalled();
1986+
expect(completeOutstandingRequestSpy).not.toHaveBeenCalled();
1987+
expect(responseInterceptorCalled).toBe(false);
1988+
1989+
$httpBackend.when('GET').respond(200);
1990+
$http.get('', {_requestError: false});
1991+
1992+
expect(incOutstandingRequestCountSpy).toHaveBeenCalledOnce();
1993+
expect(completeOutstandingRequestSpy).not.toHaveBeenCalled();
1994+
expect(responseInterceptorCalled).toBe(false);
1995+
1996+
$httpBackend.flush();
1997+
1998+
expect(incOutstandingRequestCountSpy).toHaveBeenCalledOnce();
1999+
expect(completeOutstandingRequestSpy).toHaveBeenCalledOnce();
2000+
expect(responseInterceptorCalled).toBe(true);
2001+
}
2002+
);
2003+
});
2004+
2005+
2006+
function setupServicesAndSpies() {
2007+
inject(function($browser, _$http_, _$httpBackend_, _$rootScope_) {
2008+
$http = _$http_;
2009+
$httpBackend = _$httpBackend_;
2010+
$rootScope = _$rootScope_;
2011+
2012+
incOutstandingRequestCountSpy
2013+
= spyOn($browser, '$$incOutstandingRequestCount').andCallThrough();
2014+
completeOutstandingRequestSpy
2015+
= spyOn($browser, '$$completeOutstandingRequest').andCallThrough();
2016+
});
2017+
}
2018+
});
2019+
2020+
18722021
it('should pass timeout, withCredentials and responseType', function() {
18732022
var $httpBackend = jasmine.createSpy('$httpBackend');
18742023

0 commit comments

Comments
 (0)