2016-06-23 12:47:54 -04:00
|
|
|
/**
|
|
|
|
* @license
|
|
|
|
* Copyright Google Inc. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
|
|
* found in the LICENSE file at https://angular.io/license
|
|
|
|
*/
|
|
|
|
|
2016-08-02 18:53:34 -04:00
|
|
|
import {Injectable} from '@angular/core';
|
|
|
|
import {AsyncTestCompleter, SpyObject, afterEach, beforeEach, beforeEachProviders, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
|
|
|
|
import {__platform_browser_private__} from '@angular/platform-browser';
|
|
|
|
|
2016-04-28 20:50:03 -04:00
|
|
|
import {BrowserXhr} from '../../src/backends/browser_xhr';
|
2016-08-02 18:53:34 -04:00
|
|
|
import {CookieXSRFStrategy, XHRBackend, XHRConnection} from '../../src/backends/xhr_backend';
|
|
|
|
import {BaseRequestOptions, RequestOptions} from '../../src/base_request_options';
|
|
|
|
import {BaseResponseOptions, ResponseOptions} from '../../src/base_response_options';
|
|
|
|
import {ResponseContentType, ResponseType} from '../../src/enums';
|
|
|
|
import {Map} from '../../src/facade/collection';
|
2016-07-18 17:20:03 -04:00
|
|
|
import {Json} from '../../src/facade/lang';
|
2016-08-02 18:53:34 -04:00
|
|
|
import {Headers} from '../../src/headers';
|
2016-05-27 23:15:40 -04:00
|
|
|
import {XSRFStrategy} from '../../src/interfaces';
|
2016-04-28 20:50:03 -04:00
|
|
|
import {Request} from '../../src/static_request';
|
|
|
|
import {Response} from '../../src/static_response';
|
2016-02-26 06:25:55 -05:00
|
|
|
import {URLSearchParams} from '../../src/url_search_params';
|
2015-04-29 02:07:55 -04:00
|
|
|
|
2016-02-01 20:05:50 -05:00
|
|
|
var abortSpy: any;
|
|
|
|
var sendSpy: any;
|
|
|
|
var openSpy: any;
|
|
|
|
var setRequestHeaderSpy: any;
|
|
|
|
var addEventListenerSpy: any;
|
|
|
|
var existingXHRs: MockBrowserXHR[] = [];
|
2015-07-07 23:03:00 -04:00
|
|
|
var unused: Response;
|
2015-04-29 02:07:55 -04:00
|
|
|
|
2015-06-24 03:27:07 -04:00
|
|
|
class MockBrowserXHR extends BrowserXhr {
|
2015-04-29 02:07:55 -04:00
|
|
|
abort: any;
|
|
|
|
send: any;
|
|
|
|
open: any;
|
|
|
|
response: any;
|
2016-02-24 10:37:18 -05:00
|
|
|
responseType: string;
|
2015-04-29 02:07:55 -04:00
|
|
|
responseText: string;
|
2015-07-01 18:20:09 -04:00
|
|
|
setRequestHeader: any;
|
2015-09-29 14:11:06 -04:00
|
|
|
callbacks = new Map<string, Function>();
|
2015-07-05 04:58:37 -04:00
|
|
|
status: number;
|
2015-11-19 20:51:00 -05:00
|
|
|
responseHeaders: string;
|
2015-11-19 21:47:29 -05:00
|
|
|
responseURL: string;
|
2015-09-13 12:31:56 -04:00
|
|
|
statusText: string;
|
2016-02-24 16:57:35 -05:00
|
|
|
withCredentials: boolean;
|
2015-09-13 12:31:56 -04:00
|
|
|
|
2015-04-29 02:07:55 -04:00
|
|
|
constructor() {
|
|
|
|
super();
|
2015-06-19 15:14:12 -04:00
|
|
|
var spy = new SpyObject();
|
|
|
|
this.abort = abortSpy = spy.spy('abort');
|
|
|
|
this.send = sendSpy = spy.spy('send');
|
|
|
|
this.open = openSpy = spy.spy('open');
|
2015-07-01 18:20:09 -04:00
|
|
|
this.setRequestHeader = setRequestHeaderSpy = spy.spy('setRequestHeader');
|
2016-07-21 16:44:38 -04:00
|
|
|
// If responseType is supported by the browser, then it should be set to an empty string.
|
|
|
|
// (https://www.w3.org/TR/XMLHttpRequest/#the-responsetype-attribute)
|
|
|
|
this.responseType = '';
|
2015-04-29 02:07:55 -04:00
|
|
|
}
|
2015-06-19 15:14:12 -04:00
|
|
|
|
2016-02-01 20:05:50 -05:00
|
|
|
setStatusCode(status: number) { this.status = status; }
|
2015-07-27 20:01:05 -04:00
|
|
|
|
2015-09-13 12:31:56 -04:00
|
|
|
setStatusText(statusText: string) { this.statusText = statusText; }
|
|
|
|
|
2016-02-01 20:05:50 -05:00
|
|
|
setResponse(value: string) { this.response = value; }
|
2015-07-27 20:01:05 -04:00
|
|
|
|
2016-02-01 20:05:50 -05:00
|
|
|
setResponseText(value: string) { this.responseText = value; }
|
2015-07-27 20:01:05 -04:00
|
|
|
|
2016-02-01 20:05:50 -05:00
|
|
|
setResponseURL(value: string) { this.responseURL = value; }
|
2015-11-19 21:47:29 -05:00
|
|
|
|
2016-02-01 20:05:50 -05:00
|
|
|
setResponseHeaders(value: string) { this.responseHeaders = value; }
|
2015-11-19 20:51:00 -05:00
|
|
|
|
|
|
|
getAllResponseHeaders() { return this.responseHeaders || ''; }
|
|
|
|
|
2016-02-01 20:05:50 -05:00
|
|
|
getResponseHeader(key: string) {
|
|
|
|
return Headers.fromResponseHeaderString(this.responseHeaders).get(key);
|
|
|
|
}
|
2015-11-19 21:47:29 -05:00
|
|
|
|
2015-06-24 03:27:07 -04:00
|
|
|
addEventListener(type: string, cb: Function) { this.callbacks.set(type, cb); }
|
|
|
|
|
2015-09-25 18:53:32 -04:00
|
|
|
removeEventListener(type: string, cb: Function) { this.callbacks.delete(type); }
|
|
|
|
|
2015-06-24 03:27:07 -04:00
|
|
|
dispatchEvent(type: string) { this.callbacks.get(type)({}); }
|
|
|
|
|
|
|
|
build() {
|
|
|
|
var xhr = new MockBrowserXHR();
|
|
|
|
existingXHRs.push(xhr);
|
|
|
|
return xhr;
|
|
|
|
}
|
2015-04-29 02:07:55 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
export function main() {
|
|
|
|
describe('XHRBackend', () => {
|
2016-02-01 20:05:50 -05:00
|
|
|
var backend: XHRBackend;
|
|
|
|
var sampleRequest: Request;
|
2015-04-29 02:07:55 -04:00
|
|
|
|
2016-05-27 23:15:40 -04:00
|
|
|
beforeEachProviders(
|
|
|
|
() =>
|
2016-06-08 19:38:52 -04:00
|
|
|
[{provide: ResponseOptions, useClass: BaseResponseOptions},
|
|
|
|
{provide: BrowserXhr, useClass: MockBrowserXHR}, XHRBackend,
|
|
|
|
{provide: XSRFStrategy, useValue: new CookieXSRFStrategy()},
|
2016-05-27 23:15:40 -04:00
|
|
|
]);
|
|
|
|
|
|
|
|
beforeEach(inject([XHRBackend], (be: XHRBackend) => {
|
|
|
|
backend = be;
|
|
|
|
let base = new BaseRequestOptions();
|
2015-06-24 03:27:07 -04:00
|
|
|
sampleRequest = new Request(base.merge(new RequestOptions({url: 'https://google.com'})));
|
2016-05-27 23:15:40 -04:00
|
|
|
}));
|
2015-04-29 02:07:55 -04:00
|
|
|
|
2015-06-24 03:27:07 -04:00
|
|
|
afterEach(() => { existingXHRs = []; });
|
|
|
|
|
2016-05-27 23:15:40 -04:00
|
|
|
describe('creating a connection', () => {
|
|
|
|
@Injectable()
|
|
|
|
class NoopXsrfStrategy implements XSRFStrategy {
|
|
|
|
configureRequest(req: Request) {}
|
|
|
|
}
|
2016-06-02 20:30:40 -04:00
|
|
|
beforeEachProviders(() => [{provide: XSRFStrategy, useClass: NoopXsrfStrategy}]);
|
2016-05-27 23:15:40 -04:00
|
|
|
|
|
|
|
it('succeeds',
|
|
|
|
() => { expect(() => backend.createConnection(sampleRequest)).not.toThrow(); });
|
|
|
|
});
|
2015-04-29 02:07:55 -04:00
|
|
|
|
2016-05-31 19:44:13 -04:00
|
|
|
const getDOM = __platform_browser_private__.getDOM;
|
2016-05-27 23:15:40 -04:00
|
|
|
if (getDOM().supportsCookies()) {
|
|
|
|
describe('XSRF support', () => {
|
|
|
|
it('sets an XSRF header by default', () => {
|
|
|
|
getDOM().setCookie('XSRF-TOKEN', 'magic XSRF value');
|
|
|
|
backend.createConnection(sampleRequest);
|
|
|
|
expect(sampleRequest.headers.get('X-XSRF-TOKEN')).toBe('magic XSRF value');
|
|
|
|
});
|
|
|
|
it('respects existing headers', () => {
|
|
|
|
getDOM().setCookie('XSRF-TOKEN', 'magic XSRF value');
|
|
|
|
sampleRequest.headers.set('X-XSRF-TOKEN', 'already set');
|
|
|
|
backend.createConnection(sampleRequest);
|
|
|
|
expect(sampleRequest.headers.get('X-XSRF-TOKEN')).toBe('already set');
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('configuration', () => {
|
2016-06-08 19:38:52 -04:00
|
|
|
beforeEachProviders(() => [{
|
|
|
|
provide: XSRFStrategy,
|
|
|
|
useValue: new CookieXSRFStrategy('my cookie', 'X-MY-HEADER')
|
|
|
|
}]);
|
2016-05-27 23:15:40 -04:00
|
|
|
|
|
|
|
it('uses the configured names', () => {
|
|
|
|
getDOM().setCookie('my cookie', 'XSRF value');
|
|
|
|
backend.createConnection(sampleRequest);
|
|
|
|
expect(sampleRequest.headers.get('X-MY-HEADER')).toBe('XSRF value');
|
|
|
|
});
|
2016-07-21 20:12:00 -04:00
|
|
|
});
|
2016-05-27 23:15:40 -04:00
|
|
|
});
|
|
|
|
}
|
2015-04-29 02:07:55 -04:00
|
|
|
|
|
|
|
describe('XHRConnection', () => {
|
2015-06-24 03:27:07 -04:00
|
|
|
it('should use the injected BaseResponseOptions to create the response',
|
2016-02-01 20:05:50 -05:00
|
|
|
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
2016-06-08 19:38:52 -04:00
|
|
|
var connection = new XHRConnection(
|
|
|
|
sampleRequest, new MockBrowserXHR(),
|
|
|
|
new ResponseOptions({type: ResponseType.Error}));
|
2016-02-01 20:05:50 -05:00
|
|
|
connection.response.subscribe((res: Response) => {
|
2015-12-03 16:44:14 -05:00
|
|
|
expect(res.type).toBe(ResponseType.Error);
|
2015-06-24 03:27:07 -04:00
|
|
|
async.done();
|
|
|
|
});
|
2015-11-19 20:29:41 -05:00
|
|
|
existingXHRs[0].setStatusCode(200);
|
2015-06-24 03:27:07 -04:00
|
|
|
existingXHRs[0].dispatchEvent('load');
|
|
|
|
}));
|
|
|
|
|
2016-02-01 20:05:50 -05:00
|
|
|
it('should complete a request', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
2016-06-08 19:38:52 -04:00
|
|
|
var connection = new XHRConnection(
|
|
|
|
sampleRequest, new MockBrowserXHR(),
|
|
|
|
new ResponseOptions({type: ResponseType.Error}));
|
|
|
|
connection.response.subscribe(
|
|
|
|
(res: Response) => { expect(res.type).toBe(ResponseType.Error); }, null,
|
|
|
|
() => { async.done(); });
|
2015-11-19 20:29:41 -05:00
|
|
|
existingXHRs[0].setStatusCode(200);
|
2015-07-27 19:59:09 -04:00
|
|
|
existingXHRs[0].dispatchEvent('load');
|
|
|
|
}));
|
|
|
|
|
2015-04-29 02:07:55 -04:00
|
|
|
it('should call abort when disposed', () => {
|
2015-06-19 15:14:12 -04:00
|
|
|
var connection = new XHRConnection(sampleRequest, new MockBrowserXHR());
|
2015-09-25 18:53:32 -04:00
|
|
|
var request = connection.response.subscribe();
|
|
|
|
request.unsubscribe();
|
2015-04-29 02:07:55 -04:00
|
|
|
expect(abortSpy).toHaveBeenCalled();
|
|
|
|
});
|
|
|
|
|
2016-02-01 20:05:50 -05:00
|
|
|
it('should create an error Response on error',
|
|
|
|
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
2016-06-08 19:38:52 -04:00
|
|
|
var connection = new XHRConnection(
|
|
|
|
sampleRequest, new MockBrowserXHR(),
|
|
|
|
new ResponseOptions({type: ResponseType.Error}));
|
2016-02-01 20:05:50 -05:00
|
|
|
connection.response.subscribe(null, (res: Response) => {
|
2015-12-03 16:44:14 -05:00
|
|
|
expect(res.type).toBe(ResponseType.Error);
|
2015-08-08 17:17:43 -04:00
|
|
|
async.done();
|
|
|
|
});
|
|
|
|
existingXHRs[0].dispatchEvent('error');
|
|
|
|
}));
|
2015-04-29 02:07:55 -04:00
|
|
|
|
2016-06-20 18:02:14 -04:00
|
|
|
it('should set the status text and status code on error',
|
|
|
|
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
|
|
var connection = new XHRConnection(
|
|
|
|
sampleRequest, new MockBrowserXHR(),
|
|
|
|
new ResponseOptions({type: ResponseType.Error}));
|
|
|
|
connection.response.subscribe(null, (res: Response) => {
|
|
|
|
expect(res.type).toBe(ResponseType.Error);
|
|
|
|
expect(res.status).toEqual(0);
|
|
|
|
expect(res.statusText).toEqual('');
|
|
|
|
async.done();
|
|
|
|
});
|
|
|
|
const xhr = existingXHRs[0];
|
|
|
|
// status=0 with a text='' is common for CORS errors
|
|
|
|
xhr.setStatusCode(0);
|
|
|
|
xhr.setStatusText('');
|
|
|
|
xhr.dispatchEvent('error');
|
|
|
|
}));
|
|
|
|
|
2015-09-25 18:53:32 -04:00
|
|
|
it('should call open with method and url when subscribed to', () => {
|
|
|
|
var connection = new XHRConnection(sampleRequest, new MockBrowserXHR());
|
|
|
|
expect(openSpy).not.toHaveBeenCalled();
|
|
|
|
connection.response.subscribe();
|
2015-04-29 02:07:55 -04:00
|
|
|
expect(openSpy).toHaveBeenCalledWith('GET', sampleRequest.url);
|
|
|
|
});
|
|
|
|
|
2015-09-25 18:53:32 -04:00
|
|
|
it('should call send on the backend with request body when subscribed to', () => {
|
2015-04-29 02:07:55 -04:00
|
|
|
var body = 'Some body to love';
|
2015-06-24 03:27:07 -04:00
|
|
|
var base = new BaseRequestOptions();
|
2015-09-25 18:53:32 -04:00
|
|
|
var connection = new XHRConnection(
|
|
|
|
new Request(base.merge(new RequestOptions({body: body}))), new MockBrowserXHR());
|
|
|
|
expect(sendSpy).not.toHaveBeenCalled();
|
|
|
|
connection.response.subscribe();
|
2015-04-29 02:07:55 -04:00
|
|
|
expect(sendSpy).toHaveBeenCalledWith(body);
|
|
|
|
});
|
2015-07-01 18:20:09 -04:00
|
|
|
|
|
|
|
it('should attach headers to the request', () => {
|
2015-10-07 17:56:18 -04:00
|
|
|
var headers =
|
|
|
|
new Headers({'Content-Type': 'text/xml', 'Breaking-Bad': '<3', 'X-Multi': ['a', 'b']});
|
2015-07-01 18:20:09 -04:00
|
|
|
|
|
|
|
var base = new BaseRequestOptions();
|
2015-09-25 18:53:32 -04:00
|
|
|
var connection = new XHRConnection(
|
|
|
|
new Request(base.merge(new RequestOptions({headers: headers}))), new MockBrowserXHR());
|
|
|
|
connection.response.subscribe();
|
2016-07-26 00:30:43 -04:00
|
|
|
expect(setRequestHeaderSpy).toHaveBeenCalledWith('content-type', 'text/xml');
|
|
|
|
expect(setRequestHeaderSpy).toHaveBeenCalledWith('breaking-bad', '<3');
|
|
|
|
expect(setRequestHeaderSpy).toHaveBeenCalledWith('x-multi', 'a,b');
|
2015-07-01 18:20:09 -04:00
|
|
|
});
|
2015-07-05 04:58:37 -04:00
|
|
|
|
2016-06-10 11:18:49 -04:00
|
|
|
it('should skip content type detection if custom content type header is set', () => {
|
|
|
|
let headers = new Headers({'Content-Type': 'text/plain'});
|
|
|
|
let body = {test: 'val'};
|
|
|
|
let base = new BaseRequestOptions();
|
|
|
|
let connection = new XHRConnection(
|
|
|
|
new Request(base.merge(new RequestOptions({body: body, headers: headers}))),
|
|
|
|
new MockBrowserXHR());
|
|
|
|
connection.response.subscribe();
|
2016-07-26 00:30:43 -04:00
|
|
|
expect(setRequestHeaderSpy).toHaveBeenCalledWith('content-type', 'text/plain');
|
|
|
|
expect(setRequestHeaderSpy).not.toHaveBeenCalledWith('content-type', 'application/json');
|
2016-06-10 11:18:49 -04:00
|
|
|
});
|
|
|
|
|
2016-02-26 06:25:55 -05:00
|
|
|
it('should use object body and detect content type header to the request', () => {
|
|
|
|
var body = {test: 'val'};
|
|
|
|
var base = new BaseRequestOptions();
|
|
|
|
var connection = new XHRConnection(
|
|
|
|
new Request(base.merge(new RequestOptions({body: body}))), new MockBrowserXHR());
|
|
|
|
connection.response.subscribe();
|
2016-07-18 17:20:03 -04:00
|
|
|
expect(sendSpy).toHaveBeenCalledWith(Json.stringify(body));
|
2016-07-26 00:30:43 -04:00
|
|
|
expect(setRequestHeaderSpy).toHaveBeenCalledWith('content-type', 'application/json');
|
2016-02-26 06:25:55 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should use number body and detect content type header to the request', () => {
|
|
|
|
var body = 23;
|
|
|
|
var base = new BaseRequestOptions();
|
|
|
|
var connection = new XHRConnection(
|
|
|
|
new Request(base.merge(new RequestOptions({body: body}))), new MockBrowserXHR());
|
|
|
|
connection.response.subscribe();
|
|
|
|
expect(sendSpy).toHaveBeenCalledWith('23');
|
2016-07-26 00:30:43 -04:00
|
|
|
expect(setRequestHeaderSpy).toHaveBeenCalledWith('content-type', 'text/plain');
|
2016-02-26 06:25:55 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should use string body and detect content type header to the request', () => {
|
|
|
|
var body = 'some string';
|
|
|
|
var base = new BaseRequestOptions();
|
|
|
|
var connection = new XHRConnection(
|
|
|
|
new Request(base.merge(new RequestOptions({body: body}))), new MockBrowserXHR());
|
|
|
|
connection.response.subscribe();
|
|
|
|
expect(sendSpy).toHaveBeenCalledWith(body);
|
2016-07-26 00:30:43 -04:00
|
|
|
expect(setRequestHeaderSpy).toHaveBeenCalledWith('content-type', 'text/plain');
|
2016-02-26 06:25:55 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should use URLSearchParams body and detect content type header to the request', () => {
|
|
|
|
var body = new URLSearchParams();
|
|
|
|
body.set('test1', 'val1');
|
|
|
|
body.set('test2', 'val2');
|
|
|
|
var base = new BaseRequestOptions();
|
|
|
|
var connection = new XHRConnection(
|
|
|
|
new Request(base.merge(new RequestOptions({body: body}))), new MockBrowserXHR());
|
|
|
|
connection.response.subscribe();
|
|
|
|
expect(sendSpy).toHaveBeenCalledWith('test1=val1&test2=val2');
|
|
|
|
expect(setRequestHeaderSpy)
|
2016-06-08 19:38:52 -04:00
|
|
|
.toHaveBeenCalledWith(
|
2016-07-26 00:30:43 -04:00
|
|
|
'content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
|
2016-02-26 06:25:55 -05:00
|
|
|
});
|
|
|
|
|
2016-06-08 18:45:15 -04:00
|
|
|
if ((global as any /** TODO #9100 */)['Blob']) {
|
2016-07-29 08:37:37 -04:00
|
|
|
// `new Blob(...)` throws an 'Illegal constructor' exception in Android browser <= 4.3,
|
|
|
|
// but a BlobBuilder can be used instead
|
|
|
|
const createBlob = (data: Array<string>, datatype: string) => {
|
|
|
|
let newBlob: Blob;
|
|
|
|
try {
|
|
|
|
newBlob = new Blob(data || [], datatype ? {type: datatype} : {});
|
|
|
|
} catch (e) {
|
|
|
|
const BlobBuilder = (<any>global).BlobBuilder || (<any>global).WebKitBlobBuilder ||
|
|
|
|
(<any>global).MozBlobBuilder || (<any>global).MSBlobBuilder;
|
|
|
|
const builder = new BlobBuilder();
|
|
|
|
builder.append(data);
|
|
|
|
newBlob = builder.getBlob(datatype);
|
|
|
|
}
|
|
|
|
return newBlob;
|
|
|
|
};
|
|
|
|
|
2016-02-26 06:25:55 -05:00
|
|
|
it('should use FormData body and detect content type header to the request', () => {
|
|
|
|
var body = new FormData();
|
|
|
|
body.append('test1', 'val1');
|
|
|
|
body.append('test2', 123456);
|
2016-07-29 08:37:37 -04:00
|
|
|
var blob = createBlob(['body { color: red; }'], 'text/css');
|
2016-06-08 19:38:52 -04:00
|
|
|
body.append('userfile', blob);
|
2016-02-26 06:25:55 -05:00
|
|
|
var base = new BaseRequestOptions();
|
|
|
|
var connection = new XHRConnection(
|
|
|
|
new Request(base.merge(new RequestOptions({body: body}))), new MockBrowserXHR());
|
|
|
|
connection.response.subscribe();
|
|
|
|
expect(sendSpy).toHaveBeenCalledWith(body);
|
|
|
|
expect(setRequestHeaderSpy).not.toHaveBeenCalledWith();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should use blob body and detect content type header to the request', () => {
|
2016-07-29 08:37:37 -04:00
|
|
|
var body = createBlob(['body { color: red; }'], 'text/css');
|
2016-02-26 06:25:55 -05:00
|
|
|
var base = new BaseRequestOptions();
|
|
|
|
var connection = new XHRConnection(
|
|
|
|
new Request(base.merge(new RequestOptions({body: body}))), new MockBrowserXHR());
|
|
|
|
connection.response.subscribe();
|
|
|
|
expect(sendSpy).toHaveBeenCalledWith(body);
|
2016-07-26 00:30:43 -04:00
|
|
|
expect(setRequestHeaderSpy).toHaveBeenCalledWith('content-type', 'text/css');
|
2016-02-26 06:25:55 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should use blob body without type to the request', () => {
|
2016-07-29 08:37:37 -04:00
|
|
|
var body = createBlob(['body { color: red; }'], null);
|
2016-02-26 06:25:55 -05:00
|
|
|
var base = new BaseRequestOptions();
|
|
|
|
var connection = new XHRConnection(
|
|
|
|
new Request(base.merge(new RequestOptions({body: body}))), new MockBrowserXHR());
|
|
|
|
connection.response.subscribe();
|
|
|
|
expect(sendSpy).toHaveBeenCalledWith(body);
|
|
|
|
expect(setRequestHeaderSpy).not.toHaveBeenCalledWith();
|
|
|
|
});
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
it('should use blob body without type with custom content type header to the request',
|
|
|
|
() => {
|
|
|
|
var headers = new Headers({'Content-Type': 'text/css'});
|
2016-07-29 08:37:37 -04:00
|
|
|
var body = createBlob(['body { color: red; }'], null);
|
2016-06-08 19:38:52 -04:00
|
|
|
var base = new BaseRequestOptions();
|
|
|
|
var connection = new XHRConnection(
|
|
|
|
new Request(base.merge(new RequestOptions({body: body, headers: headers}))),
|
|
|
|
new MockBrowserXHR());
|
|
|
|
connection.response.subscribe();
|
|
|
|
expect(sendSpy).toHaveBeenCalledWith(body);
|
2016-07-26 00:30:43 -04:00
|
|
|
expect(setRequestHeaderSpy).toHaveBeenCalledWith('content-type', 'text/css');
|
2016-06-08 19:38:52 -04:00
|
|
|
});
|
2016-02-26 06:25:55 -05:00
|
|
|
|
|
|
|
it('should use array buffer body to the request', () => {
|
|
|
|
var body = new ArrayBuffer(512);
|
|
|
|
var longInt8View = new Uint8Array(body);
|
|
|
|
for (var i = 0; i < longInt8View.length; i++) {
|
|
|
|
longInt8View[i] = i % 255;
|
|
|
|
}
|
|
|
|
var base = new BaseRequestOptions();
|
|
|
|
var connection = new XHRConnection(
|
2016-06-08 19:38:52 -04:00
|
|
|
new Request(base.merge(new RequestOptions({body: body}))), new MockBrowserXHR());
|
2016-02-26 06:25:55 -05:00
|
|
|
connection.response.subscribe();
|
|
|
|
expect(sendSpy).toHaveBeenCalledWith(body);
|
|
|
|
expect(setRequestHeaderSpy).not.toHaveBeenCalledWith();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should use array buffer body without type with custom content type header to the request',
|
2016-06-08 19:38:52 -04:00
|
|
|
() => {
|
|
|
|
var headers = new Headers({'Content-Type': 'text/css'});
|
|
|
|
var body = new ArrayBuffer(512);
|
|
|
|
var longInt8View = new Uint8Array(body);
|
|
|
|
for (var i = 0; i < longInt8View.length; i++) {
|
|
|
|
longInt8View[i] = i % 255;
|
|
|
|
}
|
|
|
|
var base = new BaseRequestOptions();
|
|
|
|
var connection = new XHRConnection(
|
|
|
|
new Request(base.merge(new RequestOptions({body: body, headers: headers}))),
|
|
|
|
new MockBrowserXHR());
|
|
|
|
connection.response.subscribe();
|
|
|
|
expect(sendSpy).toHaveBeenCalledWith(body);
|
2016-07-26 00:30:43 -04:00
|
|
|
expect(setRequestHeaderSpy).toHaveBeenCalledWith('content-type', 'text/css');
|
2016-06-08 19:38:52 -04:00
|
|
|
});
|
2016-02-26 06:25:55 -05:00
|
|
|
}
|
|
|
|
|
2016-02-01 20:05:50 -05:00
|
|
|
it('should return the correct status code',
|
|
|
|
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
2015-07-05 04:58:37 -04:00
|
|
|
var statusCode = 418;
|
2016-06-08 19:38:52 -04:00
|
|
|
var connection = new XHRConnection(
|
|
|
|
sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
|
2015-07-05 04:58:37 -04:00
|
|
|
|
2015-11-19 20:29:41 -05:00
|
|
|
connection.response.subscribe(
|
2016-02-01 20:05:50 -05:00
|
|
|
(res: Response) => {
|
2015-11-19 20:29:41 -05:00
|
|
|
|
|
|
|
},
|
|
|
|
errRes => {
|
|
|
|
expect(errRes.status).toBe(statusCode);
|
|
|
|
async.done();
|
|
|
|
});
|
|
|
|
|
|
|
|
existingXHRs[0].setStatusCode(statusCode);
|
|
|
|
existingXHRs[0].dispatchEvent('load');
|
|
|
|
}));
|
|
|
|
|
2016-02-01 20:05:50 -05:00
|
|
|
it('should call next and complete on 200 codes',
|
|
|
|
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
2015-11-19 20:29:41 -05:00
|
|
|
var nextCalled = false;
|
|
|
|
var errorCalled = false;
|
|
|
|
var statusCode = 200;
|
2016-06-08 19:38:52 -04:00
|
|
|
var connection = new XHRConnection(
|
|
|
|
sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
|
2015-11-19 20:29:41 -05:00
|
|
|
|
|
|
|
connection.response.subscribe(
|
2016-02-01 20:05:50 -05:00
|
|
|
(res: Response) => {
|
2015-11-19 20:29:41 -05:00
|
|
|
nextCalled = true;
|
|
|
|
expect(res.status).toBe(statusCode);
|
|
|
|
},
|
2016-06-08 19:38:52 -04:00
|
|
|
errRes => { errorCalled = true; },
|
|
|
|
() => {
|
2015-11-19 20:29:41 -05:00
|
|
|
expect(nextCalled).toBe(true);
|
|
|
|
expect(errorCalled).toBe(false);
|
|
|
|
async.done();
|
|
|
|
});
|
2015-07-05 04:58:37 -04:00
|
|
|
|
|
|
|
existingXHRs[0].setStatusCode(statusCode);
|
|
|
|
existingXHRs[0].dispatchEvent('load');
|
|
|
|
}));
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
it('should set ok to true on 200 return',
|
|
|
|
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
|
|
var statusCode = 200;
|
|
|
|
var connection = new XHRConnection(
|
|
|
|
sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
|
2016-01-15 05:49:24 -05:00
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
connection.response.subscribe(res => {
|
|
|
|
expect(res.ok).toBe(true);
|
|
|
|
async.done();
|
|
|
|
});
|
2016-01-15 05:49:24 -05:00
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
existingXHRs[0].setStatusCode(statusCode);
|
|
|
|
existingXHRs[0].dispatchEvent('load');
|
|
|
|
}));
|
2016-01-15 05:49:24 -05:00
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
it('should set ok to false on 300 return',
|
|
|
|
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
|
|
var statusCode = 300;
|
|
|
|
var connection = new XHRConnection(
|
|
|
|
sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
|
2016-01-15 05:49:24 -05:00
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
connection.response.subscribe(
|
|
|
|
res => { throw 'should not be called'; },
|
|
|
|
errRes => {
|
|
|
|
expect(errRes.ok).toBe(false);
|
|
|
|
async.done();
|
|
|
|
});
|
2016-01-15 05:49:24 -05:00
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
existingXHRs[0].setStatusCode(statusCode);
|
|
|
|
existingXHRs[0].dispatchEvent('load');
|
|
|
|
}));
|
2016-01-15 05:49:24 -05:00
|
|
|
|
2016-02-01 20:05:50 -05:00
|
|
|
it('should call error and not complete on 300+ codes',
|
|
|
|
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
2015-11-19 20:29:41 -05:00
|
|
|
var nextCalled = false;
|
|
|
|
var errorCalled = false;
|
|
|
|
var statusCode = 301;
|
2016-06-08 19:38:52 -04:00
|
|
|
var connection = new XHRConnection(
|
|
|
|
sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
|
2015-11-19 20:29:41 -05:00
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
connection.response.subscribe(
|
|
|
|
(res: Response) => { nextCalled = true; },
|
|
|
|
errRes => {
|
|
|
|
expect(errRes.status).toBe(statusCode);
|
|
|
|
expect(nextCalled).toBe(false);
|
|
|
|
async.done();
|
|
|
|
},
|
|
|
|
() => { throw 'should not be called'; });
|
2015-11-19 20:29:41 -05:00
|
|
|
|
|
|
|
existingXHRs[0].setStatusCode(statusCode);
|
|
|
|
existingXHRs[0].dispatchEvent('load');
|
|
|
|
}));
|
2016-02-01 20:05:50 -05:00
|
|
|
it('should normalize IE\'s 1223 status code into 204',
|
|
|
|
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
2015-07-05 04:58:37 -04:00
|
|
|
var statusCode = 1223;
|
|
|
|
var normalizedCode = 204;
|
2016-06-08 19:38:52 -04:00
|
|
|
var connection = new XHRConnection(
|
|
|
|
sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
|
2015-07-05 04:58:37 -04:00
|
|
|
|
2016-02-01 20:05:50 -05:00
|
|
|
connection.response.subscribe((res: Response) => {
|
2015-07-05 04:58:37 -04:00
|
|
|
expect(res.status).toBe(normalizedCode);
|
|
|
|
async.done();
|
|
|
|
});
|
|
|
|
|
|
|
|
existingXHRs[0].setStatusCode(statusCode);
|
|
|
|
existingXHRs[0].dispatchEvent('load');
|
|
|
|
}));
|
2015-07-27 20:01:05 -04:00
|
|
|
|
2016-02-01 20:05:50 -05:00
|
|
|
it('should normalize responseText and response',
|
|
|
|
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
2015-07-27 20:01:05 -04:00
|
|
|
var responseBody = 'Doge';
|
|
|
|
|
|
|
|
var connection1 =
|
|
|
|
new XHRConnection(sampleRequest, new MockBrowserXHR(), new ResponseOptions());
|
|
|
|
|
|
|
|
var connection2 =
|
|
|
|
new XHRConnection(sampleRequest, new MockBrowserXHR(), new ResponseOptions());
|
|
|
|
|
2016-02-01 20:05:50 -05:00
|
|
|
connection1.response.subscribe((res: Response) => {
|
2015-07-27 20:01:05 -04:00
|
|
|
expect(res.text()).toBe(responseBody);
|
|
|
|
|
2015-09-25 18:53:32 -04:00
|
|
|
connection2.response.subscribe(ress => {
|
2015-07-27 20:01:05 -04:00
|
|
|
expect(ress.text()).toBe(responseBody);
|
|
|
|
async.done();
|
|
|
|
});
|
2015-11-19 20:29:41 -05:00
|
|
|
existingXHRs[1].setStatusCode(200);
|
2015-09-25 18:53:32 -04:00
|
|
|
existingXHRs[1].setResponse(responseBody);
|
2015-07-27 20:01:05 -04:00
|
|
|
existingXHRs[1].dispatchEvent('load');
|
|
|
|
});
|
2015-11-19 20:29:41 -05:00
|
|
|
existingXHRs[0].setStatusCode(200);
|
2015-07-27 20:01:05 -04:00
|
|
|
existingXHRs[0].setResponseText(responseBody);
|
|
|
|
existingXHRs[0].dispatchEvent('load');
|
|
|
|
}));
|
|
|
|
|
2016-06-08 23:50:58 -04:00
|
|
|
it('should strip XSSI prefixes', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
|
|
var conn = new XHRConnection(sampleRequest, new MockBrowserXHR(), new ResponseOptions());
|
|
|
|
conn.response.subscribe((res: Response) => {
|
|
|
|
expect(res.text()).toBe('{json: "object"}');
|
|
|
|
async.done();
|
|
|
|
});
|
|
|
|
existingXHRs[0].setStatusCode(200);
|
|
|
|
existingXHRs[0].setResponseText(')]}\'\n{json: "object"}');
|
|
|
|
existingXHRs[0].dispatchEvent('load');
|
|
|
|
}));
|
|
|
|
|
2016-05-05 17:25:44 -04:00
|
|
|
it('should strip XSSI prefixes', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
|
|
var conn = new XHRConnection(sampleRequest, new MockBrowserXHR(), new ResponseOptions());
|
|
|
|
conn.response.subscribe((res: Response) => {
|
|
|
|
expect(res.text()).toBe('{json: "object"}');
|
|
|
|
async.done();
|
|
|
|
});
|
|
|
|
existingXHRs[0].setStatusCode(200);
|
|
|
|
existingXHRs[0].setResponseText(')]}\',\n{json: "object"}');
|
|
|
|
existingXHRs[0].dispatchEvent('load');
|
|
|
|
}));
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
it('should strip XSSI prefix from errors',
|
|
|
|
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
|
|
var conn = new XHRConnection(sampleRequest, new MockBrowserXHR(), new ResponseOptions());
|
2016-05-05 17:25:44 -04:00
|
|
|
conn.response.subscribe(null, (res: Response) => {
|
|
|
|
expect(res.text()).toBe('{json: "object"}');
|
|
|
|
async.done();
|
|
|
|
});
|
|
|
|
existingXHRs[0].setStatusCode(404);
|
2016-06-08 23:50:58 -04:00
|
|
|
existingXHRs[0].setResponseText(')]}\'\n{json: "object"}');
|
2016-05-05 17:25:44 -04:00
|
|
|
existingXHRs[0].dispatchEvent('load');
|
|
|
|
}));
|
|
|
|
|
2015-11-19 20:51:00 -05:00
|
|
|
it('should parse response headers and add them to the response',
|
2016-02-01 20:05:50 -05:00
|
|
|
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
2015-11-19 20:51:00 -05:00
|
|
|
var statusCode = 200;
|
2016-06-08 19:38:52 -04:00
|
|
|
var connection = new XHRConnection(
|
|
|
|
sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
|
2015-11-19 20:51:00 -05:00
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
let responseHeaderString = `Date: Fri, 20 Nov 2015 01:45:26 GMT
|
2016-07-29 01:19:49 -04:00
|
|
|
Content-Type: application/json; charset=utf-8
|
|
|
|
Transfer-Encoding: chunked
|
|
|
|
Connection: keep-alive`;
|
2015-11-19 20:51:00 -05:00
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
connection.response.subscribe((res: Response) => {
|
|
|
|
expect(res.headers.get('Date')).toEqual('Fri, 20 Nov 2015 01:45:26 GMT');
|
|
|
|
expect(res.headers.get('Content-Type')).toEqual('application/json; charset=utf-8');
|
|
|
|
expect(res.headers.get('Transfer-Encoding')).toEqual('chunked');
|
|
|
|
expect(res.headers.get('Connection')).toEqual('keep-alive');
|
|
|
|
async.done();
|
|
|
|
});
|
2015-11-19 20:51:00 -05:00
|
|
|
|
|
|
|
existingXHRs[0].setResponseHeaders(responseHeaderString);
|
|
|
|
existingXHRs[0].setStatusCode(statusCode);
|
|
|
|
existingXHRs[0].dispatchEvent('load');
|
|
|
|
}));
|
2015-11-19 21:47:29 -05:00
|
|
|
|
2016-02-01 20:05:50 -05:00
|
|
|
it('should add the responseURL to the response',
|
|
|
|
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
2015-11-19 21:47:29 -05:00
|
|
|
var statusCode = 200;
|
2016-06-08 19:38:52 -04:00
|
|
|
var connection = new XHRConnection(
|
|
|
|
sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
|
2015-11-19 21:47:29 -05:00
|
|
|
|
2016-02-01 20:05:50 -05:00
|
|
|
connection.response.subscribe((res: Response) => {
|
2015-11-19 21:47:29 -05:00
|
|
|
expect(res.url).toEqual('http://google.com');
|
|
|
|
async.done();
|
|
|
|
});
|
|
|
|
|
|
|
|
existingXHRs[0].setResponseURL('http://google.com');
|
|
|
|
existingXHRs[0].setStatusCode(statusCode);
|
|
|
|
existingXHRs[0].dispatchEvent('load');
|
|
|
|
}));
|
|
|
|
|
|
|
|
it('should add use the X-Request-URL in CORS situations',
|
2016-02-01 20:05:50 -05:00
|
|
|
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
2015-11-19 21:47:29 -05:00
|
|
|
var statusCode = 200;
|
2016-06-08 19:38:52 -04:00
|
|
|
var connection = new XHRConnection(
|
|
|
|
sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
|
2015-11-19 21:47:29 -05:00
|
|
|
var responseHeaders = `X-Request-URL: http://somedomain.com
|
2016-07-21 20:12:00 -04:00
|
|
|
Foo: Bar`;
|
2015-11-19 21:47:29 -05:00
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
connection.response.subscribe((res: Response) => {
|
|
|
|
expect(res.url).toEqual('http://somedomain.com');
|
|
|
|
async.done();
|
|
|
|
});
|
2015-11-19 21:47:29 -05:00
|
|
|
|
|
|
|
existingXHRs[0].setResponseHeaders(responseHeaders);
|
|
|
|
existingXHRs[0].setStatusCode(statusCode);
|
|
|
|
existingXHRs[0].dispatchEvent('load');
|
|
|
|
}));
|
2015-09-13 12:31:56 -04:00
|
|
|
|
|
|
|
it('should set the status text property from the XMLHttpRequest instance if present',
|
|
|
|
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
|
|
var statusText = 'test';
|
|
|
|
var connection = new XHRConnection(sampleRequest, new MockBrowserXHR());
|
|
|
|
|
|
|
|
connection.response.subscribe((res: Response) => {
|
|
|
|
expect(res.statusText).toBe(statusText);
|
|
|
|
async.done();
|
|
|
|
});
|
|
|
|
|
|
|
|
existingXHRs[0].setStatusText(statusText);
|
|
|
|
existingXHRs[0].setStatusCode(200);
|
|
|
|
existingXHRs[0].dispatchEvent('load');
|
|
|
|
}));
|
|
|
|
|
|
|
|
it('should set status text to "OK" if it is not present in XMLHttpRequest instance',
|
|
|
|
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
|
|
var connection = new XHRConnection(sampleRequest, new MockBrowserXHR());
|
|
|
|
|
|
|
|
connection.response.subscribe((res: Response) => {
|
|
|
|
expect(res.statusText).toBe('OK');
|
|
|
|
async.done();
|
|
|
|
});
|
|
|
|
|
|
|
|
existingXHRs[0].setStatusCode(200);
|
|
|
|
existingXHRs[0].dispatchEvent('load');
|
|
|
|
}));
|
|
|
|
|
2016-02-24 16:57:35 -05:00
|
|
|
it('should set withCredentials to true when defined in request options for CORS situations',
|
|
|
|
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
|
|
var statusCode = 200;
|
|
|
|
sampleRequest.withCredentials = true;
|
|
|
|
var mockXhr = new MockBrowserXHR();
|
|
|
|
var connection =
|
|
|
|
new XHRConnection(sampleRequest, mockXhr, new ResponseOptions({status: statusCode}));
|
|
|
|
var responseHeaders = `X-Request-URL: http://somedomain.com
|
2016-07-21 20:12:00 -04:00
|
|
|
Foo: Bar`;
|
2016-02-24 16:57:35 -05:00
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
connection.response.subscribe((res: Response) => {
|
|
|
|
expect(res.url).toEqual('http://somedomain.com');
|
|
|
|
expect(existingXHRs[0].withCredentials).toBeTruthy();
|
|
|
|
async.done();
|
|
|
|
});
|
2016-02-24 16:57:35 -05:00
|
|
|
|
|
|
|
existingXHRs[0].setResponseHeaders(responseHeaders);
|
|
|
|
existingXHRs[0].setStatusCode(statusCode);
|
|
|
|
existingXHRs[0].dispatchEvent('load');
|
|
|
|
}));
|
2016-07-21 16:44:38 -04:00
|
|
|
|
|
|
|
it('should set the responseType attribute to blob when the corresponding response content type is present',
|
|
|
|
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
|
|
|
var statusCode = 200;
|
|
|
|
var base = new BaseRequestOptions();
|
|
|
|
var connection = new XHRConnection(
|
|
|
|
new Request(
|
|
|
|
base.merge(new RequestOptions({responseType: ResponseContentType.Blob}))),
|
|
|
|
new MockBrowserXHR());
|
|
|
|
|
|
|
|
connection.response.subscribe((res: Response) => {
|
|
|
|
expect(existingXHRs[0].responseType).toBe('blob');
|
|
|
|
async.done();
|
|
|
|
});
|
|
|
|
|
|
|
|
existingXHRs[0].setStatusCode(statusCode);
|
|
|
|
existingXHRs[0].dispatchEvent('load');
|
|
|
|
}));
|
2015-04-29 02:07:55 -04:00
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|