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

$http service #609

Closed
wants to merge 28 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
31925e7
feat($browser): xhr returns raw request object
vojtajina Aug 3, 2011
42a2548
fix($browser.xhr): change method "JSON" to "JSONP"
vojtajina Aug 10, 2011
d05bd63
fix($browser.xhr): respond with internal -2 status on jsonp error
vojtajina Aug 10, 2011
c240ab6
fix($browser.xhr): fix IE6, IE7 bug - sync xhr when serving from cache
vojtajina Aug 18, 2011
d0c3c43
feat($browser.xhr): add timeout option to abort request
vojtajina Aug 18, 2011
15dea1e
feat($cacheFactory): add general purpose $cacheFactory service
IgorMinar Feb 17, 2011
343d25f
feat($http): new $http service, removing $xhr.*
vojtajina Aug 4, 2011
6993a40
feat(mocks.$httpBackend): add $httpBackend mock
vojtajina Aug 16, 2011
ce73a50
feat($templateCache): add $templateCache - shared by ng:include, ng:view
vojtajina Oct 18, 2011
9a7447e
feat(mocks.$browser): add simple addJs() method into $browser mock
vojtajina Aug 23, 2011
c19f2de
feat($httpBackend): extract $browser.xhr into separate service
vojtajina Aug 23, 2011
e02df36
feat($http): expose pendingRequests and configuration object
vojtajina Oct 18, 2011
821e6c7
fix($http): allow multiple json vulnerability prefixes
vojtajina Oct 19, 2011
5448f04
fix($resource): to work with $http, $httpBackend services
vojtajina Oct 19, 2011
a315a10
refactor($http): change callback matching mechanism
vojtajina Oct 27, 2011
85dba30
fix($http): add .send() alias for .retry() to get better stack trace …
vojtajina Oct 31, 2011
ceae30a
feat(mock.$httpBackend): throw when nothing to flush, dump data/heade…
vojtajina Oct 31, 2011
ba7bae4
feat($http): broadcast $http.request event
vojtajina Oct 31, 2011
f646f01
feat(mock.$httpBackend): add verifyNoOutstandingRequest method
vojtajina Nov 1, 2011
77d4c38
fix(mock.$httpBackend): flush() even requests sent during callbacks
vojtajina Nov 1, 2011
a7f13bf
refactor(mock.$httpBackend): rename when().then() to when().respond()
vojtajina Nov 1, 2011
033dac6
feat(mock.$httpBackend): verify expectations after flush()
vojtajina Nov 1, 2011
cff7b97
feat(mock.$httpBackend): say which request was expected when unexpect…
vojtajina Nov 3, 2011
e249231
feat($httpBackend): fix 0 status code when "file" protocol
vojtajina Nov 4, 2011
55cebd4
feat($http): allow passing custom cache instance per request
vojtajina Nov 4, 2011
0ef4d43
style(): get rid off some jsl warnings
vojtajina Nov 5, 2011
0144ede
fix($http): default json transformation should not crash on angular t…
vojtajina Nov 5, 2011
01b3677
refactor(ng:view, ng:include): pass cache instance into $http
vojtajina Nov 5, 2011
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat($httpBackend): extract $browser.xhr into separate service
- remove whole $browser.xhr stuff
- remove whole mock $browser.xhr stuff
- add $httpBackend service + migrate unit tests from $browser
- add temporary API to access $browser's outstandingRequests count
  • Loading branch information
