aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorVojta Jina2011-08-16 21:24:53 +0200
committerIgor Minar2011-11-30 11:12:14 -0500
commitcd28a2e952efbc2f76ff86b6b7d21fd5e41cec65 (patch)
treea2fd87414cf37838b646550f2aff1dfabf61db63 /src
parent59adadca086853c5de6867ae853f6f27a3af4bbe (diff)
downloadangular.js-cd28a2e952efbc2f76ff86b6b7d21fd5e41cec65.tar.bz2
feat(mocks.$httpBackend): add $httpBackend mock
$httpBackend mock allows: - expecting (asserting) requests - stubbing (responding without asserting) Add empty $httpBackend service (currently just wrapper for $browser.xhr)
Diffstat (limited to 'src')
-rw-r--r--src/AngularPublic.js1
-rw-r--r--src/angular-mocks.js167
-rw-r--r--src/service/http.js13
-rw-r--r--src/service/httpBackend.js6
4 files changed, 179 insertions, 8 deletions
diff --git a/src/AngularPublic.js b/src/AngularPublic.js
index df309189..4d94e901 100644
--- a/src/AngularPublic.js
+++ b/src/AngularPublic.js
@@ -78,6 +78,7 @@ function ngModule($provide, $injector) {
$provide.service('$filter', $FilterProvider);
$provide.service('$formFactory', $FormFactoryProvider);
$provide.service('$http', $HttpProvider);
+ $provide.service('$httpBackend', $HttpBackendProvider);
$provide.service('$location', $LocationProvider);
$provide.service('$log', $LogProvider);
$provide.service('$parse', $ParseProvider);
diff --git a/src/angular-mocks.js b/src/angular-mocks.js
index 73bc4cbd..bc0578f5 100644
--- a/src/angular-mocks.js
+++ b/src/angular-mocks.js
@@ -21,6 +21,7 @@ angular.module.ngMock = function($provide){
$provide.service('$browser', angular.module.ngMock.$BrowserProvider);
$provide.service('$exceptionHandler', angular.module.ngMock.$ExceptionHandlerProvider);
$provide.service('$log', angular.module.ngMock.$LogProvider);
+ $provide.service('$httpBackend', angular.module.ngMock.$HttpBackendProvider);
};
angular.module.ngMock.$inject = ['$provide'];
@@ -38,8 +39,6 @@ angular.module.ngMock.$inject = ['$provide'];
*
* The following apis can be used in tests:
*
- * - {@link #xhr} — enables testing of code that uses
- * the {@link angular.module.ng.$xhr $xhr service} to make XmlHttpRequests.
* - $browser.defer — enables testing of code that uses
* {@link angular.module.ng.$defer $defer} for executing functions via the `setTimeout` api.
*/
@@ -720,6 +719,170 @@ angular.module.ngMock.dump = function(object){
}
};
+/**
+ * @ngdoc object
+ * @name angular.module.ngMock.$httpBackend
+ */
+angular.module.ngMock.$HttpBackendProvider = function() {
+ this.$get = function() {
+ var definitions = [],
+ expectations = [],
+ responses = [];
+
+ function createResponse(status, data, headers) {
+ return angular.isNumber(status) ? [status, data, headers] : [200, status, data];
+ }
+
+ // TODO(vojta): change params to: method, url, data, headers, callback
+ function $httpBackend(method, url, data, callback, headers) {
+ var xhr = new MockXhr(),
+ expectation = expectations[0],
+ wasExpected = false;
+
+ if (expectation && expectation.match(method, url)) {
+ if (!expectation.matchData(data))
+ throw Error('Expected ' + method + ' ' + url + ' with different data');
+
+ if (!expectation.matchHeaders(headers))
+ throw Error('Expected ' + method + ' ' + url + ' with different headers');
+
+ expectations.shift();
+
+ if (expectation.response) {
+ responses.push(function() {
+ xhr.$$headers = expectation.response[2];
+ callback(expectation.response[0], expectation.response[1]);
+ });
+ return method == 'JSONP' ? undefined : xhr;
+ }
+ wasExpected = true;
+ }
+
+ var i = -1, definition;
+ while ((definition = definitions[++i])) {
+ if (definition.match(method, url, data, headers || {})) {
+ if (!definition.response) throw Error('No response defined !');
+ responses.push(function() {
+ var response = angular.isFunction(definition.response) ?
+ definition.response(method, url, data, headers) : definition.response;
+ xhr.$$headers = response[2];
+ callback(response[0], response[1]);
+ });
+ return method == 'JSONP' ? undefined : xhr;
+ }
+ }
+ throw wasExpected ? Error('No response defined !') :
+ Error('Unexpected request: ' + method + ' ' + url);
+ }
+
+ $httpBackend.when = function(method, url, data, headers) {
+ var definition = new MockHttpExpectation(method, url, data, headers);
+ definitions.push(definition);
+ return {
+ then: function(status, data, headers) {
+ definition.response = angular.isFunction(status) ? status : createResponse(status, data, headers);
+ }
+ };
+ };
+
+ $httpBackend.expect = function(method, url, data, headers) {
+ var expectation = new MockHttpExpectation(method, url, data, headers);
+ expectations.push(expectation);
+ return {
+ respond: function(status, data, headers) {
+ expectation.response = createResponse(status, data, headers);
+ }
+ };
+ };
+
+ $httpBackend.flush = function(count) {
+ count = count || responses.length;
+ while (count--) {
+ if (!responses.length) throw Error('No more pending requests');
+ responses.shift()();
+ }
+ };
+
+
+
+ $httpBackend.verifyExpectations = function() {
+ if (expectations.length) {
+ throw Error('Unsatisfied requests: ' + expectations.join(', '));
+ }
+ };
+
+ $httpBackend.resetExpectations = function() {
+ expectations = [];
+ responses = [];
+ };
+
+ return $httpBackend;
+ };
+};
+
+function MockHttpExpectation(method, url, data, headers) {
+
+ this.match = function(m, u, d, h) {
+ if (method != m) return false;
+ if (!this.matchUrl(u)) return false;
+ if (angular.isDefined(d) && !this.matchData(d)) return false;
+ if (angular.isDefined(h) && !this.matchHeaders(h)) return false;
+ return true;
+ };
+
+ this.matchUrl = function(u) {
+ if (!url) return true;
+ if (angular.isFunction(url.test)) {
+ if (!url.test(u)) return false;
+ } else if (url != u) return false;
+
+ return true;
+ };
+
+ this.matchHeaders = function(h) {
+ if (angular.isUndefined(headers)) return true;
+ if (angular.isFunction(headers)) {
+ if (!headers(h)) return false;
+ } else if (!angular.equals(headers, h)) return false;
+
+ return true;
+ };
+
+ this.matchData = function(d) {
+ if (angular.isUndefined(data)) return true;
+ if (data && angular.isFunction(data.test)) {
+ if (!data.test(d)) return false;
+ } else if (data != d) return false;
+
+ return true;
+ };
+
+ this.toString = function() {
+ return method + ' ' + url;
+ };
+}
+
+function MockXhr() {
+
+ // hack for testing $http
+ MockXhr.$$lastInstance = this;
+
+ this.getResponseHeader = function(name) {
+ return this.$$headers[name];
+ };
+
+ this.getAllResponseHeaders = function() {
+ var lines = [];
+
+ angular.forEach(this.$$headers, function(value, key) {
+ lines.push(key + ': ' + value);
+ });
+ return lines.join('\n');
+ };
+
+ this.abort = noop;
+}
+
window.jstestdriver && (function(window){
/**
* Global method to output any number of objects into JSTD console. Useful for debugging.
diff --git a/src/service/http.js b/src/service/http.js
index 13621f90..087c3809 100644
--- a/src/service/http.js
+++ b/src/service/http.js
@@ -51,6 +51,7 @@ function transform(data, fns, param) {
/**
* @ngdoc object
* @name angular.module.ng.$http
+ * @requires $httpBacked
* @requires $browser
* @requires $exceptionHandler
* @requires $cacheFactory
@@ -85,8 +86,8 @@ function $HttpProvider() {
}
};
- this.$get = ['$browser', '$exceptionHandler', '$cacheFactory', '$rootScope',
- function($browser, $exceptionHandler, $cacheFactory, $rootScope) {
+ this.$get = ['$httpBackend', '$browser', '$exceptionHandler', '$cacheFactory', '$rootScope',
+ function($httpBackend, $browser, $exceptionHandler, $cacheFactory, $rootScope) {
var cache = $cacheFactory('$http'),
pendingRequestsCount = 0;
@@ -235,7 +236,7 @@ function $HttpProvider() {
/**
* Represents Request object, returned by $http()
*
- * !!! ACCESS CLOSURE VARS: $browser, $config, $log, $rootScope, cache, pendingRequestsCount
+ * !!! ACCESS CLOSURE VARS: $httpBackend, $browser, $config, $log, $rootScope, cache, pendingRequestsCount
*/
function XhrFuture() {
var rawRequest, cfg = {}, callbacks = [],
@@ -243,7 +244,7 @@ function $HttpProvider() {
parsedHeaders;
/**
- * Callback registered to $browser.xhr:
+ * Callback registered to $httpBackend():
* - caches the response if desired
* - calls fireCallbacks()
* - clears the reference to raw request object
@@ -265,7 +266,7 @@ function $HttpProvider() {
* Fire all registered callbacks for given status code
*
* This method when:
- * - serving response from real request ($browser.xhr callback)
+ * - serving response from real request
* - serving response from cache
*
* It does:
@@ -368,7 +369,7 @@ function $HttpProvider() {
fireCallbacks(fromCache[1], fromCache[0]);
});
} else {
- rawRequest = $browser.xhr(cfg.method, cfg.url, data, done, headers, cfg.timeout);
+ rawRequest = $httpBackend(cfg.method, cfg.url, data, done, headers, cfg.timeout);
}
pendingRequestsCount++;
diff --git a/src/service/httpBackend.js b/src/service/httpBackend.js
new file mode 100644
index 00000000..af3de970
--- /dev/null
+++ b/src/service/httpBackend.js
@@ -0,0 +1,6 @@
+function $HttpBackendProvider() {
+ this.$get = ['$browser', function($browser) {
+ return $browser.xhr;
+ }];
+}
+