feat(http): add basic http service

This implementation only works in JavaScript, while the Observable transpilation
story gets worked out. Right now, the service just makes a simple request,
and returns an Observable of Response.

Additional functionality will be captured in separate issues.

Fixes #2028
This commit is contained in:
Jeff Cross
2015-04-28 23:07:55 -07:00
parent 363b9ba415
commit 21568106b1
35 changed files with 1054 additions and 2 deletions

View File

@ -0,0 +1,78 @@
import {
AsyncTestCompleter,
beforeEach,
ddescribe,
describe,
expect,
iit,
inject,
it,
xit,
SpyObject
} from 'angular2/test_lib';
import {BrowserXHR} from 'angular2/src/http/backends/browser_xhr';
import {XHRConnection, XHRBackend} from 'angular2/src/http/backends/xhr_backend';
import {bind, Injector} from 'angular2/di';
import {Request} from 'angular2/src/http/static_request';
var abortSpy;
var sendSpy;
var openSpy;
var addEventListenerSpy;
class MockBrowserXHR extends SpyObject {
abort: any;
send: any;
open: any;
addEventListener: any;
response: any;
responseText: string;
constructor() {
super();
this.abort = abortSpy = this.spy('abort');
this.send = sendSpy = this.spy('send');
this.open = openSpy = this.spy('open');
this.addEventListener = addEventListenerSpy = this.spy('addEventListener');
}
}
export function main() {
describe('XHRBackend', () => {
var backend;
var sampleRequest;
var constructSpy = new SpyObject();
beforeEach(() => {
var injector =
Injector.resolveAndCreate([bind(BrowserXHR).toValue(MockBrowserXHR), XHRBackend]);
backend = injector.get(XHRBackend);
sampleRequest = new Request('https://google.com');
});
it('should create a connection',
() => { expect(() => backend.createConnection(sampleRequest)).not.toThrow(); });
describe('XHRConnection', () => {
it('should call abort when disposed', () => {
var connection = new XHRConnection(sampleRequest, MockBrowserXHR);
connection.dispose();
expect(abortSpy).toHaveBeenCalled();
});
it('should automatically call open with method and url', () => {
new XHRConnection(sampleRequest, MockBrowserXHR);
expect(openSpy).toHaveBeenCalledWith('GET', sampleRequest.url);
});
it('should automatically call send on the backend with request body', () => {
var body = 'Some body to love';
var request = new Request('https://google.com', {body: body});
var connection = new XHRConnection(request, MockBrowserXHR);
expect(sendSpy).toHaveBeenCalledWith(body);
});
});
});
}

View File

@ -0,0 +1,66 @@
import {Headers} from 'angular2/src/http/headers';
import {Map} from 'angular2/src/facade/collection';
import {
AsyncTestCompleter,
beforeEach,
ddescribe,
describe,
expect,
iit,
inject,
it,
xit
} from 'angular2/test_lib';
export function main() {
describe('Headers', () => {
it('should conform to spec', () => {
// Examples borrowed from https://developer.mozilla.org/en-US/docs/Web/API/Headers/Headers
// Spec at https://fetch.spec.whatwg.org/#dom-headers
var myHeaders = new Headers(); // Currently empty
myHeaders.append('Content-Type', 'image/jpeg');
expect(myHeaders.get('Content-Type')).toBe('image/jpeg');
var httpHeaders = {
'Content-Type': 'image/jpeg',
'Accept-Charset': 'utf-8',
'X-My-Custom-Header': 'Zeke are cool'
};
var myHeaders = new Headers(httpHeaders);
var secondHeadersObj = new Headers(myHeaders);
expect(secondHeadersObj.get('Content-Type')).toBe('image/jpeg');
});
describe('initialization', () => {
it('should create a private headersMap map',
() => { expect(new Headers()._headersMap).toBeAnInstanceOf(Map); });
it('should merge values in provided dictionary', () => {
var headers = new Headers({foo: 'bar'});
expect(headers.get('foo')).toBe('bar');
expect(headers.getAll('foo')).toEqual(['bar']);
});
});
describe('.set()', () => {
it('should clear all values and re-set for the provided key', () => {
var headers = new Headers({foo: 'bar'});
expect(headers.get('foo')).toBe('bar');
expect(headers.getAll('foo')).toEqual(['bar']);
headers.set('foo', 'baz');
expect(headers.get('foo')).toBe('baz');
expect(headers.getAll('foo')).toEqual(['baz']);
});
it('should convert input array to string', () => {
var headers = new Headers();
headers.set('foo', ['bar', 'baz']);
expect(headers.get('foo')).toBe('bar,baz');
expect(headers.getAll('foo')).toEqual(['bar,baz']);
});
});
});
}