vojtajina committed Nov 19, 2011
commit c19f2deb80d0623da3610f35e1c7f7ebb83bacc3
180 changes: 20 additions & 160 deletions src/angular-mocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ angular.module.ngMock.$Browser = function() {
self.$$lastUrl = self.$$url; // used by url polling fn
self.pollFns = [];

// TODO(vojta): remove this temporary api
self.$$completeOutstandingRequest = noop;
self.$$incOutstandingRequestCount = noop;


// register url polling fn

Expand All @@ -73,165 +77,6 @@ angular.module.ngMock.$Browser = function() {
return listener;
};


/**
* @ngdoc method
* @name angular.module.ngMock.$browser#xhr
* @methodOf angular.module.ngMock.$browser
*
* @description
* Generic method for training browser to expect a request in a test and respond to it.
*
* See also convenience methods for browser training:
*
* - {@link #xhr.expectGET}
* - {@link #xhr.expectPOST}
* - {@link #xhr.expectPUT}
* - {@link #xhr.expectDELETE}
* - {@link #xhr.expectJSON}
*
* To flush pending requests in tests use
* {@link #xhr.flush}.
*
* @param {string} method Expected HTTP method.
* @param {string} url Url path for which a request is expected.
* @param {(object|string)=} data Expected body of the (POST) HTTP request.
* @param {function(number, *)} callback Callback to call when response is flushed.
* @param {object} headers Key-value pairs of expected headers.
* @returns {object} Response configuration object. You can call its `respond()` method to
* configure what should the browser mock return when the response is
* {@link #xhr.flush flushed}.
*/
self.xhr = function(method, url, data, callback, headers) {
headers = headers || {};
if (data && angular.isObject(data)) data = angular.toJson(data);
if (data && angular.isString(data)) url += "|" + data;
var expect = expectations[method] || {};
var expectation = expect[url];
if (!expectation) {
throw new Error("Unexpected request for method '" + method + "' and url '" + url + "'.");
}
requests.push(function() {
angular.forEach(expectation.headers, function(value, key){
if (headers[key] !== value) {
throw new Error("Missing HTTP request header: " + key + ": " + value);
}
});
callback(expectation.code, expectation.response);
});
// TODO(vojta): return mock request object
};
self.xhr.expectations = expectations;
self.xhr.requests = requests;
self.xhr.expect = function(method, url, data, headers) {
if (data && angular.isObject(data)) data = angular.toJson(data);
if (data && angular.isString(data)) url += "|" + data;
var expect = expectations[method] || (expectations[method] = {});
return {
respond: function(code, response) {
if (!angular.isNumber(code)) {
response = code;
code = 200;
}
expect[url] = {code:code, response:response, headers: headers || {}};
}
};
};

/**
* @ngdoc method
* @name angular.module.ngMock.$browser#xhr.expectGET
* @methodOf angular.module.ngMock.$browser
*
* @description
* Trains browser to expect a `GET` request and respond to it.
*
* @param {string} url Url path for which a request is expected.
* @returns {object} Response configuration object. You can call its `respond()` method to
* configure what should the browser mock return when the response is
* {@link angular.module.ngMock.$browser#xhr.flush flushed}.
*/
self.xhr.expectGET = angular.bind(self, self.xhr.expect, 'GET');

/**
* @ngdoc method
* @name angular.module.ngMock.$browser#xhr.expectPOST
* @methodOf angular.module.ngMock.$browser
*
* @description
* Trains browser to expect a `POST` request and respond to it.
*
* @param {string} url Url path for which a request is expected.
* @returns {object} Response configuration object. You can call its `respond()` method to
* configure what should the browser mock return when the response is
* {@link angular.module.ngMock.$browser#xhr.flush flushed}.
*/
self.xhr.expectPOST = angular.bind(self, self.xhr.expect, 'POST');

/**
* @ngdoc method
* @name angular.module.ngMock.$browser#xhr.expectDELETE
* @methodOf angular.module.ngMock.$browser
*
* @description
* Trains browser to expect a `DELETE` request and respond to it.
*
* @param {string} url Url path for which a request is expected.
* @returns {object} Response configuration object. You can call its `respond()` method to
* configure what should the browser mock return when the response is
* {@link angular.module.ngMock.$browser#xhr.flush flushed}.
*/
self.xhr.expectDELETE = angular.bind(self, self.xhr.expect, 'DELETE');

/**
* @ngdoc method
* @name angular.module.ngMock.$browser#xhr.expectPUT
* @methodOf angular.module.ngMock.$browser
*
* @description
* Trains browser to expect a `PUT` request and respond to it.
*
* @param {string} url Url path for which a request is expected.
* @returns {object} Response configuration object. You can call its `respond()` method to
* configure what should the browser mock return when the response is
* {@link angular.module.ngMock.$browser#xhr.flush flushed}.
*/
self.xhr.expectPUT = angular.bind(self, self.xhr.expect, 'PUT');

/**
* @ngdoc method
* @name angular.module.ngMock.$browser#xhr.expectJSON
* @methodOf angular.module.ngMock.$browser
*
* @description
* Trains browser to expect a `JSON` request and respond to it.
*
* @param {string} url Url path for which a request is expected.
* @returns {object} Response configuration object. You can call its `respond()` method to
* configure what should the browser mock return when the response is
* {@link angular.module.ngMock.$browser#xhr.flush flushed}.
*/
self.xhr.expectJSON = angular.bind(self, self.xhr.expect, 'JSON');

/**
* @ngdoc method
* @name angular.module.ngMock.$browser#xhr.flush
* @methodOf angular.module.ngMock.$browser
*
* @description
* Flushes all pending requests and executes xhr callbacks with the trained response as the
* argument.
*/
self.xhr.flush = function() {
if (requests.length == 0) {
throw new Error("No xhr requests to be flushed!");
}

while(requests.length) {
requests.pop()();
}
};

self.cookieHash = {};
self.lastCookieHash = {};
self.deferredFns = [];
Expand Down Expand Up @@ -871,9 +716,24 @@ function MockHttpExpectation(method, url, data, headers) {

function MockXhr() {

// hack for testing $http
// hack for testing $http, $httpBackend
MockXhr.$$lastInstance = this;

this.open = function(method, url, async) {
this.$$method = method;
this.$$url = url;
this.$$async = async;
this.$$headers = {};
};

this.send = function(data) {
this.$$data = data;
};

this.setRequestHeader = function(key, value) {
this.$$headers[key] = value;
};

this.getResponseHeader = function(name) {
return this.$$headers[name];
};
Expand Down
102 changes: 4 additions & 98 deletions src/service/browser.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,5 @@
'use strict';

//////////////////////////////
// Browser
//////////////////////////////
var XHR = window.XMLHttpRequest || function() {
try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) {}
try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) {}
try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e3) {}
throw new Error("This browser does not support XMLHttpRequest.");
};


