angular.js/test/service/httpSpec.js
Vojta Jina 92995bbce9 fix($http): default json transformation should not crash on angular template
The way we determine whether it's json is lame anyway. We need to change that.
We should probably check the content type header...
2011-11-30 11:17:25 -05:00

984 lines
30 KiB
JavaScript

'use strict';
// TODO(vojta): refactor these tests to use new inject() syntax
describe('$http', function() {
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');
spyOn(scope, '$apply');
callback = jasmine.createSpy('callback');
}));
afterEach(function() {
if ($exceptionHandler.errors.length) throw $exceptionHandler.errors;
$httpBackend.verifyNoOutstandingExpectation();
});
it('should do basic request', function() {
$httpBackend.expect('GET', '/url').respond('');
$http({url: '/url', method: 'GET'});
});
it('should pass data if specified', function() {
$httpBackend.expect('POST', '/url', 'some-data').respond('');
$http({url: '/url', method: 'POST', data: 'some-data'});
});
// TODO(vojta): test passing timeout
describe('callbacks', function() {
function throwing(name) {
return function() {
throw name;
};
}
it('should log exceptions', function() {
$httpBackend.expect('GET', '/url1').respond(200, 'content');
$httpBackend.expect('GET', '/url2').respond(400, '');
$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();
expect($exceptionHandler.errors.shift()).toContain('exception in success callback');
expect($exceptionHandler.errors.shift()).toContain('exception in error callback');
});
it('should log more exceptions', function() {
$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 = [];
});
it('should get response as first param', function() {
$httpBackend.expect('GET', '/url').respond('some-content');
$http({url: '/url', method: 'GET'}).on('200', callback);
$httpBackend.flush();
expect(callback).toHaveBeenCalledOnce();
expect(callback.mostRecentCall.args[0]).toBe('some-content');
});
it('should get status code as second param', function() {
$httpBackend.expect('GET', '/url').respond(250, 'some-content');
$http({url: '/url', method: 'GET'}).on('2xx', callback);
$httpBackend.flush();
expect(callback).toHaveBeenCalledOnce();
expect(callback.mostRecentCall.args[1]).toBe(250);
});
});
describe('response headers', function() {
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);
$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);
$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);
$httpBackend.flush();
expect(callback).toHaveBeenCalledOnce();
});
it('should return empty object for jsonp request', function() {
callback.andCallFake(function(r, s, headers) {
expect(headers()).toEqual({});
});
$httpBackend.expect('JSONP', '/some').respond(200);
$http({url: '/some', method: 'JSONP'}).on('200', callback);
$httpBackend.flush();
expect(callback).toHaveBeenCalledOnce();
});
});
describe('response headers parser', function() {
it('should parse basic', function() {
var parsed = parseHeaders(
'date: Thu, 04 Aug 2011 20:23:08 GMT\n' +
'content-encoding: gzip\n' +
'transfer-encoding: chunked\n' +
'x-cache-info: not cacheable; response has already expired, not cacheable; response has already expired\n' +
'connection: Keep-Alive\n' +
'x-backend-server: pm-dekiwiki03\n' +
'pragma: no-cache\n' +
'server: Apache\n' +
'x-frame-options: DENY\n' +
'content-type: text/html; charset=utf-8\n' +
'vary: Cookie, Accept-Encoding\n' +
'keep-alive: timeout=5, max=1000\n' +
'expires: Thu: , 19 Nov 1981 08:52:00 GMT\n');
expect(parsed['date']).toBe('Thu, 04 Aug 2011 20:23:08 GMT');
expect(parsed['content-encoding']).toBe('gzip');
expect(parsed['transfer-encoding']).toBe('chunked');
expect(parsed['keep-alive']).toBe('timeout=5, max=1000');
});
it('should parse lines without space after colon', function() {
expect(parseHeaders('key:value').key).toBe('value');
});
it('should trim the values', function() {
expect(parseHeaders('key: value ').key).toBe('value');
});
it('should allow headers without value', function() {
expect(parseHeaders('key:').key).toBe('');
});
it('should merge headers with same key', function() {
expect(parseHeaders('key: a\nkey:b\n').key).toBe('a, b');
});
it('should normalize keys to lower case', function() {
expect(parseHeaders('KeY: value').key).toBe('value');
});
it('should parse CRLF as delimiter', function() {
// IE does use CRLF
expect(parseHeaders('a: b\r\nc: d\r\n')).toEqual({a: 'b', c: 'd'});
expect(parseHeaders('a: b\r\nc: d\r\n').a).toBe('b');
});
it('should parse tab after semi-colon', function() {
expect(parseHeaders('a:\tbb').a).toBe('bb');
expect(parseHeaders('a: \tbb').a).toBe('bb');
});
});
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'
}});
$httpBackend.flush();
});
it('should set default headers for GET request', function() {
$httpBackend.expect('GET', '/url', undefined, function(headers) {
return headers['Accept'] == 'application/json, text/plain, */*' &&
headers['X-Requested-With'] == 'XMLHttpRequest';
}).respond('');
$http({url: '/url', method: 'GET', headers: {}});
$httpBackend.flush();
});
it('should set default headers for POST request', function() {
$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('');
$http({url: '/url', method: 'POST', headers: {}});
$httpBackend.flush();
});
it('should set default headers for PUT request', function() {
$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('');
$http({url: '/url', method: 'PUT', headers: {}});
$httpBackend.flush();
});
it('should set default headers for custom HTTP method', function() {
$httpBackend.expect('FOO', '/url', undefined, function(headers) {
return headers['Accept'] == 'application/json, text/plain, */*' &&
headers['X-Requested-With'] == 'XMLHttpRequest';
}).respond('');
$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'
}});
$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'});
$http({url: '/url', method: 'POST', headers: {'S-ome': 'Header'}});
$http({url: '/url', method: 'PUT', headers: {'Another': 'Header'}});
$http({url: '/url', method: 'DELETE', headers: {}});
$httpBackend.flush();
});
});
describe('short methods', function() {
function checkHeader(name, value) {
return function(headers) {
return headers[name] == value;
};
}
it('should have get()', function() {
$httpBackend.expect('GET', '/url').respond('');
$http.get('/url');
});
it('get() should allow config param', function() {
$httpBackend.expect('GET', '/url', undefined, checkHeader('Custom', 'Header')).respond('');
$http.get('/url', {headers: {'Custom': 'Header'}});
});
it('should have delete()', function() {
$httpBackend.expect('DELETE', '/url').respond('');
$http['delete']('/url');
});
it('delete() should allow config param', function() {
$httpBackend.expect('DELETE', '/url', undefined, checkHeader('Custom', 'Header')).respond('');
$http['delete']('/url', {headers: {'Custom': 'Header'}});
});
it('should have head()', function() {
$httpBackend.expect('HEAD', '/url').respond('');
$http.head('/url');
});
it('head() should allow config param', function() {
$httpBackend.expect('HEAD', '/url', undefined, checkHeader('Custom', 'Header')).respond('');
$http.head('/url', {headers: {'Custom': 'Header'}});
});
it('should have patch()', function() {
$httpBackend.expect('PATCH', '/url').respond('');
$http.patch('/url');
});
it('patch() should allow config param', function() {
$httpBackend.expect('PATCH', '/url', undefined, checkHeader('Custom', 'Header')).respond('');
$http.patch('/url', {headers: {'Custom': 'Header'}});
});
it('should have post()', function() {
$httpBackend.expect('POST', '/url', 'some-data').respond('');
$http.post('/url', 'some-data');
});
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'}});
});
it('should have put()', function() {
$httpBackend.expect('PUT', '/url', 'some-data').respond('');
$http.put('/url', 'some-data');
});
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'}});
});
it('should have jsonp()', function() {
$httpBackend.expect('JSONP', '/url').respond('');
$http.jsonp('/url');
});
it('jsonp() should allow config param', function() {
$httpBackend.expect('JSONP', '/url', undefined, checkHeader('Custom', 'Header')).respond('');
$http.jsonp('/url', {headers: {'Custom': 'Header'}});
});
});
describe('future', function() {
describe('abort', function() {
var future, rawXhrObject;
beforeEach(function() {
$httpBackend.when('GET', '/url').respond('');
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);
});
it('should allow aborting the request', function() {
future.abort();
expect(rawXhrObject.abort).toHaveBeenCalledOnce();
});
it('should not abort already finished request', function() {
$httpBackend.flush();
future.abort();
expect(rawXhrObject.abort).not.toHaveBeenCalled();
});
});
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() {
$httpBackend.flush();
callback.reset();
$httpBackend.expect('HEAD', '/url-x').respond('');
future.retry();
$httpBackend.flush();
expect(callback).toHaveBeenCalledOnce();
});
it('should return itself to allow chaining', function() {
$httpBackend.flush();
$httpBackend.expect('HEAD', '/url-x').respond('');
expect(future.retry()).toBe(future);
});
it('should throw error when pending request', function() {
expect(future.retry).toThrow('Can not retry request. Abort pending request first.');
});
});
describe('on', function() {
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.toHaveBeenCalled();
}
beforeEach(function() {
$httpBackend.when('GET').respond(function(m, url) {
return [parseInt(url.substr(1), 10), '', {}];
});
});
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() {
expectToMatch(205, '205');
});
it('should match 2xx', function() {
expectToMatch(200, '2xx');
expectToMatch(201, '2xx');
expectToMatch(266, '2xx');
expectToNotMatch(400, '2xx');
expectToNotMatch(300, '2xx');
});
it('should match 20x', function() {
expectToMatch(200, '20x');
expectToMatch(201, '20x');
expectToMatch(205, '20x');
expectToNotMatch(210, '20x');
expectToNotMatch(301, '20x');
expectToNotMatch(404, '20x');
expectToNotMatch(501, '20x');
});
it('should match 2x1', function() {
expectToMatch(201, '2x1');
expectToMatch(211, '2x1');
expectToMatch(251, '2x1');
expectToNotMatch(210, '2x1');
expectToNotMatch(301, '2x1');
expectToNotMatch(400, '2x1');
});
it('should match xxx', function() {
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');
$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);
expect(no).not.toHaveBeenCalled();
});
it('should allow list of status patterns', function() {
expectToMatch(201, '2xx,3xx');
expectToMatch(301, '2xx,3xx');
expectToNotMatch(405, '2xx,3xx');
});
it('should preserve the order of listeners', function() {
var log = '';
$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() {
expectToMatch(200, 'success');
expectToMatch(201, 'success');
expectToMatch(250, 'success');
expectToNotMatch(403, 'success');
expectToNotMatch(501, 'success');
});
it('should know "error" alias', function() {
expectToMatch(401, 'error');
expectToMatch(500, 'error');
expectToMatch(0, 'error');
expectToNotMatch(201, 'error');
expectToNotMatch(200, 'error');
});
it('should know "always" alias', function() {
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 not call "2xx" when 0 status code', function() {
expectToNotMatch(0, '2xx');
});
it('should normalize internal statuses -1, -2 to 0', function() {
callback.andCallFake(function(response, status) {
expect(status).toBe(0);
});
$http({method: 'GET', url: '/0'}).on('always', callback);
$http({method: 'GET', url: '/-1'}).on('always', callback);
$http({method: 'GET', url: '/-2'}).on('always', callback);
$httpBackend.flush();
expect(callback).toHaveBeenCalled();
expect(callback.callCount).toBe(3);
});
it('should match "timeout" when -1 internal status', function() {
expectToMatch(-1, 'timeout');
});
it('should match "abort" when 0 status', function() {
expectToMatch(0, 'abort');
});
it('should match "error" when 0, -1, or -2', function() {
expectToMatch(0, 'error');
expectToMatch(-1, 'error');
expectToMatch(-2, 'error');
});
});
});
describe('scope.$apply', function() {
it('should $apply after success callback', function() {
$httpBackend.when('GET').respond(200);
$http({method: 'GET', url: '/some'});
$httpBackend.flush();
expect(scope.$apply).toHaveBeenCalledOnce();
});
it('should $apply after error callback', function() {
$httpBackend.when('GET').respond(404);
$http({method: 'GET', url: '/some'});
$httpBackend.flush();
expect(scope.$apply).toHaveBeenCalledOnce();
});
it('should $apply even if exception thrown during callback', function() {
$httpBackend.when('GET').respond(200);
callback.andThrow('error in callback');
$http({method: 'GET', url: '/some'}).on('200', callback);
$httpBackend.flush();
expect(scope.$apply).toHaveBeenCalledOnce();
$exceptionHandler.errors = [];
});
});
it('should broadcast $http.request', function() {
$httpBackend.when('GET').respond(200);
scope.$on('$http.request', callback);
var xhrFuture = $http({method: 'GET', url: '/whatever'});
expect(callback).toHaveBeenCalledOnce();
expect(callback.mostRecentCall.args[1]).toBe(xhrFuture);
});
describe('transform', function() {
describe('request', 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'}});
});
it('should ignore strings', function() {
$httpBackend.expect('POST', '/url', 'string-data').respond('');
$http({method: 'POST', url: '/url', data: 'string-data'});
});
});
});
describe('response', function() {
describe('default', function() {
it('should deserialize json objects', function() {
$httpBackend.expect('GET', '/url').respond('{"foo":"bar","baz":23}');
$http({method: 'GET', url: '/url'}).on('200', callback);
$httpBackend.flush();
expect(callback).toHaveBeenCalledOnce();
expect(callback.mostRecentCall.args[0]).toEqual({foo: 'bar', baz: 23});
});
it('should deserialize json arrays', function() {
$httpBackend.expect('GET', '/url').respond('[1, "abc", {"foo":"bar"}]');
$http({method: 'GET', url: '/url'}).on('200', callback);
$httpBackend.flush();
expect(callback).toHaveBeenCalledOnce();
expect(callback.mostRecentCall.args[0]).toEqual([1, 'abc', {foo: 'bar'}]);
});
it('should deserialize json with security prefix', function() {
$httpBackend.expect('GET', '/url').respond(')]}\',\n[1, "abc", {"foo":"bar"}]');
$http({method: 'GET', url: '/url'}).on('200', callback);
$httpBackend.flush();
expect(callback).toHaveBeenCalledOnce();
expect(callback.mostRecentCall.args[0]).toEqual([1, 'abc', {foo:'bar'}]);
});
it('should deserialize json with security prefix ")]}\'"', function() {
$httpBackend.expect('GET', '/url').respond(')]}\'\n\n[1, "abc", {"foo":"bar"}]');
$http({method: 'GET', url: '/url'}).on('200', callback);
$httpBackend.flush();
expect(callback).toHaveBeenCalledOnce();
expect(callback.mostRecentCall.args[0]).toEqual([1, 'abc', {foo:'bar'}]);
});
it('should not deserialize tpl beginning with ng expression', function() {
$httpBackend.expect('GET', '/url').respond('{{some}}');
$http.get('/url').on('200', callback);
$httpBackend.flush();
expect(callback).toHaveBeenCalledOnce();
expect(callback.mostRecentCall.args[0]).toEqual('{{some}}');
});
});
it('should pipeline more functions', function() {
function first(d) {return d + '1';}
function second(d) {return d + '2';}
$httpBackend.expect('POST', '/url').respond('0');
$http({method: 'POST', url: '/url', transformResponse: [first, second]}).
on('200', callback);
$httpBackend.flush();
expect(callback).toHaveBeenCalledOnce();
expect(callback.mostRecentCall.args[0]).toBe('012');
});
});
});
describe('cache', function() {
var cache;
beforeEach(inject(function($cacheFactory) {
cache = $cacheFactory('testCache');
}));
function doFirstCacheRequest(method, respStatus, headers) {
$httpBackend.expect(method || 'GET', '/url').respond(respStatus || 200, 'content', headers);
$http({method: method || 'GET', url: '/url', cache: cache});
$httpBackend.flush();
}
it('should cache GET request when cache is provided', function() {
doFirstCacheRequest();
$http({method: 'get', url: '/url', cache: cache}).on('200', callback);
$browser.defer.flush();
expect(callback).toHaveBeenCalledOnce();
expect(callback.mostRecentCall.args[0]).toBe('content');
});
it('should not cache when cache is not provided', function() {
doFirstCacheRequest();
$httpBackend.expect('GET', '/url').respond();
$http({method: 'GET', url: '/url'});
});
it('should perform request when cache cleared', function() {
doFirstCacheRequest();
cache.removeAll();
$httpBackend.expect('GET', '/url').respond();
$http({method: 'GET', url: '/url', cache: cache});
});
it('should always call callback asynchronously', function() {
doFirstCacheRequest();
$http({method: 'get', url: '/url', cache: cache}).on('200', callback);
expect(callback).not.toHaveBeenCalled();
});
it('should not cache POST request', function() {
doFirstCacheRequest('POST');
$httpBackend.expect('POST', '/url').respond('content2');
$http({method: 'POST', url: '/url', cache: cache}).on('200', callback);
$httpBackend.flush();
expect(callback).toHaveBeenCalledOnce();
expect(callback.mostRecentCall.args[0]).toBe('content2');
});
it('should not cache PUT request', function() {
doFirstCacheRequest('PUT');
$httpBackend.expect('PUT', '/url').respond('content2');
$http({method: 'PUT', url: '/url', cache: cache}).on('200', callback);
$httpBackend.flush();
expect(callback).toHaveBeenCalledOnce();
expect(callback.mostRecentCall.args[0]).toBe('content2');
});
it('should not cache DELETE request', function() {
doFirstCacheRequest('DELETE');
$httpBackend.expect('DELETE', '/url').respond(206);
$http({method: 'DELETE', url: '/url', cache: cache}).on('206', callback);
$httpBackend.flush();
expect(callback).toHaveBeenCalledOnce();
});
it('should not cache non 2xx responses', function() {
doFirstCacheRequest('GET', 404);
$httpBackend.expect('GET', '/url').respond('content2');
$http({method: 'GET', url: '/url', cache: cache}).on('200', callback);
$httpBackend.flush();
expect(callback).toHaveBeenCalledOnce();
expect(callback.mostRecentCall.args[0]).toBe('content2');
});
it('should cache the headers as well', function() {
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: cache}).on('200', callback);
$browser.defer.flush();
expect(callback).toHaveBeenCalledOnce();
});
it('should cache status code as well', function() {
doFirstCacheRequest('GET', 201);
callback.andCallFake(function(r, status, h) {
expect(status).toBe(201);
});
$http({method: 'get', url: '/url', cache: cache}).on('2xx', callback);
$browser.defer.flush();
expect(callback).toHaveBeenCalledOnce();
});
it('should use cache even if request fired before first response is back', function() {
$httpBackend.expect('GET', '/url').respond(201, 'fake-response');
callback.andCallFake(function(response, status, headers) {
expect(response).toBe('fake-response');
expect(status).toBe(201);
});
$http({method: 'GET', url: '/url', cache: cache}).on('always', callback);
$http({method: 'GET', url: '/url', cache: cache}).on('always', callback);
$httpBackend.flush();
expect(callback).toHaveBeenCalled();
expect(callback.callCount).toBe(2);
});
});
describe('pendingRequests', function() {
it('should be an array of pending requests', function() {
$httpBackend.when('GET').respond(200);
expect($http.pendingRequests.length).toBe(0);
$http({method: 'get', url: '/some'});
expect($http.pendingRequests.length).toBe(1);
$httpBackend.flush();
expect($http.pendingRequests.length).toBe(0);
});
it('should remove the request when aborted', function() {
$httpBackend.when('GET').respond(0);
future = $http({method: 'get', url: '/x'});
expect($http.pendingRequests.length).toBe(1);
future.abort();
$httpBackend.flush();
expect($http.pendingRequests.length).toBe(0);
});
it('should update pending requests even when served from cache', function() {
$httpBackend.when('GET').respond(200);
$http({method: 'get', url: '/cached', cache: true});
$http({method: 'get', url: '/cached', cache: true});
expect($http.pendingRequests.length).toBe(2);
$httpBackend.flush();
expect($http.pendingRequests.length).toBe(0);
$http({method: 'get', url: '/cached', cache: true});
expect($http.pendingRequests.length).toBe(1);
$browser.defer.flush();
expect($http.pendingRequests.length).toBe(0);
});
it('should remove the request before firing callbacks', function() {
$httpBackend.when('GET').respond(200);
$http({method: 'get', url: '/url'}).on('xxx', function() {
expect($http.pendingRequests.length).toBe(0);
});
expect($http.pendingRequests.length).toBe(1);
$httpBackend.flush();
});
});
});