aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--angularFiles.js1
-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
-rw-r--r--test/angular-mocksSpec.js397
-rw-r--r--test/service/httpSpec.js735
-rw-r--r--test/widgetsSpec.js68
8 files changed, 944 insertions, 444 deletions
diff --git a/angularFiles.js b/angularFiles.js
index 6871c2a4..a67aa6cc 100644
--- a/angularFiles.js
+++ b/angularFiles.js
@@ -33,6 +33,7 @@ angularFiles = {
'src/service/sniffer.js',
'src/service/window.js',
'src/service/http.js',
+ 'src/service/httpBackend.js',
'src/service/locale.js',
'src/directives.js',
'src/markups.js',
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;
+ }];
+}
+
diff --git a/test/angular-mocksSpec.js b/test/angular-mocksSpec.js
index acb019c7..4551d11d 100644
--- a/test/angular-mocksSpec.js
+++ b/test/angular-mocksSpec.js
@@ -342,4 +342,401 @@ describe('mocks', function() {
expect(count).toBe(2);
});
});
+
+
+ describe('$httpBackend', function() {
+ var hb, callback;
+
+ beforeEach(inject(function($httpBackend) {
+ callback = jasmine.createSpy('callback');
+ hb = $httpBackend;
+ }));
+
+
+ it('should respond with first matched definition', function() {
+ hb.when('GET', '/url1').then(200, 'content', {});
+ hb.when('GET', '/url1').then(201, 'another', {});
+
+ callback.andCallFake(function(status, response) {
+ expect(status).toBe(200);
+ expect(response).toBe('content');
+ });
+
+ hb('GET', '/url1', null, callback);
+ expect(callback).not.toHaveBeenCalled();
+ hb.flush();
+ expect(callback).toHaveBeenCalledOnce();
+ });
+
+
+ it('should throw error when unexpected request', function() {
+ hb.when('GET', '/url1').then(200, 'content');
+ expect(function() {
+ hb('GET', '/xxx');
+ }).toThrow('Unexpected request: GET /xxx');
+ });
+
+
+ it('should match headers if specified', function() {
+ hb.when('GET', '/url', null, {'X': 'val1'}).then(201, 'content1');
+ hb.when('GET', '/url', null, {'X': 'val2'}).then(202, 'content2');
+ hb.when('GET', '/url').then(203, 'content3');
+
+ hb('GET', '/url', null, function(status, response) {
+ expect(status).toBe(203);
+ expect(response).toBe('content3');
+ });
+
+ hb('GET', '/url', null, function(status, response) {
+ expect(status).toBe(201);
+ expect(response).toBe('content1');
+ }, {'X': 'val1'});
+
+ hb('GET', '/url', null, function(status, response) {
+ expect(status).toBe(202);
+ expect(response).toBe('content2');
+ }, {'X': 'val2'});
+
+ hb.flush();
+ });
+
+
+ it('should match data if specified', function() {
+ hb.when('GET', '/a/b', '{a: true}').then(201, 'content1');
+ hb.when('GET', '/a/b').then(202, 'content2');
+
+ hb('GET', '/a/b', '{a: true}', function(status, response) {
+ expect(status).toBe(201);
+ expect(response).toBe('content1');
+ });
+
+ hb('GET', '/a/b', null, function(status, response) {
+ expect(status).toBe(202);
+ expect(response).toBe('content2');
+ });
+
+ hb.flush();
+ });
+
+
+ it('should match only method', function() {
+ hb.when('GET').then(202, 'c');
+ callback.andCallFake(function(status, response) {
+ expect(status).toBe(202);
+ expect(response).toBe('c');
+ });
+
+ hb('GET', '/some', null, callback, {});
+ hb('GET', '/another', null, callback, {'X-Fake': 'Header'});
+ hb('GET', '/third', 'some-data', callback, {});
+ hb.flush();
+
+ expect(callback).toHaveBeenCalled();
+ });
+
+
+ it('should expose given headers', function() {
+ hb.when('GET', '/u1').then(200, null, {'X-Fake': 'Header', 'Content-Type': 'application/json'});
+ var xhr = hb('GET', '/u1', null, noop, {});
+ hb.flush();
+ expect(xhr.getResponseHeader('X-Fake')).toBe('Header');
+ expect(xhr.getAllResponseHeaders()).toBe('X-Fake: Header\nContent-Type: application/json');
+ });
+
+
+ it('should preserve the order of requests', function() {
+ hb.when('GET', '/url1').then(200, 'first');
+ hb.when('GET', '/url2').then(201, 'second');
+
+ hb('GET', '/url2', null, callback);
+ hb('GET', '/url1', null, callback);
+
+ hb.flush();
+
+ expect(callback.callCount).toBe(2);
+ expect(callback.argsForCall[0]).toEqual([201, 'second']);
+ expect(callback.argsForCall[1]).toEqual([200, 'first']);
+ });
+
+
+ it('then() should take function', function() {
+ hb.when('GET', '/some').then(function(m, u, d, h) {
+ return [301, m + u + ';' + d + ';a=' + h.a, {'Connection': 'keep-alive'}];
+ });
+
+ var xhr = hb('GET', '/some', 'data', callback, {a: 'b'});
+ hb.flush();
+
+ expect(callback).toHaveBeenCalledOnce();
+ expect(callback.mostRecentCall.args[0]).toBe(301);
+ expect(callback.mostRecentCall.args[1]).toBe('GET/some;data;a=b');
+ expect(xhr.getResponseHeader('Connection')).toBe('keep-alive');
+ });
+
+
+ it('expect() should require specified order', function() {
+ hb.expect('GET', '/url1').respond(200, '');
+ hb.expect('GET', '/url2').respond(200, '');
+
+ expect(function() {
+ hb('GET', '/url2', null, noop, {});
+ }).toThrow('Unexpected request: GET /url2');
+ });
+
+
+ it('expect() should have precendence over when()', function() {
+ callback.andCallFake(function(status, response) {
+ expect(status).toBe(300);
+ expect(response).toBe('expect');
+ });
+
+ hb.when('GET', '/url').then(200, 'when');
+ hb.expect('GET', '/url').respond(300, 'expect');
+
+ hb('GET', '/url', null, callback, {});
+ hb.flush();
+ expect(callback).toHaveBeenCalledOnce();
+ });
+
+
+ it ('should throw exception when only headers differes from expectation', function() {
+ hb.when('GET').then(200, '', {});
+ hb.expect('GET', '/match', undefined, {'Content-Type': 'application/json'});
+
+ expect(function() {
+ hb('GET', '/match', null, noop, {});
+ }).toThrow('Expected GET /match with different headers');
+ });
+
+
+ it ('should throw exception when only data differes from expectation', function() {
+ hb.when('GET').then(200, '', {});
+ hb.expect('GET', '/match', 'some-data');
+
+ expect(function() {
+ hb('GET', '/match', 'different', noop, {});
+ }).toThrow('Expected GET /match with different data');
+ });
+
+
+ it('expect() should without respond() and use then()', function() {
+ callback.andCallFake(function(status, response) {
+ expect(status).toBe(201);
+ expect(response).toBe('data');
+ });
+
+ hb.when('GET', '/some').then(201, 'data');
+ hb.expect('GET', '/some');
+ hb('GET', '/some', null, callback);
+ hb.flush();
+
+ expect(callback).toHaveBeenCalled();
+ expect(function() { hb.verifyExpectations(); }).not.toThrow();
+ });
+
+
+ it('flush() should not flush requests fired during callbacks', function() {
+ // regression
+ hb.when('GET').then(200, '');
+ hb('GET', '/some', null, function() {
+ hb('GET', '/other', null, callback);
+ });
+
+ hb.flush();
+ expect(callback).not.toHaveBeenCalled();
+ });
+
+
+ it('flush() should flush given number of pending requests', function() {
+ hb.when('GET').then(200, '');
+ hb('GET', '/some', null, callback);
+ hb('GET', '/some', null, callback);
+ hb('GET', '/some', null, callback);
+
+ hb.flush(2);
+ expect(callback).toHaveBeenCalled();
+ expect(callback.callCount).toBe(2);
+ });
+
+
+ it('flush() should throw exception when flushing more requests than pending', function() {
+ hb.when('GET').then(200, '');
+ hb('GET', '/url', null, callback);
+
+ expect(function() {hb.flush(2);}).toThrow('No more pending requests');
+ expect(callback).toHaveBeenCalledOnce();
+ });
+
+
+ it('respond() should set default status 200 if not defined', function() {
+ callback.andCallFake(function(status, response) {
+ expect(status).toBe(200);
+ expect(response).toBe('some-data');
+ });
+
+ hb.expect('GET', '/url1').respond('some-data');
+ hb.expect('GET', '/url2').respond('some-data', {'X-Header': 'true'});
+ hb('GET', '/url1', null, callback);
+ hb('GET', '/url2', null, callback);
+ hb.flush();
+ expect(callback).toHaveBeenCalled();
+ expect(callback.callCount).toBe(2);
+ });
+
+
+ it('then() should set default status 200 if not defined', function() {
+ callback.andCallFake(function(status, response) {
+ expect(status).toBe(200);
+ expect(response).toBe('some-data');
+ });
+
+ hb.when('GET', '/url1').then('some-data');
+ hb.when('GET', '/url2').then('some-data', {'X-Header': 'true'});
+ hb('GET', '/url1', null, callback);
+ hb('GET', '/url2', null, callback);
+ hb.flush();
+ expect(callback).toHaveBeenCalled();
+ expect(callback.callCount).toBe(2);
+ });
+
+
+ it('should respond with definition if no response for expectation', function() {
+ callback.andCallFake(function(status, response) {
+ expect(status).toBe(201);
+ expect(response).toBe('def-response');
+ });
+
+ hb.when('GET').then(201, 'def-response');
+ hb.expect('GET', '/some-url');
+
+ hb('GET', '/some-url', null, callback);
+ hb.flush();
+ expect(callback).toHaveBeenCalledOnce();
+ hb.verifyExpectations();
+ });
+
+
+ it('should throw an exception if no response defined', function() {
+ hb.when('GET', '/test');
+ expect(function() {
+ hb('GET', '/test', null, callback);
+ }).toThrow('No response defined !');
+ });
+
+
+ it('should throw an exception if no response for expection and no definition', function() {
+ hb.expect('GET', '/url');
+ expect(function() {
+ hb('GET', '/url', null, callback);
+ }).toThrow('No response defined !');
+ });
+
+
+ it('should respond undefined when JSONP method', function() {
+ hb.when('JSONP', '/url1').then(200);
+ hb.expect('JSONP', '/url2').respond(200);
+
+ expect(hb('JSONP', '/url1')).toBeUndefined();
+ expect(hb('JSONP', '/url2')).toBeUndefined();
+ });
+
+
+ describe('verify', function() {
+
+ it('should throw exception if not all expectations were satisfied', function() {
+ hb.expect('POST', '/u1', 'ddd').respond(201, '', {});
+ hb.expect('GET', '/u2').respond(200, '', {});
+ hb.expect('POST', '/u3').respond(201, '', {});
+
+ hb('POST', '/u1', 'ddd', noop, {});
+
+ expect(function() {hb.verifyExpectations();})
+ .toThrow('Unsatisfied requests: GET /u2, POST /u3');
+ });
+
+
+ it('should do nothing when no expectation', function() {
+ hb.when('DELETE', '/some').then(200, '');
+
+ expect(function() {hb.verifyExpectations();}).not.toThrow();
+ });
+
+
+ it('should do nothing when all expectations satisfied', function() {
+ hb.expect('GET', '/u2').respond(200, '', {});
+ hb.expect('POST', '/u3').respond(201, '', {});
+ hb.when('DELETE', '/some').then(200, '');
+
+ hb('GET', '/u2', noop);
+ hb('POST', '/u3', noop);
+
+ expect(function() {hb.verifyExpectations();}).not.toThrow();
+ });
+ });
+
+
+ describe('reset', function() {
+
+ it('should remove all expectations', function() {
+ hb.expect('GET', '/u2').respond(200, '', {});
+ hb.expect('POST', '/u3').respond(201, '', {});
+ hb.resetExpectations();
+
+ expect(function() {hb.verifyExpectations();}).not.toThrow();
+ });
+
+
+ it('should remove all responses', function() {
+ hb.expect('GET', '/url').respond(200, '', {});
+ hb('GET', '/url', null, callback, {});
+ hb.resetExpectations();
+ hb.flush();
+
+ expect(callback).not.toHaveBeenCalled();
+ });
+ });
+
+
+ describe('MockHttpExpectation', function() {
+
+ it('should accept url as regexp', function() {
+ var exp = new MockHttpExpectation('GET', /^\/x/);
+
+ expect(exp.match('GET', '/x')).toBe(true);
+ expect(exp.match('GET', '/xxx/x')).toBe(true);
+ expect(exp.match('GET', 'x')).toBe(false);
+ expect(exp.match('GET', 'a/x')).toBe(false);
+ });
+
+
+ it('should accept data as regexp', function() {
+ var exp = new MockHttpExpectation('POST', '/url', /\{.*?\}/);
+
+ expect(exp.match('POST', '/url', '{"a": "aa"}')).toBe(true);
+ expect(exp.match('POST', '/url', '{"one": "two"}')).toBe(true);
+ expect(exp.match('POST', '/url', '{"one"')).toBe(false);
+ });
+
+
+ it('should ignore data only if undefined (not null or false)', function() {
+ var exp = new MockHttpExpectation('POST', '/url', null);
+ expect(exp.matchData(null)).toBe(true);
+ expect(exp.matchData('some-data')).toBe(false);
+
+ exp = new MockHttpExpectation('POST', '/url', undefined);
+ expect(exp.matchData(null)).toBe(true);
+ expect(exp.matchData('some-data')).toBe(true);
+ });
+
+
+ it('should accept headers as function', function() {
+ var exp = new MockHttpExpectation('GET', '/url', undefined, function(h) {
+ return h['Content-Type'] == 'application/json';
+ });
+
+ expect(exp.matchHeaders({})).toBe(false);
+ expect(exp.matchHeaders({'Content-Type': 'application/json', 'X-Another': 'true'})).toBe(true);
+ });
+ });
+ });
});
diff --git a/test/service/httpSpec.js b/test/service/httpSpec.js
index 196a57ed..75e85359 100644
--- a/test/service/httpSpec.js
+++ b/test/service/httpSpec.js
@@ -3,98 +3,68 @@
// TODO(vojta): refactor these tests to use new inject() syntax
describe('$http', function() {
- var $http, $browser, $exceptionHandler, // services
- method, url, data, headers, timeout, // passed arguments
- onSuccess, onError, // callback spies
- scope, errorLogs, respond, rawXhrObject, future;
+ var $http, $browser, $exceptionHandler, $httpBackend,
+ scope, callback, future, callback;
beforeEach(inject(function($injector) {
$injector.get('$exceptionHandlerProvider').mode('log');
scope = $injector.get('$rootScope');
$http = $injector.get('$http');
$browser = $injector.get('$browser');
+ $httpBackend = $injector.get('$httpBackend');
$exceptionHandler = $injector.get('$exceptionHandler');
-
- // TODO(vojta): move this into mock browser ?
- respond = method = url = data = headers = null;
- rawXhrObject = {
- abort: jasmine.createSpy('request.abort'),
- getResponseHeader: function(h) {return h + '-val';},
- getAllResponseHeaders: function() {
- return 'content-encoding: gzip\nserver: Apache\n';
- }
- };
-
spyOn(scope, '$apply');
- spyOn($browser, 'xhr').andCallFake(function(m, u, d, c, h, t) {
- method = m;
- url = u;
- data = d;
- respond = c;
- headers = h;
- timeout = t;
- return rawXhrObject;
- });
+ callback = jasmine.createSpy('callback');
}));
afterEach(function() {
- // expect($exceptionHandler.errors.length).toBe(0);
+ if ($exceptionHandler.errors.length) throw $exceptionHandler.errors;
+ $httpBackend.verifyExpectations();
});
- function doCommonXhr(method, url) {
- future = $http({method: method || 'GET', url: url || '/url'});
-
- onSuccess = jasmine.createSpy('on200');
- onError = jasmine.createSpy('on400');
- future.on('200', onSuccess);
- future.on('400', onError);
-
- return future;
- }
-
it('should do basic request', function() {
+ $httpBackend.expect('GET', '/url').respond('');
$http({url: '/url', method: 'GET'});
- expect($browser.xhr).toHaveBeenCalledOnce();
- expect(url).toBe('/url');
- expect(method).toBe('GET');
});
it('should pass data if specified', function() {
+ $httpBackend.expect('POST', '/url', 'some-data').respond('');
$http({url: '/url', method: 'POST', data: 'some-data'});
- expect($browser.xhr).toHaveBeenCalledOnce();
- expect(data).toBe('some-data');
});
- it('should pass timeout if specified', function() {
- $http({url: '/url', method: 'POST', timeout: 5000});
- expect($browser.xhr).toHaveBeenCalledOnce();
- expect(timeout).toBe(5000);
- });
+ // TODO(vojta): test passing timeout
describe('callbacks', function() {
- beforeEach(doCommonXhr);
+ function throwing(name) {
+ return function() {
+ throw name;
+ };
+ }
it('should log exceptions', function() {
- onSuccess.andThrow('exception in success callback');
- onError.andThrow('exception in error callback');
+ $httpBackend.expect('GET', '/url1').respond(200, 'content');
+ $httpBackend.expect('GET', '/url2').respond(400, '');
- respond(200, 'content');
- expect($exceptionHandler.errors.pop()).toContain('exception in success callback');
+ $http({url: '/url1', method: 'GET'}).on('200', throwing('exception in success callback'));
+ $http({url: '/url2', method: 'GET'}).on('400', throwing('exception in error callback'));
+ $httpBackend.flush();
- respond(400, '');
- expect($exceptionHandler.errors.pop()).toContain('exception in error callback');
+ expect($exceptionHandler.errors.shift()).toContain('exception in success callback');
+ expect($exceptionHandler.errors.shift()).toContain('exception in error callback');
});
it('should log more exceptions', function() {
- onError.andThrow('exception in error callback');
- future.on('500', onError).on('50x', onError);
- respond(500, '');
+ $httpBackend.expect('GET', '/url').respond(500, '');
+ $http({url: '/url', method: 'GET'})
+ .on('500', throwing('exception in error callback'))
+ .on('5xx', throwing('exception in error callback'));
+ $httpBackend.flush();
expect($exceptionHandler.errors.length).toBe(2);
$exceptionHandler.errors = [];
@@ -102,82 +72,76 @@ describe('$http', function() {
it('should get response as first param', function() {
- respond(200, 'response');
- expect(onSuccess).toHaveBeenCalledOnce();
- expect(onSuccess.mostRecentCall.args[0]).toBe('response');
+ $httpBackend.expect('GET', '/url').respond('some-content');
+ $http({url: '/url', method: 'GET'}).on('200', callback);
+ $httpBackend.flush();
- respond(400, 'empty');
- expect(onError).toHaveBeenCalledOnce();
- expect(onError.mostRecentCall.args[0]).toBe('empty');
+ expect(callback).toHaveBeenCalledOnce();
+ expect(callback.mostRecentCall.args[0]).toBe('some-content');
});
it('should get status code as second param', function() {
- respond(200, 'response');
- expect(onSuccess).toHaveBeenCalledOnce();
- expect(onSuccess.mostRecentCall.args[1]).toBe(200);
+ $httpBackend.expect('GET', '/url').respond(250, 'some-content');
+ $http({url: '/url', method: 'GET'}).on('2xx', callback);
+ $httpBackend.flush();
- respond(400, 'empty');
- expect(onError).toHaveBeenCalledOnce();
- expect(onError.mostRecentCall.args[1]).toBe(400);
+ expect(callback).toHaveBeenCalledOnce();
+ expect(callback.mostRecentCall.args[1]).toBe(250);
});
});
describe('response headers', function() {
- var callback;
-
- beforeEach(function() {
- callback = jasmine.createSpy('callback');
- });
-
it('should return single header', function() {
+ $httpBackend.expect('GET', '/url').respond('', {'date': 'date-val'});
callback.andCallFake(function(r, s, header) {
expect(header('date')).toBe('date-val');
});
$http({url: '/url', method: 'GET'}).on('200', callback);
- respond(200, '');
+ $httpBackend.flush();
expect(callback).toHaveBeenCalledOnce();
});
it('should return null when single header does not exist', function() {
+ $httpBackend.expect('GET', '/url').respond('', {'Some-Header': 'Fake'});
callback.andCallFake(function(r, s, header) {
header(); // we need that to get headers parsed first
expect(header('nothing')).toBe(null);
});
$http({url: '/url', method: 'GET'}).on('200', callback);
- respond(200, '');
+ $httpBackend.flush();
expect(callback).toHaveBeenCalledOnce();
});
it('should return all headers as object', function() {
+ $httpBackend.expect('GET', '/url').respond('', {'content-encoding': 'gzip', 'server': 'Apache'});
callback.andCallFake(function(r, s, header) {
expect(header()).toEqual({'content-encoding': 'gzip', 'server': 'Apache'});
});
$http({url: '/url', method: 'GET'}).on('200', callback);
- respond(200, '');
+ $httpBackend.flush();
expect(callback).toHaveBeenCalledOnce();
});
it('should return empty object for jsonp request', function() {
- // jsonp doesn't return raw object
- rawXhrObject = undefined;
callback.andCallFake(function(r, s, headers) {
expect(headers()).toEqual({});
});
+ $httpBackend.expect('JSONP', '/some').respond(200);
$http({url: '/some', method: 'JSONP'}).on('200', callback);
- respond(200, '');
+ $httpBackend.flush();
expect(callback).toHaveBeenCalledOnce();
});
});
@@ -250,202 +214,192 @@ describe('$http', function() {
describe('request headers', function() {
it('should send custom headers', function() {
+ $httpBackend.expect('GET', '/url', undefined, function(headers) {
+ return headers['Custom'] == 'header' && headers['Content-Type'] == 'application/json';
+ }).respond('');
+
$http({url: '/url', method: 'GET', headers: {
'Custom': 'header',
'Content-Type': 'application/json'
}});
- expect(headers['Custom']).toEqual('header');
- expect(headers['Content-Type']).toEqual('application/json');
+ $httpBackend.flush();
});
it('should set default headers for GET request', function() {
- $http({url: '/url', method: 'GET', headers: {}});
+ $httpBackend.expect('GET', '/url', undefined, function(headers) {
+ return headers['Accept'] == 'application/json, text/plain, */*' &&
+ headers['X-Requested-With'] == 'XMLHttpRequest';
+ }).respond('');
- expect(headers['Accept']).toBe('application/json, text/plain, */*');
- expect(headers['X-Requested-With']).toBe('XMLHttpRequest');
+ $http({url: '/url', method: 'GET', headers: {}});
+ $httpBackend.flush();
});
it('should set default headers for POST request', function() {
- $http({url: '/url', method: 'POST', headers: {}});
+ $httpBackend.expect('POST', '/url', undefined, function(headers) {
+ return headers['Accept'] == 'application/json, text/plain, */*' &&
+ headers['X-Requested-With'] == 'XMLHttpRequest' &&
+ headers['Content-Type'] == 'application/json';
+ }).respond('');
- expect(headers['Accept']).toBe('application/json, text/plain, */*');
- expect(headers['X-Requested-With']).toBe('XMLHttpRequest');
- expect(headers['Content-Type']).toBe('application/json');
+ $http({url: '/url', method: 'POST', headers: {}});
+ $httpBackend.flush();
});
it('should set default headers for PUT request', function() {
- $http({url: '/url', method: 'PUT', headers: {}});
+ $httpBackend.expect('PUT', '/url', undefined, function(headers) {
+ return headers['Accept'] == 'application/json, text/plain, */*' &&
+ headers['X-Requested-With'] == 'XMLHttpRequest' &&
+ headers['Content-Type'] == 'application/json';
+ }).respond('');
- expect(headers['Accept']).toBe('application/json, text/plain, */*');
- expect(headers['X-Requested-With']).toBe('XMLHttpRequest');
- expect(headers['Content-Type']).toBe('application/json');
+ $http({url: '/url', method: 'PUT', headers: {}});
+ $httpBackend.flush();
});
it('should set default headers for custom HTTP method', function() {
- $http({url: '/url', method: 'FOO', headers: {}});
+ $httpBackend.expect('FOO', '/url', undefined, function(headers) {
+ return headers['Accept'] == 'application/json, text/plain, */*' &&
+ headers['X-Requested-With'] == 'XMLHttpRequest';
+ }).respond('');
- expect(headers['Accept']).toBe('application/json, text/plain, */*');
- expect(headers['X-Requested-With']).toBe('XMLHttpRequest');
+ $http({url: '/url', method: 'FOO', headers: {}});
+ $httpBackend.flush();
});
it('should override default headers with custom', function() {
+ $httpBackend.expect('POST', '/url', undefined, function(headers) {
+ return headers['Accept'] == 'Rewritten' &&
+ headers['X-Requested-With'] == 'XMLHttpRequest' &&
+ headers['Content-Type'] == 'Rewritten';
+ }).respond('');
+
$http({url: '/url', method: 'POST', headers: {
'Accept': 'Rewritten',
'Content-Type': 'Rewritten'
}});
-
- expect(headers['Accept']).toBe('Rewritten');
- expect(headers['X-Requested-With']).toBe('XMLHttpRequest');
- expect(headers['Content-Type']).toBe('Rewritten');
+ $httpBackend.flush();
});
it('should set the XSRF cookie into a XSRF header', function() {
+ function checkXSRF(secret) {
+ return function(headers) {
+ return headers['X-XSRF-TOKEN'] == secret;
+ };
+ }
+
$browser.cookies('XSRF-TOKEN', 'secret');
+ $httpBackend.expect('GET', '/url', undefined, checkXSRF('secret')).respond('');
+ $httpBackend.expect('POST', '/url', undefined, checkXSRF('secret')).respond('');
+ $httpBackend.expect('PUT', '/url', undefined, checkXSRF('secret')).respond('');
+ $httpBackend.expect('DELETE', '/url', undefined, checkXSRF('secret')).respond('');
$http({url: '/url', method: 'GET'});
- expect(headers['X-XSRF-TOKEN']).toBe('secret');
-
$http({url: '/url', method: 'POST', headers: {'S-ome': 'Header'}});
- expect(headers['X-XSRF-TOKEN']).toBe('secret');
-
$http({url: '/url', method: 'PUT', headers: {'Another': 'Header'}});
- expect(headers['X-XSRF-TOKEN']).toBe('secret');
-
$http({url: '/url', method: 'DELETE', headers: {}});
- expect(headers['X-XSRF-TOKEN']).toBe('secret');
+
+ $httpBackend.flush();
});
});
describe('short methods', function() {
- it('should have .get()', function() {
- $http.get('/url');
+ function checkHeader(name, value) {
+ return function(headers) {
+ return headers[name] == value;
+ };
+ }
- expect(method).toBe('GET');
- expect(url).toBe('/url');
+ it('should have get()', function() {
+ $httpBackend.expect('GET', '/url').respond('');
+ $http.get('/url');
});
- it('.get() should allow config param', function() {
+ it('get() should allow config param', function() {
+ $httpBackend.expect('GET', '/url', undefined, checkHeader('Custom', 'Header')).respond('');
$http.get('/url', {headers: {'Custom': 'Header'}});
-
- expect(method).toBe('GET');
- expect(url).toBe('/url');
- expect(headers['Custom']).toBe('Header');
});
- it('should have .delete()', function() {
+ it('should have delete()', function() {
+ $httpBackend.expect('DELETE', '/url').respond('');
$http['delete']('/url');
-
- expect(method).toBe('DELETE');
- expect(url).toBe('/url');
});
- it('.delete() should allow config param', function() {
+ it('delete() should allow config param', function() {
+ $httpBackend.expect('DELETE', '/url', undefined, checkHeader('Custom', 'Header')).respond('');
$http['delete']('/url', {headers: {'Custom': 'Header'}});
-
- expect(method).toBe('DELETE');
- expect(url).toBe('/url');
- expect(headers['Custom']).toBe('Header');
});
- it('should have .head()', function() {
+ it('should have head()', function() {
+ $httpBackend.expect('HEAD', '/url').respond('');
$http.head('/url');
-
- expect(method).toBe('HEAD');
- expect(url).toBe('/url');
});
- it('.head() should allow config param', function() {
+ it('head() should allow config param', function() {
+ $httpBackend.expect('HEAD', '/url', undefined, checkHeader('Custom', 'Header')).respond('');
$http.head('/url', {headers: {'Custom': 'Header'}});
-
- expect(method).toBe('HEAD');
- expect(url).toBe('/url');
- expect(headers['Custom']).toBe('Header');
});
- it('should have .patch()', function() {
+ it('should have patch()', function() {
+ $httpBackend.expect('PATCH', '/url').respond('');
$http.patch('/url');
-
- expect(method).toBe('PATCH');
- expect(url).toBe('/url');
});
- it('.patch() should allow config param', function() {
+ it('patch() should allow config param', function() {
+ $httpBackend.expect('PATCH', '/url', undefined, checkHeader('Custom', 'Header')).respond('');
$http.patch('/url', {headers: {'Custom': 'Header'}});
-
- expect(method).toBe('PATCH');
- expect(url).toBe('/url');
- expect(headers['Custom']).toBe('Header');
});
- it('should have .post()', function() {
+ it('should have post()', function() {
+ $httpBackend.expect('POST', '/url', 'some-data').respond('');
$http.post('/url', 'some-data');
-
- expect(method).toBe('POST');
- expect(url).toBe('/url');
- expect(data).toBe('some-data');
});
- it('.post() should allow config param', function() {
+ it('post() should allow config param', function() {
+ $httpBackend.expect('POST', '/url', 'some-data', checkHeader('Custom', 'Header')).respond('');
$http.post('/url', 'some-data', {headers: {'Custom': 'Header'}});
-
- expect(method).toBe('POST');
- expect(url).toBe('/url');
- expect(data).toBe('some-data');
- expect(headers['Custom']).toBe('Header');
});
- it('should have .put()', function() {
+ it('should have put()', function() {
+ $httpBackend.expect('PUT', '/url', 'some-data').respond('');
$http.put('/url', 'some-data');
-
- expect(method).toBe('PUT');
- expect(url).toBe('/url');
- expect(data).toBe('some-data');
});
- it('.put() should allow config param', function() {
+ it('put() should allow config param', function() {
+ $httpBackend.expect('PUT', '/url', 'some-data', checkHeader('Custom', 'Header')).respond('');
$http.put('/url', 'some-data', {headers: {'Custom': 'Header'}});
-
- expect(method).toBe('PUT');
- expect(url).toBe('/url');
- expect(data).toBe('some-data');
- expect(headers['Custom']).toBe('Header');
});
- it('should have .jsonp()', function() {
+ it('should have jsonp()', function() {
+ $httpBackend.expect('JSONP', '/url').respond('');
$http.jsonp('/url');
-
- expect(method).toBe('JSONP');
- expect(url).toBe('/url');
});
- it('.jsonp() should allow config param', function() {
+ it('jsonp() should allow config param', function() {
+ $httpBackend.expect('JSONP', '/url', undefined, checkHeader('Custom', 'Header')).respond('');
$http.jsonp('/url', {headers: {'Custom': 'Header'}});
-
- expect(method).toBe('JSONP');
- expect(url).toBe('/url');
- expect(headers['Custom']).toBe('Header');
});
});
@@ -454,7 +408,14 @@ describe('$http', function() {
describe('abort', function() {
- beforeEach(doCommonXhr);
+ var future, rawXhrObject;
+
+ beforeEach(function() {
+ $httpBackend.when('GET', '/url').then('');
+ future = $http({method: 'GET', url: '/url'});
+ rawXhrObject = MockXhr.$$lastInstance;
+ spyOn(rawXhrObject, 'abort');
+ });
it('should return itself to allow chaining', function() {
expect(future.abort()).toBe(future);
@@ -468,7 +429,7 @@ describe('$http', function() {
it('should not abort already finished request', function() {
- respond(200, 'content');
+ $httpBackend.flush();
future.abort();
expect(rawXhrObject.abort).not.toHaveBeenCalled();
@@ -478,31 +439,33 @@ describe('$http', function() {
describe('retry', function() {
+ var future;
+
+ beforeEach(function() {
+ $httpBackend.expect('HEAD', '/url-x').respond('');
+ future = $http({method: 'HEAD', url: '/url-x'}).on('2xx', callback);
+ });
+
it('should retry last request with same callbacks', function() {
- doCommonXhr('HEAD', '/url-x');
- respond(200, '');
- $browser.xhr.reset();
- onSuccess.reset();
+ $httpBackend.flush();
+ callback.reset();
+ $httpBackend.expect('HEAD', '/url-x').respond('');
future.retry();
- expect($browser.xhr).toHaveBeenCalledOnce();
- expect(method).toBe('HEAD');
- expect(url).toBe('/url-x');
-
- respond(200, 'body');
- expect(onSuccess).toHaveBeenCalledOnce();
+ $httpBackend.flush();
+ expect(callback).toHaveBeenCalledOnce();
});
it('should return itself to allow chaining', function() {
- doCommonXhr();
- respond(200, '');
+ $httpBackend.flush();
+
+ $httpBackend.expect('HEAD', '/url-x').respond('');
expect(future.retry()).toBe(future);
});
it('should throw error when pending request', function() {
- doCommonXhr();
expect(future.retry).toThrow('Can not retry request. Abort pending request first.');
});
});
@@ -510,98 +473,92 @@ describe('$http', function() {
describe('on', function() {
- var callback;
+ var future;
+
+ function expectToMatch(status, pattern) {
+ expectToNotMatch(status, pattern, true);
+ }
+
+ function expectToNotMatch(status, pattern, match) {
+ callback.reset();
+ future = $http({method: 'GET', url: '/' + status});
+ future.on(pattern, callback);
+ $httpBackend.flush();
+
+ if (match) expect(callback).toHaveBeenCalledOnce();
+ else expect(callback).not.toHaveBeenCalledOnce();
+ }
beforeEach(function() {
- future = $http({method: 'GET', url: '/url'});
- callback = jasmine.createSpy('callback');
+ $httpBackend.when('GET').then(function(m, url) {
+ return [parseInt(url.substr(1)), '', {}];
+ });
});
it('should return itself to allow chaining', function() {
+ future = $http({method: 'GET', url: '/url'});
expect(future.on('200', noop)).toBe(future);
});
it('should call exact status code callback', function() {
- future.on('205', callback);
- respond(205, '');
-
- expect(callback).toHaveBeenCalledOnce();
+ expectToMatch(205, '205');
});
it('should match 2xx', function() {
- future.on('2xx', callback);
-
- respond(200, '');
- respond(201, '');
- respond(266, '');
+ expectToMatch(200, '2xx');
+ expectToMatch(201, '2xx');
+ expectToMatch(266, '2xx');
- respond(400, '');
- respond(300, '');
-
- expect(callback).toHaveBeenCalled();
- expect(callback.callCount).toBe(3);
+ expectToNotMatch(400, '2xx');
+ expectToNotMatch(300, '2xx');
});
it('should match 20x', function() {
- future.on('20x', callback);
-
- respond(200, '');
- respond(201, '');
- respond(205, '');
-
- respond(400, '');
- respond(300, '');
- respond(210, '');
- respond(255, '');
+ expectToMatch(200, '20x');
+ expectToMatch(201, '20x');
+ expectToMatch(205, '20x');
- expect(callback).toHaveBeenCalled();
- expect(callback.callCount).toBe(3);
+ expectToNotMatch(210, '20x');
+ expectToNotMatch(301, '20x');
+ expectToNotMatch(404, '20x');
+ expectToNotMatch(501, '20x');
});
it('should match 2x1', function() {
- future.on('2x1', callback);
-
- respond(201, '');
- respond(211, '');
- respond(251, '');
-
- respond(400, '');
- respond(300, '');
- respond(210, '');
- respond(255, '');
+ expectToMatch(201, '2x1');
+ expectToMatch(211, '2x1');
+ expectToMatch(251, '2x1');
- expect(callback).toHaveBeenCalled();
- expect(callback.callCount).toBe(3);
+ expectToNotMatch(210, '2x1');
+ expectToNotMatch(301, '2x1');
+ expectToNotMatch(400, '2x1');
});
it('should match xxx', function() {
- future.on('xxx', callback);
-
- respond(201, '');
- respond(211, '');
- respond(251, '');
- respond(404, '');
- respond(501, '');
-
- expect(callback).toHaveBeenCalled();
- expect(callback.callCount).toBe(5);
+ expectToMatch(200, 'xxx');
+ expectToMatch(210, 'xxx');
+ expectToMatch(301, 'xxx');
+ expectToMatch(406, 'xxx');
+ expectToMatch(510, 'xxx');
});
it('should call all matched callbacks', function() {
var no = jasmine.createSpy('wrong');
- future.on('xxx', callback);
- future.on('2xx', callback);
- future.on('205', callback);
- future.on('3xx', no);
- future.on('2x1', no);
- future.on('4xx', no);
- respond(205, '');
+ $http({method: 'GET', url: '/205'})
+ .on('xxx', callback)
+ .on('2xx', callback)
+ .on('205', callback)
+ .on('3xx', no)
+ .on('2x1', no)
+ .on('4xx', no);
+
+ $httpBackend.flush();
expect(callback).toHaveBeenCalled();
expect(callback.callCount).toBe(3);
@@ -610,98 +567,66 @@ describe('$http', function() {
it('should allow list of status patterns', function() {
- future.on('2xx,3xx', callback);
-
- respond(405, '');
- expect(callback).not.toHaveBeenCalled();
-
- respond(201);
- expect(callback).toHaveBeenCalledOnce();
-
- respond(301);
- expect(callback.callCount).toBe(2);
+ expectToMatch(201, '2xx,3xx');
+ expectToMatch(301, '2xx,3xx');
+ expectToNotMatch(405, '2xx,3xx');
});
it('should preserve the order of listeners', function() {
var log = '';
- future.on('2xx', function() {log += '1';});
- future.on('201', function() {log += '2';});
- future.on('2xx', function() {log += '3';});
- respond(201);
+ $http({method: 'GET', url: '/201'})
+ .on('2xx', function() {log += '1';})
+ .on('201', function() {log += '2';})
+ .on('2xx', function() {log += '3';});
+
+ $httpBackend.flush();
expect(log).toBe('123');
});
it('should know "success" alias', function() {
- future.on('success', callback);
- respond(200, '');
- expect(callback).toHaveBeenCalledOnce();
-
- callback.reset();
- respond(201, '');
- expect(callback).toHaveBeenCalledOnce();
-
- callback.reset();
- respond(250, '');
- expect(callback).toHaveBeenCalledOnce();
+ expectToMatch(200, 'success');
+ expectToMatch(201, 'success');
+ expectToMatch(250, 'success');
- callback.reset();
- respond(404, '');
- respond(501, '');
- expect(callback).not.toHaveBeenCalled();
+ expectToNotMatch(403, 'success');
+ expectToNotMatch(501, 'success');
});
it('should know "error" alias', function() {
- future.on('error', callback);
- respond(401, '');
- expect(callback).toHaveBeenCalledOnce();
-
- callback.reset();
- respond(500, '');
- expect(callback).toHaveBeenCalledOnce();
+ expectToMatch(401, 'error');
+ expectToMatch(500, 'error');
+ expectToMatch(0, 'error');
- callback.reset();
- respond(0, '');
- expect(callback).toHaveBeenCalledOnce();
-
- callback.reset();
- respond(201, '');
- respond(200, '');
- respond(300, '');
- expect(callback).not.toHaveBeenCalled();
+ expectToNotMatch(201, 'error');
+ expectToNotMatch(200, 'error');
});
it('should know "always" alias', function() {
- future.on('always', callback);
- respond(201, '');
- respond(200, '');
- respond(300, '');
- respond(401, '');
- respond(502, '');
- respond(0, '');
- respond(-1, '');
- respond(-2, '');
-
- expect(callback).toHaveBeenCalled();
- expect(callback.callCount).toBe(8);
+ expectToMatch(200, 'always');
+ expectToMatch(201, 'always');
+ expectToMatch(250, 'always');
+ expectToMatch(300, 'always');
+ expectToMatch(302, 'always');
+ expectToMatch(404, 'always');
+ expectToMatch(501, 'always');
+ expectToMatch(0, 'always');
+ expectToMatch(-1, 'always');
+ expectToMatch(-2, 'always');
});
it('should call "xxx" when 0 status code', function() {
- future.on('xxx', callback);
- respond(0, '');
- expect(callback).toHaveBeenCalledOnce();
+ expectToMatch(0, 'xxx');
});
it('should not call "2xx" when 0 status code', function() {
- future.on('2xx', callback);
- respond(0, '');
- expect(callback).not.toHaveBeenCalled();
+ expectToNotMatch(0, '2xx');
});
it('should normalize internal statuses -1, -2 to 0', function() {
@@ -709,36 +634,27 @@ describe('$http', function() {
expect(status).toBe(0);
});
- future.on('xxx', callback);
- respond(-1, '');
- respond(-2, '');
+ $http({method: 'GET', url: '/0'}).on('xxx', callback);
+ $http({method: 'GET', url: '/-1'}).on('xxx', callback);
+ $http({method: 'GET', url: '/-2'}).on('xxx', callback);
+ $httpBackend.flush();
expect(callback).toHaveBeenCalled();
- expect(callback.callCount).toBe(2);
+ expect(callback.callCount).toBe(3);
});
it('should match "timeout" when -1 internal status', function() {
- future.on('timeout', callback);
- respond(-1, '');
-
- expect(callback).toHaveBeenCalledOnce();
+ expectToMatch(-1, 'timeout');
});
it('should match "abort" when 0 status', function() {
- future.on('abort', callback);
- respond(0, '');
-
- expect(callback).toHaveBeenCalledOnce();
+ expectToMatch(0, 'abort');
});
it('should match "error" when 0, -1, or -2', function() {
- future.on('error', callback);
- respond(0, '');
- respond(-1, '');
- respond(-2, '');
-
- expect(callback).toHaveBeenCalled();
- expect(callback.callCount).toBe(3);
+ expectToMatch(0, 'error');
+ expectToMatch(-1, 'error');
+ expectToMatch(-2, 'error');
});
});
});
@@ -746,29 +662,28 @@ describe('$http', function() {
describe('scope.$apply', function() {
- beforeEach(doCommonXhr);
-
it('should $apply after success callback', function() {
- respond(200, '');
+ $httpBackend.when('GET').then(200);
+ $http({method: 'GET', url: '/some'});
+ $httpBackend.flush();
expect(scope.$apply).toHaveBeenCalledOnce();
});
it('should $apply after error callback', function() {
- respond(404, '');
+ $httpBackend.when('GET').then(404);
+ $http({method: 'GET', url: '/some'});
+ $httpBackend.flush();
expect(scope.$apply).toHaveBeenCalledOnce();
});
it('should $apply even if exception thrown during callback', function() {
- onSuccess.andThrow('error in callback');
- onError.andThrow('error in callback');
-
- respond(200, '');
- expect(scope.$apply).toHaveBeenCalledOnce();
+ $httpBackend.when('GET').then(200);
+ callback.andThrow('error in callback');
- scope.$apply.reset();
- respond(400, '');
+ $http({method: 'GET', url: '/some'}).on('200', callback);
+ $httpBackend.flush();
expect(scope.$apply).toHaveBeenCalledOnce();
$exceptionHandler.errors = [];
@@ -783,14 +698,14 @@ describe('$http', function() {
describe('default', function() {
it('should transform object into json', function() {
+ $httpBackend.expect('POST', '/url', '{"one":"two"}').respond('');
$http({method: 'POST', url: '/url', data: {one: 'two'}});
- expect(data).toBe('{"one":"two"}');
});
it('should ignore strings', function() {
+ $httpBackend.expect('POST', '/url', 'string-data').respond('');
$http({method: 'POST', url: '/url', data: 'string-data'});
- expect(data).toBe('string-data');
});
});
});
@@ -801,40 +716,47 @@ describe('$http', function() {
describe('default', function() {
it('should deserialize json objects', function() {
- doCommonXhr();
- respond(200, '{"foo":"bar","baz":23}');
+ $httpBackend.expect('GET', '/url').respond('{"foo":"bar","baz":23}');
+ $http({method: 'GET', url: '/url'}).on('200', callback);
+ $httpBackend.flush();
- expect(onSuccess.mostRecentCall.args[0]).toEqual({foo: 'bar', baz: 23});
+ expect(callback).toHaveBeenCalledOnce();
+ expect(callback.mostRecentCall.args[0]).toEqual({foo: 'bar', baz: 23});
});
it('should deserialize json arrays', function() {
- doCommonXhr();
- respond(200, '[1, "abc", {"foo":"bar"}]');
+ $httpBackend.expect('GET', '/url').respond('[1, "abc", {"foo":"bar"}]');
+ $http({method: 'GET', url: '/url'}).on('200', callback);
+ $httpBackend.flush();
- expect(onSuccess.mostRecentCall.args[0]).toEqual([1, 'abc', {foo: 'bar'}]);
+ expect(callback).toHaveBeenCalledOnce();
+ expect(callback.mostRecentCall.args[0]).toEqual([1, 'abc', {foo: 'bar'}]);
});
it('should deserialize json with security prefix', function() {
- doCommonXhr();
- respond(200, ')]}\',\n[1, "abc", {"foo":"bar"}]');
+ $httpBackend.expect('GET', '/url').respond(')]}\',\n[1, "abc", {"foo":"bar"}]');
+ $http({method: 'GET', url: '/url'}).on('200', callback);
+ $httpBackend.flush();
- expect(onSuccess.mostRecentCall.args[0]).toEqual([1, 'abc', {foo:'bar'}]);
+ expect(callback).toHaveBeenCalledOnce();
+ expect(callback.mostRecentCall.args[0]).toEqual([1, 'abc', {foo:'bar'}]);
});
});
+
it('should pipeline more functions', function() {
function first(d) {return d + '1';}
function second(d) {return d + '2';}
- onSuccess = jasmine.createSpy('onSuccess');
- $http({method: 'POST', url: '/url', data: '0', transformResponse: [first, second]})
- .on('200', onSuccess);
+ $httpBackend.expect('POST', '/url').respond('0');
+ $http({method: 'POST', url: '/url', transformResponse: [first, second]})
+ .on('200', callback);
+ $httpBackend.flush();
- respond(200, '0');
- expect(onSuccess).toHaveBeenCalledOnce();
- expect(onSuccess.mostRecentCall.args[0]).toBe('012');
+ expect(callback).toHaveBeenCalledOnce();
+ expect(callback.mostRecentCall.args[0]).toBe('012');
});
});
});
@@ -842,95 +764,100 @@ describe('$http', function() {
describe('cache', function() {
- function doFirstCacheRequest(method, responseStatus) {
- onSuccess = jasmine.createSpy('on200');
- $http({method: method || 'get', url: '/url', cache: true});
- respond(responseStatus || 200, 'content');
- $browser.xhr.reset();
+ function doFirstCacheRequest(method, respStatus, headers) {
+ $httpBackend.expect(method || 'GET', '/url').respond(respStatus || 200, 'content', headers);
+ $http({method: method || 'GET', url: '/url', cache: true});
+ $httpBackend.flush();
}
it('should cache GET request', function() {
doFirstCacheRequest();
- $http({method: 'get', url: '/url', cache: true}).on('200', onSuccess);
+ $http({method: 'get', url: '/url', cache: true}).on('200', callback);
$browser.defer.flush();
- expect(onSuccess).toHaveBeenCalledOnce();
- expect(onSuccess.mostRecentCall.args[0]).toBe('content');
- expect($browser.xhr).not.toHaveBeenCalled();
+ expect(callback).toHaveBeenCalledOnce();
+ expect(callback.mostRecentCall.args[0]).toBe('content');
});
it('should always call callback asynchronously', function() {
doFirstCacheRequest();
+ $http({method: 'get', url: '/url', cache: true}).on('200', callback);
- $http({method: 'get', url: '/url', cache: true}).on('200', onSuccess);
- expect(onSuccess).not.toHaveBeenCalled();
+ expect(callback).not.toHaveBeenCalledOnce();
});
it('should not cache POST request', function() {
- doFirstCacheRequest('post');
+ doFirstCacheRequest('POST');
- $http({method: 'post', url: '/url', cache: true}).on('200', onSuccess);
- $browser.defer.flush();
- expect(onSuccess).not.toHaveBeenCalled();
- expect($browser.xhr).toHaveBeenCalledOnce();
+ $httpBackend.expect('POST', '/url').respond('content2');
+ $http({method: 'POST', url: '/url', cache: true}).on('200', callback);
+ $httpBackend.flush();
+
+ expect(callback).toHaveBeenCalledOnce();
+ expect(callback.mostRecentCall.args[0]).toBe('content2');
});
it('should not cache PUT request', function() {
- doFirstCacheRequest('put');
+ doFirstCacheRequest('PUT');
- $http({method: 'put', url: '/url', cache: true}).on('200', onSuccess);
- $browser.defer.flush();
- expect(onSuccess).not.toHaveBeenCalled();
- expect($browser.xhr).toHaveBeenCalledOnce();
+ $httpBackend.expect('PUT', '/url').respond('content2');
+ $http({method: 'PUT', url: '/url', cache: true}).on('200', callback);
+ $httpBackend.flush();
+
+ expect(callback).toHaveBeenCalledOnce();
+ expect(callback.mostRecentCall.args[0]).toBe('content2');
});
it('should not cache DELETE request', function() {
- doFirstCacheRequest('delete');
+ doFirstCacheRequest('DELETE');
- $http({method: 'delete', url: '/url', cache: true}).on('200', onSuccess);
- $browser.defer.flush();
- expect(onSuccess).not.toHaveBeenCalled();
- expect($browser.xhr).toHaveBeenCalledOnce();
+ $httpBackend.expect('DELETE', '/url').respond(206);
+ $http({method: 'DELETE', url: '/url', cache: true}).on('206', callback);
+ $httpBackend.flush();
+
+ expect(callback).toHaveBeenCalledOnce();
});
it('should not cache non 2xx responses', function() {
- doFirstCacheRequest('get', 404);
+ doFirstCacheRequest('GET', 404);
- $http({method: 'get', url: '/url', cache: true}).on('200', onSuccess);
- $browser.defer.flush();
- expect(onSuccess).not.toHaveBeenCalled();
- expect($browser.xhr).toHaveBeenCalledOnce();
+ $httpBackend.expect('GET', '/url').respond('content2');
+ $http({method: 'GET', url: '/url', cache: true}).on('200', callback);
+ $httpBackend.flush();
+
+ expect(callback).toHaveBeenCalledOnce();
+ expect(callback.mostRecentCall.args[0]).toBe('content2');
});
it('should cache the headers as well', function() {
- doFirstCacheRequest();
- onSuccess.andCallFake(function(r, s, headers) {
+ doFirstCacheRequest('GET', 200, {'content-encoding': 'gzip', 'server': 'Apache'});
+ callback.andCallFake(function(r, s, headers) {
expect(headers()).toEqual({'content-encoding': 'gzip', 'server': 'Apache'});
expect(headers('server')).toBe('Apache');
});
- $http({method: 'get', url: '/url', cache: true}).on('200', onSuccess);
+ $http({method: 'GET', url: '/url', cache: true}).on('200', callback);
$browser.defer.flush();
- expect(onSuccess).toHaveBeenCalledOnce();
+ expect(callback).toHaveBeenCalledOnce();
});
it('should cache status code as well', function() {
- doFirstCacheRequest('get', 201);
- onSuccess.andCallFake(function(r, status, h) {
+ doFirstCacheRequest('GET', 201);
+ callback.andCallFake(function(r, status, h) {
expect(status).toBe(201);
});
- $http({method: 'get', url: '/url', cache: true}).on('2xx', onSuccess);
+ $http({method: 'get', url: '/url', cache: true}).on('2xx', callback);
$browser.defer.flush();
- expect(onSuccess).toHaveBeenCalledOnce();
+ expect(callback).toHaveBeenCalledOnce();
});
});
@@ -938,29 +865,34 @@ describe('$http', function() {
describe('pendingCount', function() {
it('should return number of pending requests', function() {
+ $httpBackend.when('GET').then(200);
expect($http.pendingCount()).toBe(0);
$http({method: 'get', url: '/some'});
expect($http.pendingCount()).toBe(1);
- respond(200, '');
+ $httpBackend.flush();
expect($http.pendingCount()).toBe(0);
});
it('should decrement the counter when request aborted', function() {
+ $httpBackend.when('GET').then(0);
future = $http({method: 'get', url: '/x'});
expect($http.pendingCount()).toBe(1);
+
future.abort();
- respond(0, '');
+ $httpBackend.flush();
expect($http.pendingCount()).toBe(0);
});
it('should decrement the counter when served from cache', function() {
+ $httpBackend.when('GET').then(200);
+
$http({method: 'get', url: '/cached', cache: true});
- respond(200, 'content');
+ $httpBackend.flush();
expect($http.pendingCount()).toBe(0);
$http({method: 'get', url: '/cached', cache: true});
@@ -972,12 +904,13 @@ describe('$http', function() {
it('should decrement the counter before firing callbacks', function() {
- $http({method: 'get', url: '/cached'}).on('xxx', function() {
+ $httpBackend.when('GET').then(200);
+ $http({method: 'get', url: '/url'}).on('xxx', function() {
expect($http.pendingCount()).toBe(0);
});
expect($http.pendingCount()).toBe(1);
- respond(200, 'content');
+ $httpBackend.flush();
});
});
});
diff --git a/test/widgetsSpec.js b/test/widgetsSpec.js
index 2ddb26e1..c3bc1333 100644
--- a/test/widgetsSpec.js
+++ b/test/widgetsSpec.js
@@ -134,14 +134,13 @@ describe("widget", function() {
expect($rootScope.$$childHead).toBeFalsy();
}));
- it('should do xhr request and cache it', inject(function($rootScope, $browser, $compile) {
+ it('should do xhr request and cache it', inject(function($rootScope, $httpBackend, $compile) {
var element = $compile('<ng:include src="url"></ng:include>')($rootScope);
- var $browserXhr = $browser.xhr;
- $browserXhr.expectGET('myUrl').respond('my partial');
+ $httpBackend.expect('GET', 'myUrl').respond('my partial');
$rootScope.url = 'myUrl';
$rootScope.$digest();
- $browserXhr.flush();
+ $httpBackend.flush();
expect(element.text()).toEqual('my partial');
$rootScope.url = null;
@@ -155,14 +154,13 @@ describe("widget", function() {
}));
it('should clear content when error during xhr request',
- inject(function($browser, $compile, $rootScope) {
+ inject(function($httpBackend, $compile, $rootScope) {
var element = $compile('<ng:include src="url">content</ng:include>')($rootScope);
- var $browserXhr = $browser.xhr;
- $browserXhr.expectGET('myUrl').respond(404, '');
+ $httpBackend.expect('GET', 'myUrl').respond(404, '');
$rootScope.url = 'myUrl';
$rootScope.$digest();
- $browserXhr.flush();
+ $httpBackend.flush();
expect(element.text()).toBe('');
}));
@@ -500,33 +498,33 @@ describe("widget", function() {
it('should load content via xhr when route changes',
- inject(function($rootScope, $compile, $browser, $location, $route) {
+ inject(function($rootScope, $compile, $httpBackend, $location, $route) {
$route.when('/foo', {template: 'myUrl1'});
$route.when('/bar', {template: 'myUrl2'});
expect(element.text()).toEqual('');
$location.path('/foo');
- $browser.xhr.expectGET('myUrl1').respond('<div>{{1+3}}</div>');
+ $httpBackend.expect('GET', 'myUrl1').respond('<div>{{1+3}}</div>');
$rootScope.$digest();
- $browser.xhr.flush();
+ $httpBackend.flush();
expect(element.text()).toEqual('4');
$location.path('/bar');
- $browser.xhr.expectGET('myUrl2').respond('angular is da best');
+ $httpBackend.expect('GET', 'myUrl2').respond('angular is da best');
$rootScope.$digest();
- $browser.xhr.flush();
+ $httpBackend.flush();
expect(element.text()).toEqual('angular is da best');
}));
it('should remove all content when location changes to an unknown route',
- inject(function($rootScope, $compile, $location, $browser, $route) {
+ inject(function($rootScope, $compile, $location, $httpBackend, $route) {
$route.when('/foo', {template: 'myUrl1'});
$location.path('/foo');
- $browser.xhr.expectGET('myUrl1').respond('<div>{{1+3}}</div>');
+ $httpBackend.expect('GET', 'myUrl1').respond('<div>{{1+3}}</div>');
$rootScope.$digest();
- $browser.xhr.flush();
+ $httpBackend.flush();
expect(element.text()).toEqual('4');
$location.path('/unknown');
@@ -535,14 +533,14 @@ describe("widget", function() {
}));
it('should chain scopes and propagate evals to the child scope',
- inject(function($rootScope, $compile, $location, $browser, $route) {
+ inject(function($rootScope, $compile, $location, $httpBackend, $route) {
$route.when('/foo', {template: 'myUrl1'});
$rootScope.parentVar = 'parent';
$location.path('/foo');
- $browser.xhr.expectGET('myUrl1').respond('<div>{{parentVar}}</div>');
+ $httpBackend.expect('GET', 'myUrl1').respond('<div>{{parentVar}}</div>');
$rootScope.$digest();
- $browser.xhr.flush();
+ $httpBackend.flush();
expect(element.text()).toEqual('parent');
$rootScope.parentVar = 'new parent';
@@ -551,10 +549,11 @@ describe("widget", function() {
}));
it('should be possible to nest ng:view in ng:include', inject(function() {
+ // TODO(vojta): refactor this test
var injector = angular.injector('ng', 'ngMock');
var myApp = injector.get('$rootScope');
- var $browser = injector.get('$browser');
- $browser.xhr.expectGET('includePartial.html').respond('view: <ng:view></ng:view>');
+ var $httpBackend = injector.get('$httpBackend');
+ $httpBackend.expect('GET', 'includePartial.html').respond('view: <ng:view></ng:view>');
injector.get('$location').path('/foo');
var $route = injector.get('$route');
@@ -566,9 +565,10 @@ describe("widget", function() {
'</div>')(myApp);
myApp.$apply();
- $browser.xhr.expectGET('viewPartial.html').respond('content');
+ $httpBackend.expect('GET', 'viewPartial.html').respond('content');
+ $httpBackend.flush();
myApp.$digest();
- $browser.xhr.flush();
+ $httpBackend.flush();
expect(myApp.$element.text()).toEqual('include: view: content');
expect($route.current.template).toEqual('viewPartial.html');
@@ -576,11 +576,10 @@ describe("widget", function() {
}));
it('should initialize view template after the view controller was initialized even when ' +
- 'templates were cached', inject(function($rootScope, $compile, $location, $browser, $route) {
+ 'templates were cached', inject(function($rootScope, $compile, $location, $httpBackend, $route) {
//this is a test for a regression that was introduced by making the ng:view cache sync
$route.when('/foo', {controller: ParentCtrl, template: 'viewPartial.html'});
-
$rootScope.log = [];
function ParentCtrl() {
@@ -592,12 +591,12 @@ describe("widget", function() {
};
$location.path('/foo');
- $browser.xhr.expectGET('viewPartial.html').
+ $httpBackend.expect('GET', 'viewPartial.html').
respond('<div ng:init="log.push(\'init\')">' +
'<div ng:controller="ChildCtrl"></div>' +
'</div>');
$rootScope.$apply();
- $browser.xhr.flush();
+ $httpBackend.flush();
expect($rootScope.log).toEqual(['parent', 'init', 'child']);
@@ -608,13 +607,12 @@ describe("widget", function() {
$rootScope.log = [];
$location.path('/foo');
$rootScope.$apply();
- $browser.defer.flush();
expect($rootScope.log).toEqual(['parent', 'init', 'child']);
}));
it('should discard pending xhr callbacks if a new route is requested before the current ' +
- 'finished loading', inject(function($route, $rootScope, $location, $browser) {
+ 'finished loading', inject(function($route, $rootScope, $location, $httpBackend) {
// this is a test for a bad race condition that affected feedback
$route.when('/foo', {template: 'myUrl1'});
@@ -623,26 +621,26 @@ describe("widget", function() {
expect($rootScope.$element.text()).toEqual('');
$location.path('/foo');
- $browser.xhr.expectGET('myUrl1').respond('<div>{{1+3}}</div>');
+ $httpBackend.expect('GET', 'myUrl1').respond('<div>{{1+3}}</div>');
$rootScope.$digest();
$location.path('/bar');
- $browser.xhr.expectGET('myUrl2').respond('<div>{{1+1}}</div>');
+ $httpBackend.expect('GET', 'myUrl2').respond('<div>{{1+1}}</div>');
$rootScope.$digest();
- $browser.xhr.flush(); // now that we have to requests pending, flush!
+ $httpBackend.flush(); // now that we have to requests pending, flush!
expect($rootScope.$element.text()).toEqual('2');
}));
it('should clear the content when error during xhr request',
- inject(function($route, $location, $rootScope, $browser) {
+ inject(function($route, $location, $rootScope, $httpBackend) {
$route.when('/foo', {controller: noop, template: 'myUrl1'});
$location.path('/foo');
- $browser.xhr.expectGET('myUrl1').respond(404, '');
+ $httpBackend.expect('GET', 'myUrl1').respond(404, '');
$rootScope.$element.text('content');
$rootScope.$digest();
- $browser.xhr.flush();
+ $httpBackend.flush();
expect($rootScope.$element.text()).toBe('');
}));