/**
* @ngdoc object
* @name angular.module.ng.$browser
Expand All @@ -33,7 +22,7 @@ var XHR = window.XMLHttpRequest || function() {
* @param {object} $log console.log or an object with the same interface.
* @param {object} $sniffer $sniffer service
*/
function Browser(window, document, body, XHR, $log, $sniffer) {
function Browser(window, document, body, $log, $sniffer) {
var self = this,
rawDocument = document[0],
location = window.location,
Expand All @@ -44,13 +33,12 @@ function Browser(window, document, body, XHR, $log, $sniffer) {

self.isMock = false;

//////////////////////////////////////////////////////////////
// XHR API
//////////////////////////////////////////////////////////////
var idCounter = 0;
var outstandingRequestCount = 0;
var outstandingRequestCallbacks = [];

// TODO(vojta): remove this temporary api
self.$$completeOutstandingRequest = completeOutstandingRequest;
self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };

/**
* Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
Expand All @@ -73,88 +61,6 @@ function Browser(window, document, body, XHR, $log, $sniffer) {
}
}

// normalize IE bug (http://bugs.jquery.com/ticket/1450)
function fixStatus(status) {
return status == 1223 ? 204 : status;
}

/**
* @ngdoc method
* @name angular.module.ng.$browser#xhr
* @methodOf angular.module.ng.$browser
*
* @param {string} method Requested method (get|post|put|delete|head|json)
* @param {string} url Requested url
* @param {?string} post Post data to send (null if nothing to post)
* @param {function(number, string)} callback Function that will be called on response
* @param {object=} header additional HTTP headers to send with XHR.
* Standard headers are:
* <ul>
* <li><tt>Content-Type</tt>: <tt>application/x-www-form-urlencoded</tt></li>
* <li><tt>Accept</tt>: <tt>application/json, text/plain, &#42;/&#42;</tt></li>
* <li><tt>X-Requested-With</tt>: <tt>XMLHttpRequest</tt></li>
* </ul>
*
* @param {number=} timeout Timeout in ms, when the request will be aborted
* @returns {XMLHttpRequest|undefined} Raw XMLHttpRequest object or undefined when JSONP method
*
* @description
* Send ajax request
*
* TODO(vojta): change signature of this method to (method, url, data, headers, callback)
*/
self.xhr = function(method, url, post, callback, headers, timeout) {
outstandingRequestCount ++;
if (lowercase(method) == 'jsonp') {
var callbackId = ("angular_" + Math.random() + '_' + (idCounter++)).replace(/\d\./, '');
window[callbackId] = function(data) {
window[callbackId].data = data;
};

var script = self.addJs(url.replace('JSON_CALLBACK', callbackId), function() {
if (window[callbackId].data) {
completeOutstandingRequest(callback, 200, window[callbackId].data);
} else {
completeOutstandingRequest(callback, -2);
}
delete window[callbackId];
body[0].removeChild(script);
});
} else {
var xhr = new XHR();
xhr.open(method, url, true);
forEach(headers, function(value, key) {
if (value) xhr.setRequestHeader(key, value);
});

var status;
xhr.send(post || '');

// IE6, IE7 bug - does sync when serving from cache
if (xhr.readyState == 4) {
setTimeout(function() {
completeOutstandingRequest(callback, fixStatus(status || xhr.status), xhr.responseText);
}, 0);
} else {
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
completeOutstandingRequest(callback, fixStatus(status || xhr.status),
xhr.responseText);
}
};
}

if (timeout > 0) {
setTimeout(function() {
status = -1;
xhr.abort();
}, timeout);
}

return xhr;
}
};

/**
* @private
* Note: this method is used only by scenario runner
Expand Down
Loading