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

Commit 4f6f2bc

Browse files
wbyokopetebacondarwin
authored andcommitted
fix($http): properly increment/decrement $browser.outstandingRequestCount
Calling `$http` will not increment `$browser.outstandingRequestCount` until after all (potentially) asynchronous request interceptors have been processed and will decrement it before any (potentially) asynchronous response interceptors have been processed. This can lead to `$browser.notifyWhenNoOutstandingRequests` firing prematurely, which can be problematic in end-to-end tests. This commit fixes this, by synchronizing the increment/decrement operations with `$http`'s internal interceptor promise chain. Fixes #13782 Closes #13862 Closes #14921 BREAKING CHANGE: HTTP requests now update the outstanding request count synchronously. Previously the request count would not have been updated until the request to the server is actually in flight. Now the request count is updated before the async interceptor is called. The new behaviour is correct but it may change the expected behaviour in a small number of e2e test cases where an async request interceptor is being used.
1 parent 56d4563 commit 4f6f2bc

File tree

6 files changed

+93
-5
lines changed

6 files changed

+93
-5
lines changed

src/ng/http.js

+14-3
Original file line numberDiff line numberDiff line change
@@ -374,8 +374,8 @@ function $HttpProvider() {
374374
**/
375375
var interceptorFactories = this.interceptors = [];
376376

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

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

@@ -981,7 +981,7 @@ function $HttpProvider() {
981981
};
982982

983983
var chain = [serverRequest, undefined];
984-
var promise = $q.when(config);
984+
var promise = initiateOutstandingRequest(config);
985985

986986
// apply interceptors
987987
forEach(reversedInterceptors, function(interceptor) {
@@ -1000,6 +1000,8 @@ function $HttpProvider() {
10001000
promise = promise.then(thenFn, rejectFn);
10011001
}
10021002

1003+
promise.finally(completeOutstandingRequest);
1004+
10031005
if (useLegacyPromise) {
10041006
promise.success = function(fn) {
10051007
assertArgFn(fn, 'fn');
@@ -1025,6 +1027,15 @@ function $HttpProvider() {
10251027

10261028
return promise;
10271029

1030+
function initiateOutstandingRequest(config) {
1031+
$browser.$$incOutstandingRequestCount();
1032+
return $q.when(config);
1033+
}
1034+
1035+
function completeOutstandingRequest() {
1036+
$browser.$$completeOutstandingRequest(noop);
1037+
}
1038+
10281039
function transformResponse(response) {
10291040
// make a copy since the response must be cacheable
10301041
var resp = extend({}, response);

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, eventHandlers, uploadEventHandlers) {
58-
$browser.$$incOutstandingRequestCount();
5958
url = url || $browser.url();
6059

6160
if (lowercase(method) === 'jsonp') {
@@ -162,7 +161,6 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
162161
jsonpDone = xhr = null;
163162

164163
callback(status, response, headersString, statusText);
165-
$browser.$$completeOutstandingRequest(noop);
166164
}
167165
};
168166

test/e2e/fixtures/http/index.html

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!DOCTYPE html>
2+
<html ng-app="test">
3+
<body>
4+
<div ng-controller="TestController">
5+
<p>{{text}}</p>
6+
</div>
7+
8+
<script src="angular.js"></script>
9+
<script src="script.js"></script>
10+
</body>
11+
</html>

test/e2e/fixtures/http/script.js

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
angular.
2+
module('test', []).
3+
config(function($httpProvider) {
4+
$httpProvider.interceptors.push(function($q) {
5+
return {
6+
request: function(config) {
7+
return $q(function(resolve) {
8+
setTimeout(resolve, 100, config);
9+
});
10+
},
11+
response: function(response) {
12+
return $q(function(resolve) {
13+
setTimeout(resolve, 100, response);
14+
});
15+
}
16+
};
17+
});
18+
}).
19+
controller('TestController', function($cacheFactory, $http, $scope) {
20+
var url = '/some/url';
21+
22+
var cache = $cacheFactory('test');
23+
cache.put(url, 'Hello, world!');
24+
25+
$http.
26+
get(url, {cache: cache}).
27+
then(function(response) { $scope.text = response.data; });
28+
});

test/e2e/tests/httpSpec.js

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
describe('$http', function() {
2+
beforeEach(function() {
3+
loadFixture('http');
4+
});
5+
6+
it('should correctly update the outstanding request count', function() {
7+
expect(element(by.binding('text')).getText()).toBe('Hello, world!');
8+
});
9+
});

test/ng/httpSpec.js

+31
Original file line numberDiff line numberDiff line change
@@ -1896,6 +1896,37 @@ describe('$http', function() {
18961896
expect(paramSerializer({foo: 'foo', bar: ['bar', 'baz']})).toEqual('bar=bar&bar=baz&foo=foo');
18971897
});
18981898
});
1899+
1900+
describe('$browser\'s outstandingRequestCount', function() {
1901+
var incOutstandingRequestCountSpy, completeOutstandingRequestSpy;
1902+
1903+
beforeEach(inject(function($browser) {
1904+
incOutstandingRequestCountSpy
1905+
= spyOn($browser, '$$incOutstandingRequestCount').andCallThrough();
1906+
completeOutstandingRequestSpy
1907+
= spyOn($browser, '$$completeOutstandingRequest').andCallThrough();
1908+
}));
1909+
1910+
it('should update $browser outstandingRequestCount on success', function() {
1911+
$httpBackend.when('GET').respond(200);
1912+
1913+
expect(incOutstandingRequestCountSpy).not.toHaveBeenCalled();
1914+
$http.get('');
1915+
expect(incOutstandingRequestCountSpy).toHaveBeenCalledOnce();
1916+
$httpBackend.flush();
1917+
expect(completeOutstandingRequestSpy).toHaveBeenCalledOnce();
1918+
});
1919+
1920+
it('should update $browser outstandingRequestCount on error', function() {
1921+
$httpBackend.when('GET').respond(500);
1922+
1923+
expect(incOutstandingRequestCountSpy).not.toHaveBeenCalled();
1924+
$http.get('');
1925+
expect(incOutstandingRequestCountSpy).toHaveBeenCalledOnce();
1926+
$httpBackend.flush();
1927+
expect(completeOutstandingRequestSpy).toHaveBeenCalledOnce();
1928+
});
1929+
});
18991930
});
19001931

19011932

0 commit comments

Comments
 (0)