diff --git a/src/ng/http.js b/src/ng/http.js index 9f0a821f3e0f..524044f6d50e 100644 --- a/src/ng/http.js +++ b/src/ng/http.js @@ -375,8 +375,8 @@ function $HttpProvider() { **/ var interceptorFactories = this.interceptors = []; - this.$get = ['$httpBackend', '$$cookieReader', '$cacheFactory', '$rootScope', '$q', '$injector', - function($httpBackend, $$cookieReader, $cacheFactory, $rootScope, $q, $injector) { + this.$get = ['$browser', '$httpBackend', '$$cookieReader', '$cacheFactory', '$rootScope', '$q', '$injector', + function($browser, $httpBackend, $$cookieReader, $cacheFactory, $rootScope, $q, $injector) { var defaultCache = $cacheFactory('$http'); @@ -956,7 +956,7 @@ function $HttpProvider() { }; var chain = [serverRequest, undefined]; - var promise = $q.when(config); + var promise = initiateOutstandingRequest(config); // apply interceptors forEach(reversedInterceptors, function(interceptor) { @@ -975,6 +975,8 @@ function $HttpProvider() { promise = promise.then(thenFn, rejectFn); } + promise.finally(completeOutstandingRequest); + if (useLegacyPromise) { promise.success = function(fn) { assertArgFn(fn, 'fn'); @@ -1000,6 +1002,15 @@ function $HttpProvider() { return promise; + function initiateOutstandingRequest(config) { + $browser.$$incOutstandingRequestCount(); + return $q.when(config); + } + + function completeOutstandingRequest() { + $browser.$$completeOutstandingRequest(noop); + } + function transformResponse(response) { // make a copy since the response must be cacheable var resp = extend({}, response); diff --git a/src/ng/httpBackend.js b/src/ng/httpBackend.js index 0b16b34a7748..f857cefb9c23 100644 --- a/src/ng/httpBackend.js +++ b/src/ng/httpBackend.js @@ -55,7 +55,6 @@ function $HttpBackendProvider() { function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) { // TODO(vojta): fix the signature return function(method, url, post, callback, headers, timeout, withCredentials, responseType) { - $browser.$$incOutstandingRequestCount(); url = url || $browser.url(); if (lowercase(method) == 'jsonp') { @@ -158,7 +157,6 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc jsonpDone = xhr = null; callback(status, response, headersString, statusText); - $browser.$$completeOutstandingRequest(noop); } }; diff --git a/test/e2e/fixtures/http/index.html b/test/e2e/fixtures/http/index.html new file mode 100644 index 000000000000..57cd3ca795cd --- /dev/null +++ b/test/e2e/fixtures/http/index.html @@ -0,0 +1,8 @@ + + +
+

{{text}}

+
+ + + diff --git a/test/e2e/fixtures/http/script.js b/test/e2e/fixtures/http/script.js new file mode 100644 index 000000000000..db636b84734d --- /dev/null +++ b/test/e2e/fixtures/http/script.js @@ -0,0 +1,29 @@ +angular.module('test', []) + .controller('TestCtrl', function($scope, $http, $cacheFactory, $timeout) { + var cache = $cacheFactory('sites'); + var siteUrl = "http://some.site"; + cache.put(siteUrl, "Something"); + $http.get(siteUrl, {cache: cache}).then(function(data) { + $scope.text = "Hello, world!"; + }); + }) + .config(function($httpProvider) { + $httpProvider.interceptors.push(function($q, $window) { + return { + 'request': function(config) { + return $q(function(resolve,reject) { + $window.setTimeout(function() { + resolve(config); + }, 50); + }); + }, + 'response': function(response) { + return $q(function(resolve,reject) { + $window.setTimeout(function() { + resolve(response); + }, 50); + }); + } + }; + }); + }); diff --git a/test/e2e/tests/httpSpec.js b/test/e2e/tests/httpSpec.js new file mode 100644 index 000000000000..66a0990c179f --- /dev/null +++ b/test/e2e/tests/httpSpec.js @@ -0,0 +1,11 @@ + +describe('$http', function() { + beforeEach(function() { + loadFixture("http").andWaitForAngular(); + }); + + it('should have the interpolated text', function() { + expect(element(by.binding('text')).getText()) + .toBe('Hello, world!'); + }); +}); diff --git a/test/ng/httpSpec.js b/test/ng/httpSpec.js index bc27ff5b5fe6..eb2b4af4ed2c 100644 --- a/test/ng/httpSpec.js +++ b/test/ng/httpSpec.js @@ -1866,6 +1866,37 @@ describe('$http', function() { expect(paramSerializer({foo: 'foo', bar: ['bar', 'baz']})).toEqual('bar=bar&bar=baz&foo=foo'); }); }); + + describe('$browser\'s outstandingRequestCount', function() { + var incOutstandingRequestCountSpy, completeOutstandingRequestSpy; + + beforeEach(inject(function($browser) { + incOutstandingRequestCountSpy + = spyOn($browser, '$$incOutstandingRequestCount').andCallThrough(); + completeOutstandingRequestSpy + = spyOn($browser, '$$completeOutstandingRequest').andCallThrough(); + })); + + it('should update $browser outstandingRequestCount on success', function() { + $httpBackend.when('GET').respond(200); + + expect(incOutstandingRequestCountSpy).not.toHaveBeenCalled(); + $http.get(''); + expect(incOutstandingRequestCountSpy).toHaveBeenCalledOnce(); + $httpBackend.flush(); + expect(completeOutstandingRequestSpy).toHaveBeenCalledOnce(); + }); + + it('should update $browser outstandingRequestCount on error', function() { + $httpBackend.when('GET').respond(500); + + expect(incOutstandingRequestCountSpy).not.toHaveBeenCalled(); + $http.get(''); + expect(incOutstandingRequestCountSpy).toHaveBeenCalledOnce(); + $httpBackend.flush(); + expect(completeOutstandingRequestSpy).toHaveBeenCalledOnce(); + }); + }); });