Skip to content

Commit c9db640

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 angular#13782 Closes angular#13862
1 parent 5a3504a commit c9db640

File tree

3 files changed

+197
-13
lines changed

3 files changed

+197
-13
lines changed

src/ng/http.js

Lines changed: 26 additions & 11 deletions
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

Lines changed: 0 additions & 2 deletions
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

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1869,6 +1869,177 @@ 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+
it('should properly increment/decrement `outstandingRequestCount` '
1935+
+ 'upon error in transformResponse',
1936+
inject(function($exceptionHandler) {
1937+
expect(incOutstandingRequestCountSpy).not.toHaveBeenCalled();
1938+
expect(completeOutstandingRequestSpy).not.toHaveBeenCalled();
1939+
1940+
$httpBackend.when('GET').respond(200);
1941+
$http.get('', {transformResponse: function() { throw new Error(); }});
1942+
1943+
expect(incOutstandingRequestCountSpy).toHaveBeenCalledOnce();
1944+
expect(completeOutstandingRequestSpy).not.toHaveBeenCalled();
1945+
1946+
$httpBackend.flush();
1947+
1948+
expect(incOutstandingRequestCountSpy).toHaveBeenCalledOnce();
1949+
expect(completeOutstandingRequestSpy).toHaveBeenCalledOnce();
1950+
1951+
$exceptionHandler.errors = [];
1952+
})
1953+
);
1954+
});
1955+
1956+
1957+
describe('with interceptors', function() {
1958+
var requestInterceptorCalled;
1959+
var responseInterceptorCalled;
1960+
1961+
1962+
beforeEach(module(function($httpProvider) {
1963+
requestInterceptorCalled = false;
1964+
responseInterceptorCalled = false;
1965+
1966+
$httpProvider.interceptors.push(function($q) {
1967+
return {
1968+
request: function(config) {
1969+
requestInterceptorCalled = true;
1970+
return config._requestError ? $q.reject() : config;
1971+
},
1972+
response: function() {
1973+
responseInterceptorCalled = true;
1974+
return $q.reject();
1975+
}
1976+
};
1977+
});
1978+
}));
1979+
beforeEach(setupServicesAndSpies);
1980+
1981+
1982+
it('should properly increment/decrement `outstandingRequestCount` '
1983+
+ 'upon error in request interceptor',
1984+
function() {
1985+
expect(incOutstandingRequestCountSpy).not.toHaveBeenCalled();
1986+
expect(completeOutstandingRequestSpy).not.toHaveBeenCalled();
1987+
expect(requestInterceptorCalled).toBe(false);
1988+
1989+
$http.get('', {_requestError: true});
1990+
1991+
expect(incOutstandingRequestCountSpy).toHaveBeenCalledOnce();
1992+
expect(completeOutstandingRequestSpy).not.toHaveBeenCalled();
1993+
expect(requestInterceptorCalled).toBe(false);
1994+
1995+
$rootScope.$digest();
1996+
1997+
expect(incOutstandingRequestCountSpy).toHaveBeenCalledOnce();
1998+
expect(completeOutstandingRequestSpy).toHaveBeenCalledOnce();
1999+
expect(requestInterceptorCalled).toBe(true);
2000+
}
2001+
);
2002+
2003+
2004+
it('should properly increment/decrement `outstandingRequestCount` '
2005+
+ 'upon error in response interceptor',
2006+
function() {
2007+
expect(incOutstandingRequestCountSpy).not.toHaveBeenCalled();
2008+
expect(completeOutstandingRequestSpy).not.toHaveBeenCalled();
2009+
expect(responseInterceptorCalled).toBe(false);
2010+
2011+
$httpBackend.when('GET').respond(200);
2012+
$http.get('', {_requestError: false});
2013+
2014+
expect(incOutstandingRequestCountSpy).toHaveBeenCalledOnce();
2015+
expect(completeOutstandingRequestSpy).not.toHaveBeenCalled();
2016+
expect(responseInterceptorCalled).toBe(false);
2017+
2018+
$httpBackend.flush();
2019+
2020+
expect(incOutstandingRequestCountSpy).toHaveBeenCalledOnce();
2021+
expect(completeOutstandingRequestSpy).toHaveBeenCalledOnce();
2022+
expect(responseInterceptorCalled).toBe(true);
2023+
}
2024+
);
2025+
});
2026+
2027+
2028+
function setupServicesAndSpies() {
2029+
inject(function($browser, _$http_, _$httpBackend_, _$rootScope_) {
2030+
$http = _$http_;
2031+
$httpBackend = _$httpBackend_;
2032+
$rootScope = _$rootScope_;
2033+
2034+
incOutstandingRequestCountSpy
2035+
= spyOn($browser, '$$incOutstandingRequestCount').andCallThrough();
2036+
completeOutstandingRequestSpy
2037+
= spyOn($browser, '$$completeOutstandingRequest').andCallThrough();
2038+
});
2039+
}
2040+
});
2041+
2042+
18722043
it('should pass timeout, withCredentials and responseType', function() {
18732044
var $httpBackend = jasmine.createSpy('$httpBackend');
18742045

0 commit comments

Comments
 (0)