View File

@ -0,0 +1,96 @@
import {
AsyncTestCompleter,
beforeEach,
ddescribe,
describe,
expect,
iit,
inject,
it,
xit,
SpyObject
} from 'angular2/test_lib';
import {Http, HttpFactory} from 'angular2/src/http/http';
import {XHRBackend} from 'angular2/src/http/backends/xhr_backend';
import {httpInjectables} from 'angular2/http';
import {Injector, bind} from 'angular2/di';
import {MockBackend} from 'angular2/src/http/backends/mock_backend';
import {Response} from 'angular2/src/http/static_response';
import {ReadyStates} from 'angular2/src/http/enums';
class SpyObserver extends SpyObject {
onNext: Function;
onError: Function;
onCompleted: Function;
constructor() {
super();
this.onNext = this.spy('onNext');
this.onError = this.spy('onError');
this.onCompleted = this.spy('onCompleted');
}
}
export function main() {
describe('http', () => {
var url = 'http://foo.bar';
var http;
var injector;
var backend: MockBackend;
var baseResponse;
var sampleObserver;
beforeEach(() => {
injector = Injector.resolveAndCreate([MockBackend, bind(Http).toFactory(HttpFactory, [MockBackend])]);
http = injector.get(Http);
backend = injector.get(MockBackend);
baseResponse = new Response('base response');
sampleObserver = new SpyObserver();
});
afterEach(() => { /*backend.verifyNoPendingRequests();*/ });
it('should return an Observable', () => {
expect(typeof http(url).subscribe).toBe('function');
backend.resolveAllConnections();
});
it('should perform a get request for given url if only passed a string',
inject([AsyncTestCompleter], (async) => {
var connection;
backend.connections.subscribe((c) => connection = c);
var subscription = http('http://basic.connection')
.subscribe(res => {
expect(res.text()).toBe('base response');
async.done();
});
connection.mockRespond(baseResponse)
}));
it('should perform a get request for given url if passed a ConnectionConfig instance',
inject([AsyncTestCompleter], async => {
var connection;
backend.connections.subscribe((c) => connection = c);
http('http://basic.connection', {method: ReadyStates.UNSENT})
.subscribe(res => {
expect(res.text()).toBe('base response');
async.done();
});
connection.mockRespond(baseResponse)
}));
it('should perform a get request for given url if passed a dictionary',
inject([AsyncTestCompleter], async => {
var connection;
backend.connections.subscribe((c) => connection = c);
http(url, {method: ReadyStates.UNSENT})
.subscribe(res => {
expect(res.text()).toBe('base response');
async.done();
});
connection.mockRespond(baseResponse)
}));
});
}

View File

@ -0,0 +1,35 @@
import {
AsyncTestCompleter,
beforeEach,
ddescribe,
describe,
expect,
iit,
inject,
it,
xit
} from 'angular2/test_lib';
import {URLSearchParams} from 'angular2/src/http/url_search_params';
export function main() {
describe('URLSearchParams', () => {
it('should conform to spec', () => {
var paramsString = "q=URLUtils.searchParams&topic=api";
var searchParams = new URLSearchParams(paramsString);
// Tests borrowed from example at
// https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams
// Compliant with spec described at https://url.spec.whatwg.org/#urlsearchparams
expect(searchParams.has("topic")).toBe(true);
expect(searchParams.has("foo")).toBe(false);
expect(searchParams.get("topic")).toBe("api");
expect(searchParams.getAll("topic")).toEqual(["api"]);
expect(searchParams.get("foo")).toBe(null);
searchParams.append("topic", "webdev");
expect(searchParams.getAll("topic")).toEqual(["api", "webdev"]);
expect(searchParams.toString()).toBe("q=URLUtils.searchParams&topic=api&topic=webdev");
searchParams.delete("topic");
expect(searchParams.toString()).toBe("q=URLUtils.searchParams");
});
});
}