aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorIgor Minar2012-01-10 19:16:33 -0800
committerIgor Minar2012-01-13 14:28:20 -0800
commit939c8e8fac0487da12e56291d69c5199a8ed9a30 (patch)
treef249b1cada0b289db0ad1dccf150f7b244c9c527 /src
parentd2ba4c5170f604f2610aaef1d205137e2848a791 (diff)
downloadangular.js-939c8e8fac0487da12e56291d69c5199a8ed9a30.tar.bz2
docs($http, $httpBackend): docs docs docs
Diffstat (limited to 'src')
-rw-r--r--src/angular-mocks.js576
-rw-r--r--src/service/http.js322
-rw-r--r--src/service/httpBackend.js5
3 files changed, 868 insertions, 35 deletions
diff --git a/src/angular-mocks.js b/src/angular-mocks.js
index 0d284884..dfa43d7d 100644
--- a/src/angular-mocks.js
+++ b/src/angular-mocks.js
@@ -580,11 +580,175 @@ angular.mock.dump = function(object) {
/**
* @ngdoc object
* @name angular.module.ngMock.$httpBackend
- * @describe
- * Fake version of `$httpBackend` service used by the `$http` service during unit testing.
+ * @description
+ * Fake HTTP backend implementation suitable for unit testing application that use the
+ * {@link angular.module.ng.$http $http service}.
+ *
+ * *Note*: For fake http backend implementation suitable for end-to-end testing or backend-less
+ * development please see {@link angular.module.ngMockE2E.$httpBackend e2e $httpBackend mock}.
+ *
+ * During unit testing, we want our unit tests to run quickly and have no external dependencies so
+ * we don’t want to send {@link https://developer.mozilla.org/en/xmlhttprequest XHR} or
+ * {@link http://en.wikipedia.org/wiki/JSONP JSONP} requests to a real server. All we really need is
+ * to verify whether a certain request has been sent or not, or alternatively just let the
+ * application make requests, respond with pre-trained responses and assert that the end result is
+ * what we expect it to be.
+ *
+ * This mock implementation can be used to respond with static or dynamic responses via the
+ * `expect` and `when` apis and their shortcuts (`expectGET`, `whenPOST`, etc).
+ *
+ * When an Angular application needs some data from a server, it calls the $http service, which
+ * sends the request to a real server using $httpBackend service. With dependency injection, it is
+ * easy to inject $httpBackend mock (which has the same API as $httpBackend) and use it to verify
+ * the requests and respond with some testing data without sending a request to real server.
+ *
+ * There are two ways to specify what test data should be returned as http responses by the mock
+ * backend when the code under test makes http requests:
+ *
+ * - `$httpBackend.expect` - specifies a request expectation
+ * - `$httpBackend.when` - specifies a backend definition
+ *
+ *
+ * # Request Expectations vs Backend Definitions
+ *
+ * Request expectations provide a way to make assertions about requests made by the application and
+ * to define responses for those requests. The test will fail if the expected requests are not made
+ * or they are made in the wrong order.
+ *
+ * Backend definitions allow you to define a fake backend for your application which doesn't assert
+ * if a particular request was made or not, it just returns a trained response if a request is made.
+ * The test will pass whether or not the request gets made during testing.
+ *
*
- * This implementation can be used to respond with static or dynamic responses via the `expect` and
- * `when` apis and their shortcuts (`expectGET`, `whenPOST`, etc).
+ * <table class="table">
+ * <tr><th width="220px"></th><th>Request expectations</th><th>Backend definitions</th></tr>
+ * <tr>
+ * <th>Syntax</th>
+ * <td>.expect(...).respond(...)</td>
+ * <td>.when(...).respond(...)</td>
+ * </tr>
+ * <tr>
+ * <th>Typical usage</th>
+ * <td>strict unit tests</td>
+ * <td>loose (black-box) unit testing</td>
+ * </tr>
+ * <tr>
+ * <th>Fulfills multiple requests</th>
+ * <td>NO</td>
+ * <td>YES</td>
+ * </tr>
+ * <tr>
+ * <th>Order of requests matters</th>
+ * <td>YES</td>
+ * <td>NO</td>
+ * </tr>
+ * <tr>
+ * <th>Request required</th>
+ * <td>YES</td>
+ * <td>NO</td>
+ * </tr>
+ * <tr>
+ * <th>Response required</th>
+ * <td>optional (see below)</td>
+ * <td>YES</td>
+ * </tr>
+ * </table>
+ *
+ * In cases where both backend definitions and request expectations are specified during unit
+ * testing, the request expectations are evaluated first.
+ *
+ * If a request expectation has no response specified, the algorithm will search your backend
+ * definitions for an appropriate response.
+ *
+ * If a request didn't match any expectation or if the expectation doesn't have the response
+ * defined, the backend definitions are evaluated in sequential order to see if any of them match
+ * the request. The response from the first matched definition is returned.
+ *
+ *
+ * # Flushing HTTP requests
+ *
+ * The $httpBackend used in production, always responds to requests with responses asynchronously.
+ * If we preserved this behavior in unit testing, we'd have to create async unit tests, which are
+ * hard to write, follow and maintain. At the same time the testing mock, can't respond
+ * synchronously because that would change the execution of the code under test. For this reason the
+ * mock $httpBackend has a `flush()` method, which allows the test to explicitly flush pending
+ * requests and thus preserving the async api of the backend, while allowing the test to execute
+ * synchronously.
+ *
+ *
+ * # Unit testing with mock $httpBackend
+ *
+ * <pre>
+ // controller
+ function MyController($http) {
+ var scope = this;
+
+ $http.get('/auth.py').success(function(data) {
+ scope.user = data;
+ });
+
+ this.saveMessage = function(message) {
+ scope.status = 'Saving...';
+ $http.post('/add-msg.py', message).success(function(response) {
+ scope.status = '';
+ }).error(function() {
+ scope.status = 'ERROR!';
+ });
+ };
+ }
+
+ // testing controller
+ var $http;
+
+ beforeEach(inject(function($injector) {
+ $httpBackend = $injector.get('$httpBackend');
+
+ // backend definition common for all tests
+ $httpBackend.when('GET', '/auth.py').respond({userId: 'userX'}, {'A-Token': 'xxx'});
+ }));
+
+
+ afterEach(function() {
+ $httpBackend.verifyNoOutstandingExpectation();
+ $httpBackend.verifyNoOutstandingRequest();
+ });
+
+
+ it('should fetch authentication token', function() {
+ $httpBackend.expectGET('/auth.py');
+ var controller = scope.$new(MyController);
+ $httpBackend.flush();
+ });
+
+
+ it('should send msg to server', function() {
+ // now you don’t care about the authentication, but
+ // the controller will still send the request and
+ // $httpBackend will respond without you having to
+ // specify the expectation and response for this request
+ $httpBackend.expectPOST('/add-msg.py', 'message content').respond(201, '');
+
+ var controller = scope.$new(MyController);
+ $httpBackend.flush();
+ controller.saveMessage('message content');
+ expect(controller.status).toBe('Saving...');
+ $httpBackend.flush();
+ expect(controller.status).toBe('');
+ });
+
+
+ it('should send auth header', function() {
+ $httpBackend.expectPOST('/add-msg.py', undefined, function(headers) {
+ // check if the header was send, if it wasn't the expectation won't
+ // match the request and the test will fail
+ return headers['Authorization'] == 'xxx';
+ }).respond(201, '');
+
+ var controller = scope.$new(MyController);
+ controller.saveMessage('whatever');
+ $httpBackend.flush();
+ });
+ </pre>
*/
angular.mock.$HttpBackendProvider = function() {
this.$get = [createHttpBackendMock];
@@ -677,6 +841,26 @@ function createHttpBackendMock($delegate, $defer) {
(expectation ? 'Expected ' + expectation : 'No more request expected'));
}
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#when
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Creates a new backend definition.
+ *
+ * @param {string} method HTTP method.
+ * @param {string|RegExp} url HTTP url.
+ * @param {(string|RegExp)=} data HTTP request body.
+ * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
+ * object and returns true if the headers match the current definition.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ *
+ * - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
+ * – The respond method takes a set of static data to be returned or a function that can return
+ * an array containing response status (number), response data (string) and response headers
+ * (Object).
+ */
$httpBackend.when = function(method, url, data, headers) {
var definition = new MockHttpExpectation(method, url, data, headers),
chain = {
@@ -695,9 +879,107 @@ function createHttpBackendMock($delegate, $defer) {
return chain;
};
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#whenGET
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Creates a new backend definition for GET requests. For more info see `when()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#whenHEAD
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Creates a new backend definition for HEAD requests. For more info see `when()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#whenDELETE
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Creates a new backend definition for DELETE requests. For more info see `when()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#whenPOST
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Creates a new backend definition for POST requests. For more info see `when()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {(string|RegExp)=} data HTTP request body.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#whenPUT
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Creates a new backend definition for PUT requests. For more info see `when()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {(string|RegExp)=} data HTTP request body.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#whenJSONP
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Creates a new backend definition for JSONP requests. For more info see `when()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ */
createShortMethods('when');
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#expect
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Creates a new request expectation.
+ *
+ * @param {string} method HTTP method.
+ * @param {string|RegExp} url HTTP url.
+ * @param {(string|RegExp)=} data HTTP request body.
+ * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
+ * object and returns true if the headers match the current expectation.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ *
+ * - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
+ * – The respond method takes a set of static data to be returned or a function that can return
+ * an array containing response status (number), response data (string) and response headers
+ * (Object).
+ */
$httpBackend.expect = function(method, url, data, headers) {
var expectation = new MockHttpExpectation(method, url, data, headers);
expectations.push(expectation);
@@ -708,9 +990,99 @@ function createHttpBackendMock($delegate, $defer) {
};
};
+
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#expectGET
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Creates a new request expectation for GET requests. For more info see `expect()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {Object=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled. See #expect for more info.
+ */
+
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#expectHEAD
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Creates a new request expectation for HEAD requests. For more info see `expect()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {Object=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#expectDELETE
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Creates a new request expectation for DELETE requests. For more info see `expect()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {Object=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#expectPOST
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Creates a new request expectation for POST requests. For more info see `expect()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {(string|RegExp)=} data HTTP request body.
+ * @param {Object=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#expectPUT
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Creates a new request expectation for PUT requests. For more info see `expect()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {(string|RegExp)=} data HTTP request body.
+ * @param {Object=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#expectJSONP
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Creates a new request expectation for JSONP requests. For more info see `expect()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ */
createShortMethods('expect');
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#flush
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Flushes all pending requests using the trained responses.
+ *
+ * @param {number=} count Number of responses to flush (in the order they arrived). If undefined,
+ * all pending requests will be flushed. If there are no pending requests when the flush method
+ * is called an exception is thrown (as this typically a sign of programming error).
+ */
$httpBackend.flush = function(count) {
if (!responses.length) throw Error('No pending request to flush !');
@@ -727,18 +1099,59 @@ function createHttpBackendMock($delegate, $defer) {
$httpBackend.verifyNoOutstandingExpectation();
};
+
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#verifyNoOutstandingExpectation
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Verifies that all of the requests defined via the `expect` api were made. If any of the
+ * requests were not made, verifyNoOutstandingExpectation throws an exception.
+ *
+ * Typically, you would call this method following each test case that asserts requests using an
+ * "afterEach" clause.
+ *
+ * <pre>
+ * afterEach($httpBackend.verifyExpectations);
+ * </pre>
+ */
$httpBackend.verifyNoOutstandingExpectation = function() {
if (expectations.length) {
throw Error('Unsatisfied requests: ' + expectations.join(', '));
}
};
+
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#verifyNoOutstandingRequest
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Verifies that there are no outstanding requests that need to be flushed.
+ *
+ * Typically, you would call this method following each test case that asserts requests using an
+ * "afterEach" clause.
+ *
+ * <pre>
+ * afterEach($httpBackend.verifyNoOutstandingRequest);
+ * </pre>
+ */
$httpBackend.verifyNoOutstandingRequest = function() {
if (responses.length) {
throw Error('Unflushed requests: ' + responses.length);
}
};
+
+ /**
+ * @ngdoc method
+ * @name angular.module.ngMock.$httpBackend#resetExpectations
+ * @methodOf angular.module.ngMock.$httpBackend
+ * @description
+ * Resets all request expectations, but preserves all backend definitions. Typically, you would
+ * call resetExpectations during a multiple-phase test when you want to reuse the same instance of
+ * $httpBackend mock.
+ */
$httpBackend.resetExpectations = function() {
expectations.length = 0;
responses.length = 0;
@@ -870,13 +1283,164 @@ angular.module('ngMock', ['ng']).service({
* @name angular.module.ngMockE2E
* @description
*
- * The `ngMockE2E` is an angular module which contains mock for `$httpBackend`. This mock allows you
- * to either respond with fake data or delegate to real backend.
+ * The `ngMockE2E` is an angular module which contains mocks suitable for end-to-end testing.
+ * Currently there is only one mock present in this module -
+ * the {@link angular.module.ngMockE2E.$httpBackend e2e $httpBackend} mock.
*/
angular.module('ngMockE2E', ['ng']).init(function($provide) {
$provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator);
});
+/**
+ * @ngdoc object
+ * @name angular.module.ngMockE2E.$httpBackend
+ * @description
+ * Fake HTTP backend implementation suitable for end-to-end testing or backend-less development of
+ * applications that use the {@link angular.module.ng.$http $http service}.
+ *
+ * *Note*: For fake http backend implementation suitable for unit testing please see
+ * {@link angular.module.ngMock.$httpBackend unit-testing $httpBackend mock}.
+ *
+ * This implementation can be used to respond with static or dynamic responses via the `when` api
+ * and its shortcuts (`whenGET`, `whenPOST`, etc) and optionally pass through requests to the
+ * real $httpBackend for specific requests (e.g. to interact with certain remote apis or to fetch
+ * templates from a webserver).
+ *
+ * As opposed to unit-testing, in an end-to-end testing scenario or in scenario when an application
+ * is being developed with the real backend api replaced with a mock, it is often desirable for
+ * certain category of requests to bypass the mock and issue a real http request (e.g. to fetch
+ * templates or static files from the webserver). To configure the backend with this behavior
+ * use the `passThrough` request handler of `when` instead of `respond`.
+ *
+ * Additionally, we don't want to manually have to flush mocked out requests like we do during unit
+ * testing. For this reason the e2e $httpBackend automatically flushes mocked out requests
+ * automatically, closely simulating the behavior of the XMLHttpRequest object.
+ *
+ * To setup the application to run with this http backend, you have to create a module that depends
+ * on the `ngMockE2E` and your application modules and defines the fake backend:
+ *
+ * <pre>
+ * myAppDev = angular.module('myAppDev', ['myApp', 'ngMockE2E']);
+ * myAppDev.run(function($httpBackend) {
+ * phones = [{name: 'phone1'}, {name: 'phone2'}];
+ *
+ * // returns the current list of phones
+ * $httpBackend.whenGET('/phones').respond(phones);
+ *
+ * // adds a new phone to the phones array
+ * $httpBackend.whenPOST('/phones').respond(function(method, url, data) {
+ * phones.push(angular.fromJSON(data));
+ * });
+ * $httpBackend.whenGET(/^\/templates\//).passThrough();
+ * //...
+ * });
+ * </pre>
+ *
+ * Afterwards, bootstrap your app with this new module.
+ */
+
+/**
+ * @ngdoc method
+ * @name angular.module.ngMockE2E.$httpBackend#when
+ * @methodOf angular.module.ngMockE2E.$httpBackend
+ * @description
+ * Creates a new backend definition.
+ *
+ * @param {string} method HTTP method.
+ * @param {string|RegExp} url HTTP url.
+ * @param {(string|RegExp)=} data HTTP request body.
+ * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
+ * object and returns true if the headers match the current definition.
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
+ * control how a matched request is handled.
+ *
+ * - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
+ * – The respond method takes a set of static data to be returned or a function that can return
+ * an array containing response status (number), response data (string) and response headers
+ * (Object).
+ * - passThrough – `{function()}` – Any request matching a backend definition with `passThrough`
+ * handler, will be pass through to the real backend (an XHR request will be made to the
+ * server.
+ */
+
+/**
+ * @ngdoc method
+ * @name angular.module.ngMockE2E.$httpBackend#whenGET
+ * @methodOf angular.module.ngMockE2E.$httpBackend
+ * @description
+ * Creates a new backend definition for GET requests. For more info see `when()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
+ * control how a matched request is handled.
+ */
+
+/**
+ * @ngdoc method
+ * @name angular.module.ngMockE2E.$httpBackend#whenHEAD
+ * @methodOf angular.module.ngMockE2E.$httpBackend
+ * @description
+ * Creates a new backend definition for HEAD requests. For more info see `when()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
+ * control how a matched request is handled.
+ */
+
+/**
+ * @ngdoc method
+ * @name angular.module.ngMockE2E.$httpBackend#whenDELETE
+ * @methodOf angular.module.ngMockE2E.$httpBackend
+ * @description
+ * Creates a new backend definition for DELETE requests. For more info see `when()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
+ * control how a matched request is handled.
+ */
+
+/**
+ * @ngdoc method
+ * @name angular.module.ngMockE2E.$httpBackend#whenPOST
+ * @methodOf angular.module.ngMockE2E.$httpBackend
+ * @description
+ * Creates a new backend definition for POST requests. For more info see `when()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {(string|RegExp)=} data HTTP request body.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
+ * control how a matched request is handled.
+ */
+
+/**
+ * @ngdoc method
+ * @name angular.module.ngMockE2E.$httpBackend#whenPUT
+ * @methodOf angular.module.ngMockE2E.$httpBackend
+ * @description
+ * Creates a new backend definition for PUT requests. For more info see `when()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {(string|RegExp)=} data HTTP request body.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
+ * control how a matched request is handled.
+ */
+
+/**
+ * @ngdoc method
+ * @name angular.module.ngMockE2E.$httpBackend#whenJSONP
+ * @methodOf angular.module.ngMockE2E.$httpBackend
+ * @description
+ * Creates a new backend definition for JSONP requests. For more info see `when()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
+ * control how a matched request is handled.
+ */
angular.mock.e2e = {};
angular.mock.e2e.$httpBackendDecorator = ['$delegate', '$defer', createHttpBackendMock];
diff --git a/src/service/http.js b/src/service/http.js
index e9c49ec2..f9a8d921 100644
--- a/src/service/http.js
+++ b/src/service/http.js
@@ -139,35 +139,314 @@ function $HttpProvider() {
* @requires $q
* @requires $injector
*
- * @param {object} config Object describing the request to be made and how it should be processed.
- * The object has following properties:
+ * @description
+ * The `$http` service is a core Angular service that is responsible for communication with the
+ * remote HTTP servers via browser's {@link https://developer.mozilla.org/en/xmlhttprequest
+ * XMLHttpRequest} object or via {@link http://en.wikipedia.org/wiki/JSONP JSONP}.
+ *
+ * For unit testing applications that use `$http` service, see
+ * {@link angular.module.ngMock.$httpBackend $httpBackend mock}.
+ *
+ * For a higher level of abstraction, please check out the {@link angular.module.ng.$resource
+ * $resource} service.
+ *
+ *
+ * # General usage
+ * The `$http` service is a function which takes a single argument — a configuration object —
+ * that is used to generate an http request and returns a {@link angular.module.ng.$q promise}
+ * with two $http specific methods: `success` and `error`.
+ *
+ * <pre>
+ * $http({method: 'GET', url: '/someUrl'}).
+ * success(function(data, status, headers, config) {
+ * // this callback will be called asynchronously
+ * // when the response is available
+ * }).
+ * error(function(data, status, headers, config) {
+ * // called asynchronously if an error occurs
+ * // or server returns response with status
+ * // code outside of the <200, 400) range
+ * });
+ * </pre>
+ *
+ * Since the returned value is a Promise object, you can also use the `then` method to register
+ * callbacks, and these callbacks will receive a single argument – an object representing the
+ * response. See the api signature and type info below for more details.
+ *
+ *
+ * # Shortcut methods
+ *
+ * Since all invocation of the $http service require definition of the http method and url and
+ * POST and PUT requests require response body/data to be provided as well, shortcut methods
+ * were created to simplify using the api:
+ *
+ * <pre>
+ * $http.get('/someUrl').success(successCallback);
+ * $http.post('/someUrl', data).success(successCallback);
+ * </pre>
+ *
+ * Complete list of shortcut methods:
+ *
+ * - {@link angular.module.ng.$http#get $http.get}
+ * - {@link angular.module.ng.$http#head $http.head}
+ * - {@link angular.module.ng.$http#post $http.post}
+ * - {@link angular.module.ng.$http#put $http.put}
+ * - {@link angular.module.ng.$http#delete $http.delete}
+ * - {@link angular.module.ng.$http#jsonp $http.jsonp}
+ *
+ *
+ * # HTTP Headers
+ *
+ * The $http service will automatically add certain http headers to all requests. These defaults
+ * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
+ * object, which currently contains this default configuration:
+ *
+ * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
+ * - `Accept: application/json, text/plain, * / *`
+ * - `X-Requested-With: XMLHttpRequest`
+ * - `$httpProvider.defaults.headers.post: (header defaults for HTTP POST requests)
+ * - `Content-Type: application/json`
+ * - `$httpProvider.defaults.headers.put` (header defaults for HTTP PUT requests)
+ * - `Content-Type: application/json`
+ *
+ * To add or overwrite these defaults, simply add or remove a property from this configuration
+ * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
+ * with name equal to the lower-cased http method name, e.g.
+ * `$httpProvider.defaults.headers.get['My-Header']='value'`.
+ *
+ *
+ * # Request / Response transformations
+ *
+ * Both requests and responses can be transformed using transform functions. By default, Angular
+ * applies these transformations:
+ *
+ * Request transformations:
+ *
+ * - if the `data` property of the request config object contains an object, serialize it into
+ * JSON format.
+ *
+ * Response transformations:
+ *
+ * - if XSRF prefix is detected, strip it (see Security Considerations section below)
+ * - if json response is detected, deserialize it using a JSON parser
+ *
+ * These transformations can be overridden locally by specifying transform functions as
+ * `transformRequest` and/or `transformResponse` properties of the config object. To globally
+ * override the default transforms, override the `$httpProvider.defaults.transformRequest` and
+ * `$httpProvider.defaults.transformResponse` properties of the `$httpProvider`.
+ *
+ *
+ * # Caching
+ *
+ * You can enable caching by setting the configuration property `cache` to `true`. When the
+ * cache is enabled, `$http` stores the response from the server in local cache. Next time the
+ * response is served from the cache without sending a request to the server.
+ *
+ * Note that even if the response is served from cache, delivery of the data is asynchronous in
+ * the same way that real requests are.
+ *
+ * If there are multiple GET requests for the same url that should be cached using the same
+ * cache, but the cache is not populated yet, only one request to the server will be made and
+ * the remaining requests will be fulfilled using the response for the first request.
+ *
+ *
+ * # Response interceptors
+ *
+ * For purposes of global error handling, authentication or any kind of synchronous or
+ * asynchronous preprocessing of received responses, it is desirable to be able to intercept
+ * responses for http requests before they are handed over to the application code that
+ * initiated these requests. The response interceptors leverage the {@link angular.module.ng.$q
+ * promise apis} to fulfil this need for both synchronous and asynchronous preprocessing.
+ *
+ * The interceptors are service factories that are registered with the $httpProvider by
+ * adding them to the `$httpProvider.responseInterceptors` array. The factory is called and
+ * injected with dependencies (if specified) and returns the interceptor — a function that
+ * takes a {@link angular.module.ng.$q promise} and returns the original or a new promise.
+ *
+ * Before you start creating interceptors, be sure to understand the
+ * {@link angular.module.ng.$q $q and deferred/promise APIs}.
+ *
+ * <pre>
+ * // register the interceptor as a service
+ * $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
+ * return function(promise) {
+ * return promise.then(function(response) {
+ * // do something on success
+ * }, function(response) {
+ * // do something on error
+ * if (canRecover(response)) {
+ * return responseOrNewPromise
+ * }
+ * return $q.reject(response);
+ * });
+ * }
+ * });
+ *
+ * $httpProvider.responseInterceptors.push('myHttpInterceptor');
+ *
+ *
+ * // register the interceptor via an anonymous factory
+ * $httpProvider.responseInterceptors.push(function($q, dependency1, dependency2) {
+ * return function(promise) {
+ * // same as above
+ * }
+ * });
+ * </pre>
+ *
+ *
+ * # Security Considerations
+ *
+ * When designing web applications your design needs to consider security threats from
+ * {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
+ * JSON Vulnerability} and {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF}.
+ * Both server and the client must cooperate in order to eliminate these threats. Angular comes
+ * pre-configured with strategies that address these issues, but for this to work backend server
+ * cooperation is required.
+ *
+ * ## JSON Vulnerability Protection
+ *
+ * A {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
+ * JSON Vulnerability} allows third party web-site to turn your JSON resource URL into
+ * {@link http://en.wikipedia.org/wiki/JSON#JSONP JSONP} request under some conditions. To
+ * counter this your server can prefix all JSON requests with following string `")]}',\n"`.
+ * Angular will automatically strip the prefix before processing it as JSON.
+ *
+ * For example if your server needs to return:
+ * <pre>
+ * ['one','two']
+ * </pre>
+ *
+ * which is vulnerable to attack, your server can return:
+ * <pre>
+ * )]}',
+ * ['one','two']
+ * </pre>
+ *
+ * Angular will strip the prefix, before processing the JSON.
+ *
+ *
+ * ## Cross Site Request Forgery (XSRF) Protection
+ *
+ * {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF} is a technique by which
+ * an unauthorized site can gain your user's private data. Angular provides following mechanism
+ * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
+ * called `XSRF-TOKEN` and sets it as the HTTP header `X-XSRF-TOKEN`. Since only JavaScript that
+ * runs on your domain could read the cookie, your server can be assured that the XHR came from
+ * JavaScript running on your domain.
+ *
+ * To take advantage of this, your server needs to set a token in a JavaScript readable session
+ * cookie called `XSRF-TOKEN` on first HTTP GET request. On subsequent non-GET requests the
+ * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
+ * that only JavaScript running on your domain could have read the token. The token must be
+ * unique for each user and must be verifiable by the server (to prevent the JavaScript making
+ * up its own tokens). We recommend that the token is a digest of your site's authentication
+ * cookie with {@link http://en.wikipedia.org/wiki/Rainbow_table salt for added security}.
+ *
+ *
+ * @param {object} config Object describing the request to be made and how it should be
+ * processed. The object has following properties:
*
* - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
* - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
* - **data** – `{string|Object}` – Data to be sent as the request message data.
* - **headers** – `{Object}` – Map of strings representing HTTP headers to send to the server.
+ * - **transformRequest** – `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
+ * transform function or an array of such functions. The transform function takes the http
+ * request body and headers and returns its transformed (typically serialized) version.
+ * - **transformResponse** – `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
+ * transform function or an array of such functions. The transform function takes the http
+ * response body and headers and returns its transformed (typically deserialized) version.
* - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
- * GET request, otherwise if a cache instance built with $cacheFactory, this cache will be
- * used for caching.
+ * GET request, otherwise if a cache instance built with
+ * {@link angular.module.ng.$cacheFactory $cacheFactory}, this cache will be used for
+ * caching.
+ * - **timeout** – `{number}` – timeout in milliseconds.
*
- * @returns {HttpPromise} Returns a promise object with the standard `then` method and two http
- * specific methods: `success` and `error`. The `then` method takes two arguments a success and
- * an error callback which will be called with a response object. The `success` and `error`
- * methods take a single argument - a function that will be called when the request succeeds or
- * fails respectively. The arguments passed into these functions are destructured representation
- * of the response object passed into the `then` method. The response object has these
- * properties:
+ * @returns {HttpPromise} Returns a {@link angular.module.ng.$q promise} object with the
+ * standard `then` method and two http specific methods: `success` and `error`. The `then`
+ * method takes two arguments a success and an error callback which will be called with a
+ * response object. The `success` and `error` methods take a single argument - a function that
+ * will be called when the request succeeds or fails respectively. The arguments passed into
+ * these functions are destructured representation of the response object passed into the
+ * `then` method. The response object has these properties:
*
* - **data** – `{string|Object}` – The response body transformed with the transform functions.
* - **status** – `{number}` – HTTP status code of the response.
* - **headers** – `{function([headerName])}` – Header getter function.
* - **config** – `{Object}` – The configuration object that was used to generate the request.
*
- * @property {Array.<Object>} pendingRequests Array of config objects for pending requests.
- * This is primarily meant to be used for debugging purposes.
+ * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
+ * requests. This is primarily meant to be used for debugging purposes.
*
- * @description
- * $http is a service through which XHR and JSONP requests can be made.
+ *
+ * @example
+ <doc:example>
+ <doc:source jsfiddle="false">
+ <script>
+ function FetchCtrl($http) {
+ var self = this;
+ this.method = 'GET';
+ this.url = 'examples/http-hello.html';
+
+ this.fetch = function() {
+ self.code = null;
+ self.response = null;
+
+ $http({method: self.method, url: self.url}).
+ success(function(data, status) {
+ self.status = status;
+ self.data = data;
+ }).
+ error(function(data, status) {
+ self.data = data || "Request failed";
+ self.status = status;
+ });
+ };
+
+ this.updateModel = function(method, url) {
+ self.method = method;
+ self.url = url;
+ };
+ }
+ </script>
+ <div ng:controller="FetchCtrl">
+ <select ng:model="method">
+ <option>GET</option>
+ <option>JSONP</option>
+ </select>
+ <input type="text" ng:model="url" size="80"/>
+ <button ng:click="fetch()">fetch</button><br>
+ <button ng:click="updateModel('GET', 'examples/http-hello.html')">Sample GET</button>
+ <button ng:click="updateModel('JSONP', 'http://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">Sample JSONP</button>
+ <button ng:click="updateModel('JSONP', 'http://angularjs.org/doesntexist&callback=JSON_CALLBACK')">Invalid JSONP</button>
+ <pre>http status code: {{status}}</pre>
+ <pre>http response data: {{data}}</pre>
+ </div>
+ </doc:source>
+ <doc:scenario>
+ it('should make an xhr GET request', function() {
+ element(':button:contains("Sample GET")').click();
+ element(':button:contains("fetch")').click();
+ expect(binding('status')).toBe('http status code: 200');
+ expect(binding('data')).toBe('http response data: Hello, $http!\n');
+ });
+
+ it('should make a JSONP request to angularjs.org', function() {
+ element(':button:contains("Sample JSONP")').click();
+ element(':button:contains("fetch")').click();
+ expect(binding('status')).toBe('http status code: 200');
+ expect(binding('data')).toMatch(/Super Hero!/);
+ });
+
+ it('should make JSONP request to invalid URL and invoke the error handler',
+ function() {
+ element(':button:contains("Invalid JSONP")').click();
+ element(':button:contains("fetch")').click();
+ expect(binding('status')).toBe('http status code: 0');
+ expect(binding('data')).toBe('http response data: Request failed');
+ });
+ </doc:scenario>
+ </doc:example>
*/
function $http(config) {
config.method = uppercase(config.method);
@@ -263,19 +542,6 @@ function $HttpProvider() {
/**
* @ngdoc method
- * @name angular.module.ng.$http#patch
- * @methodOf angular.module.ng.$http
- *
- * @description
- * Shortcut method to perform `PATCH` request
- *
- * @param {string} url Relative or absolute URL specifying the destination of the request
- * @param {Object=} config Optional configuration object
- * @returns {HttpPromise} Future object
- */
-
- /**
- * @ngdoc method
* @name angular.module.ng.$http#jsonp
* @methodOf angular.module.ng.$http
*
diff --git a/src/service/httpBackend.js b/src/service/httpBackend.js
index f18808c6..291d24bb 100644
--- a/src/service/httpBackend.js
+++ b/src/service/httpBackend.js
@@ -15,7 +15,10 @@ var XHR = window.XMLHttpRequest || function() {
*
* @description
* HTTP backend used by the {@link angular.module.ng.$http service} that delegates to
- * XMLHttpRequest object.
+ * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
+ *
+ * You should never need to use this service directly, instead use the higher-level abstractions:
+ * {@link angular.module.ng.$http $http} or {@link angular.module.ng.$resource $resource}.
*
* During testing this implementation is swapped with {@link angular.module.ngMock.$httpBackend mock
* $httpBackend} which can be trained with responses.