765 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			765 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| /**
 | |
|  * @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
 | |
|  */
 | |
| 
 | |
| import {Injectable} from '@angular/core';
 | |
| import {AsyncTestCompleter, SpyObject, afterEach, beforeEach, beforeEachProviders, describe, expect, inject, it} from '@angular/core/testing/src/testing_internal';
 | |
| import {ɵgetDOM as getDOM} from '@angular/platform-browser';
 | |
| import {BrowserXhr} from '../../src/backends/browser_xhr';
 | |
| 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 {Headers} from '../../src/headers';
 | |
| import {XSRFStrategy} from '../../src/interfaces';
 | |
| import {Request} from '../../src/static_request';
 | |
| import {Response} from '../../src/static_response';
 | |
| import {URLSearchParams} from '../../src/url_search_params';
 | |
| 
 | |
| let abortSpy: any;
 | |
| let sendSpy: any;
 | |
| let openSpy: any;
 | |
| let setRequestHeaderSpy: any;
 | |
| let existingXHRs: MockBrowserXHR[] = [];
 | |
| 
 | |
| class MockBrowserXHR extends BrowserXhr {
 | |
|   abort: any;
 | |
|   send: any;
 | |
|   open: any;
 | |
|   response: any;
 | |
|   responseType: string;
 | |
|   responseText: string;
 | |
|   setRequestHeader: any;
 | |
|   callbacks = new Map<string, Function>();
 | |
|   status: number;
 | |
|   responseHeaders: string;
 | |
|   responseURL: string;
 | |
|   statusText: string;
 | |
|   withCredentials: boolean;
 | |
| 
 | |
|   constructor() {
 | |
|     super();
 | |
|     const spy = new SpyObject();
 | |
|     this.abort = abortSpy = spy.spy('abort');
 | |
|     this.send = sendSpy = spy.spy('send');
 | |
|     this.open = openSpy = spy.spy('open');
 | |
|     this.setRequestHeader = setRequestHeaderSpy = spy.spy('setRequestHeader');
 | |
|     // 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 = '';
 | |
|   }
 | |
| 
 | |
|   setStatusCode(status: number) { this.status = status; }
 | |
| 
 | |
|   setStatusText(statusText: string) { this.statusText = statusText; }
 | |
| 
 | |
|   setResponse(value: string) { this.response = value; }
 | |
| 
 | |
|   setResponseText(value: string) { this.responseText = value; }
 | |
| 
 | |
|   setResponseURL(value: string) { this.responseURL = value; }
 | |
| 
 | |
|   setResponseHeaders(value: string) { this.responseHeaders = value; }
 | |
| 
 | |
|   getAllResponseHeaders() { return this.responseHeaders || ''; }
 | |
| 
 | |
|   getResponseHeader(key: string) {
 | |
|     return Headers.fromResponseHeaderString(this.responseHeaders).get(key);
 | |
|   }
 | |
| 
 | |
|   addEventListener(type: string, cb: Function) { this.callbacks.set(type, cb); }
 | |
| 
 | |
|   removeEventListener(type: string, cb: Function) { this.callbacks.delete(type); }
 | |
| 
 | |
|   dispatchEvent(type: string) { this.callbacks.get(type) !({}); }
 | |
| 
 | |
|   build() {
 | |
|     const xhr = new MockBrowserXHR();
 | |
|     existingXHRs.push(xhr);
 | |
|     return xhr;
 | |
|   }
 | |
| }
 | |
| 
 | |
| export function main() {
 | |
|   describe('XHRBackend', () => {
 | |
|     let backend: XHRBackend;
 | |
|     let sampleRequest: Request;
 | |
| 
 | |
|     beforeEachProviders(
 | |
|         () =>
 | |
|             [{provide: ResponseOptions, useClass: BaseResponseOptions},
 | |
|              {provide: BrowserXhr, useClass: MockBrowserXHR}, XHRBackend,
 | |
|              {provide: XSRFStrategy, useValue: new CookieXSRFStrategy()},
 | |
|     ]);
 | |
| 
 | |
|     beforeEach(inject([XHRBackend], (be: XHRBackend) => {
 | |
|       backend = be;
 | |
|       const base = new BaseRequestOptions();
 | |
|       sampleRequest =
 | |
|           new Request(base.merge(new RequestOptions({url: 'https://google.com'})) as any);
 | |
|     }));
 | |
| 
 | |
|     afterEach(() => { existingXHRs = []; });
 | |
| 
 | |
|     describe('creating a connection', () => {
 | |
|       @Injectable()
 | |
|       class NoopXsrfStrategy implements XSRFStrategy {
 | |
|         configureRequest(req: Request) {}
 | |
|       }
 | |
|       beforeEachProviders(() => [{provide: XSRFStrategy, useClass: NoopXsrfStrategy}]);
 | |
| 
 | |
|       it('succeeds',
 | |
|          () => { expect(() => backend.createConnection(sampleRequest)).not.toThrow(); });
 | |
|     });
 | |
| 
 | |
|     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('should allow overwriting of 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('magic XSRF value');
 | |
|         });
 | |
| 
 | |
|         describe('configuration', () => {
 | |
|           beforeEachProviders(() => [{
 | |
|                                 provide: XSRFStrategy,
 | |
|                                 useValue: new CookieXSRFStrategy('my cookie', 'X-MY-HEADER')
 | |
|                               }]);
 | |
| 
 | |
|           it('uses the configured names', () => {
 | |
|             getDOM().setCookie('my cookie', 'XSRF value');
 | |
|             backend.createConnection(sampleRequest);
 | |
|             expect(sampleRequest.headers.get('X-MY-HEADER')).toBe('XSRF value');
 | |
|           });
 | |
|         });
 | |
|       });
 | |
|     }
 | |
| 
 | |
|     describe('XHRConnection', () => {
 | |
|       it('should use the injected BaseResponseOptions to create the response',
 | |
|          inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
 | |
|            const connection = new XHRConnection(
 | |
|                sampleRequest, new MockBrowserXHR(),
 | |
|                new ResponseOptions({type: ResponseType.Error}));
 | |
|            connection.response.subscribe((res: Response) => {
 | |
|              expect(res.type).toBe(ResponseType.Error);
 | |
|              async.done();
 | |
|            });
 | |
|            existingXHRs[0].setStatusCode(200);
 | |
|            existingXHRs[0].dispatchEvent('load');
 | |
|          }));
 | |
| 
 | |
|       it('should complete a request', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
 | |
|            const 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(); });
 | |
|            existingXHRs[0].setStatusCode(200);
 | |
|            existingXHRs[0].dispatchEvent('load');
 | |
|          }));
 | |
| 
 | |
|       it('should call abort when disposed', () => {
 | |
|         const connection = new XHRConnection(sampleRequest, new MockBrowserXHR());
 | |
|         const request = connection.response.subscribe();
 | |
|         request.unsubscribe();
 | |
|         expect(abortSpy).toHaveBeenCalled();
 | |
|       });
 | |
| 
 | |
|       it('should create an error Response on error',
 | |
|          inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
 | |
|            const connection = new XHRConnection(
 | |
|                sampleRequest, new MockBrowserXHR(),
 | |
|                new ResponseOptions({type: ResponseType.Error}));
 | |
|            connection.response.subscribe(null !, (res: Response) => {
 | |
|              expect(res.type).toBe(ResponseType.Error);
 | |
|              async.done();
 | |
|            });
 | |
|            existingXHRs[0].dispatchEvent('error');
 | |
|          }));
 | |
| 
 | |
|       it('should set the status text and status code on error',
 | |
|          inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
 | |
|            const 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');
 | |
|          }));
 | |
| 
 | |
|       it('should call open with method and url when subscribed to', () => {
 | |
|         const connection = new XHRConnection(sampleRequest, new MockBrowserXHR());
 | |
|         expect(openSpy).not.toHaveBeenCalled();
 | |
|         connection.response.subscribe();
 | |
|         expect(openSpy).toHaveBeenCalledWith('GET', sampleRequest.url);
 | |
|       });
 | |
| 
 | |
|       it('should call send on the backend with request body when subscribed to', () => {
 | |
|         const body = 'Some body to love';
 | |
|         const base = new BaseRequestOptions();
 | |
|         const connection = new XHRConnection(
 | |
|             new Request(base.merge(new RequestOptions({body: body})) as any), new MockBrowserXHR());
 | |
|         expect(sendSpy).not.toHaveBeenCalled();
 | |
|         connection.response.subscribe();
 | |
|         expect(sendSpy).toHaveBeenCalledWith(body);
 | |
|       });
 | |
| 
 | |
|       it('should attach headers to the request', () => {
 | |
|         const headers =
 | |
|             new Headers({'Content-Type': 'text/xml', 'Breaking-Bad': '<3', 'X-Multi': ['a', 'b']});
 | |
| 
 | |
|         const base = new BaseRequestOptions();
 | |
|         const connection = new XHRConnection(
 | |
|             new Request(base.merge(new RequestOptions({headers: headers})) as any),
 | |
|             new MockBrowserXHR());
 | |
|         connection.response.subscribe();
 | |
|         expect(setRequestHeaderSpy).toHaveBeenCalledWith('Content-Type', 'text/xml');
 | |
|         expect(setRequestHeaderSpy).toHaveBeenCalledWith('Breaking-Bad', '<3');
 | |
|         expect(setRequestHeaderSpy).toHaveBeenCalledWith('X-Multi', 'a,b');
 | |
|       });
 | |
| 
 | |
|       it('should attach default Accept header', () => {
 | |
|         const headers = new Headers();
 | |
|         const base = new BaseRequestOptions();
 | |
|         const connection = new XHRConnection(
 | |
|             new Request(base.merge(new RequestOptions({headers})) as any), new MockBrowserXHR());
 | |
|         connection.response.subscribe();
 | |
|         expect(setRequestHeaderSpy)
 | |
|             .toHaveBeenCalledWith('Accept', 'application/json, text/plain, */*');
 | |
|       });
 | |
| 
 | |
|       it('should not override user provided Accept header', () => {
 | |
|         const headers = new Headers({'Accept': 'text/xml'});
 | |
|         const base = new BaseRequestOptions();
 | |
|         const connection = new XHRConnection(
 | |
|             new Request(base.merge(new RequestOptions({headers})) as any), new MockBrowserXHR());
 | |
|         connection.response.subscribe();
 | |
|         expect(setRequestHeaderSpy).toHaveBeenCalledWith('Accept', 'text/xml');
 | |
|       });
 | |
| 
 | |
|       it('should skip content type detection if custom content type header is set', () => {
 | |
|         const headers = new Headers({'Content-Type': 'text/plain'});
 | |
|         const body = {test: 'val'};
 | |
|         const base = new BaseRequestOptions();
 | |
|         const connection = new XHRConnection(
 | |
|             new Request(base.merge(new RequestOptions({body: body, headers: headers})) as any),
 | |
|             new MockBrowserXHR());
 | |
|         connection.response.subscribe();
 | |
|         expect(setRequestHeaderSpy).toHaveBeenCalledWith('Content-Type', 'text/plain');
 | |
|         expect(setRequestHeaderSpy).not.toHaveBeenCalledWith('Content-Type', 'application/json');
 | |
|         expect(setRequestHeaderSpy).not.toHaveBeenCalledWith('content-type', 'application/json');
 | |
|       });
 | |
| 
 | |
|       it('should use object body and detect content type header to the request', () => {
 | |
|         const body = {test: 'val'};
 | |
|         const base = new BaseRequestOptions();
 | |
|         const connection = new XHRConnection(
 | |
|             new Request(base.merge(new RequestOptions({body: body})) as any), new MockBrowserXHR());
 | |
|         connection.response.subscribe();
 | |
|         expect(sendSpy).toHaveBeenCalledWith(JSON.stringify(body, null, 2));
 | |
|         expect(setRequestHeaderSpy).toHaveBeenCalledWith('content-type', 'application/json');
 | |
|       });
 | |
| 
 | |
|       it('should use number body and detect content type header to the request', () => {
 | |
|         const body = 23;
 | |
|         const base = new BaseRequestOptions();
 | |
|         const connection = new XHRConnection(
 | |
|             new Request(base.merge(new RequestOptions({body: body})) as any), new MockBrowserXHR());
 | |
|         connection.response.subscribe();
 | |
|         expect(sendSpy).toHaveBeenCalledWith('23');
 | |
|         expect(setRequestHeaderSpy).toHaveBeenCalledWith('content-type', 'text/plain');
 | |
|       });
 | |
| 
 | |
|       it('should use string body and detect content type header to the request', () => {
 | |
|         const body = 'some string';
 | |
|         const base = new BaseRequestOptions();
 | |
|         const connection = new XHRConnection(
 | |
|             new Request(base.merge(new RequestOptions({body: body})) as any), new MockBrowserXHR());
 | |
|         connection.response.subscribe();
 | |
|         expect(sendSpy).toHaveBeenCalledWith(body);
 | |
|         expect(setRequestHeaderSpy).toHaveBeenCalledWith('content-type', 'text/plain');
 | |
|       });
 | |
| 
 | |
|       it('should use URLSearchParams body and detect content type header to the request', () => {
 | |
|         const body = new URLSearchParams();
 | |
|         body.set('test1', 'val1');
 | |
|         body.set('test2', 'val2');
 | |
|         const base = new BaseRequestOptions();
 | |
|         const connection = new XHRConnection(
 | |
|             new Request(base.merge(new RequestOptions({body: body})) as any), new MockBrowserXHR());
 | |
|         connection.response.subscribe();
 | |
|         expect(sendSpy).toHaveBeenCalledWith('test1=val1&test2=val2');
 | |
|         expect(setRequestHeaderSpy)
 | |
|             .toHaveBeenCalledWith(
 | |
|                 'content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
 | |
|       });
 | |
| 
 | |
|       if ((global as any /** TODO #9100 */)['Blob']) {
 | |
|         // `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;
 | |
|         };
 | |
| 
 | |
|         it('should use FormData body and detect content type header to the request', () => {
 | |
|           const body = new FormData();
 | |
|           body.append('test1', 'val1');
 | |
|           body.append('test2', '123456');
 | |
|           const blob = createBlob(['body { color: red; }'], 'text/css');
 | |
|           body.append('userfile', blob);
 | |
|           const base = new BaseRequestOptions();
 | |
|           const connection = new XHRConnection(
 | |
|               new Request(base.merge(new RequestOptions({body: body})) as any),
 | |
|               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', () => {
 | |
|           const body = createBlob(['body { color: red; }'], 'text/css');
 | |
|           const base = new BaseRequestOptions();
 | |
|           const connection = new XHRConnection(
 | |
|               new Request(base.merge(new RequestOptions({body: body})) as any),
 | |
|               new MockBrowserXHR());
 | |
|           connection.response.subscribe();
 | |
|           expect(sendSpy).toHaveBeenCalledWith(body);
 | |
|           expect(setRequestHeaderSpy).toHaveBeenCalledWith('content-type', 'text/css');
 | |
|         });
 | |
| 
 | |
|         it('should use blob body without type to the request', () => {
 | |
|           const body = createBlob(['body { color: red; }'], null !);
 | |
|           const base = new BaseRequestOptions();
 | |
|           const 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 without type with custom content type header to the request',
 | |
|            () => {
 | |
|              const headers = new Headers({'Content-Type': 'text/css'});
 | |
|              const body = createBlob(['body { color: red; }'], null !);
 | |
|              const base = new BaseRequestOptions();
 | |
|              const connection = new XHRConnection(
 | |
|                  new Request(base.merge(new RequestOptions({body: body, headers: headers}))),
 | |
|                  new MockBrowserXHR());
 | |
|              connection.response.subscribe();
 | |
|              expect(sendSpy).toHaveBeenCalledWith(body);
 | |
|              expect(setRequestHeaderSpy).toHaveBeenCalledWith('Content-Type', 'text/css');
 | |
|            });
 | |
| 
 | |
|         it('should use array buffer body to the request', () => {
 | |
|           const body = new ArrayBuffer(512);
 | |
|           const longInt8View = new Uint8Array(body);
 | |
|           for (let i = 0; i < longInt8View.length; i++) {
 | |
|             longInt8View[i] = i % 255;
 | |
|           }
 | |
|           const base = new BaseRequestOptions();
 | |
|           const 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 array buffer body without type with custom content type header to the request',
 | |
|            () => {
 | |
|              const headers = new Headers({'Content-Type': 'text/css'});
 | |
|              const body = new ArrayBuffer(512);
 | |
|              const longInt8View = new Uint8Array(body);
 | |
|              for (let i = 0; i < longInt8View.length; i++) {
 | |
|                longInt8View[i] = i % 255;
 | |
|              }
 | |
|              const base = new BaseRequestOptions();
 | |
|              const connection = new XHRConnection(
 | |
|                  new Request(base.merge(new RequestOptions({body: body, headers: headers}))),
 | |
|                  new MockBrowserXHR());
 | |
|              connection.response.subscribe();
 | |
|              expect(sendSpy).toHaveBeenCalledWith(body);
 | |
|              expect(setRequestHeaderSpy).toHaveBeenCalledWith('Content-Type', 'text/css');
 | |
|            });
 | |
|       }
 | |
| 
 | |
|       it('should return the correct status code',
 | |
|          inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
 | |
|            const statusCode = 418;
 | |
|            const connection = new XHRConnection(
 | |
|                sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
 | |
| 
 | |
|            connection.response.subscribe(
 | |
|                (res: Response) => {
 | |
| 
 | |
|                },
 | |
|                errRes => {
 | |
|                  expect(errRes.status).toBe(statusCode);
 | |
|                  async.done();
 | |
|                });
 | |
| 
 | |
|            existingXHRs[0].setStatusCode(statusCode);
 | |
|            existingXHRs[0].dispatchEvent('load');
 | |
|          }));
 | |
| 
 | |
|       it('should call next and complete on 200 codes',
 | |
|          inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
 | |
|            let nextCalled = false;
 | |
|            let errorCalled = false;
 | |
|            const statusCode = 200;
 | |
|            const connection = new XHRConnection(
 | |
|                sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
 | |
| 
 | |
|            connection.response.subscribe(
 | |
|                (res: Response) => {
 | |
|                  nextCalled = true;
 | |
|                  expect(res.status).toBe(statusCode);
 | |
|                },
 | |
|                errRes => { errorCalled = true; },
 | |
|                () => {
 | |
|                  expect(nextCalled).toBe(true);
 | |
|                  expect(errorCalled).toBe(false);
 | |
|                  async.done();
 | |
|                });
 | |
| 
 | |
|            existingXHRs[0].setStatusCode(statusCode);
 | |
|            existingXHRs[0].dispatchEvent('load');
 | |
|          }));
 | |
| 
 | |
|       it('should set ok to true on 200 return',
 | |
|          inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
 | |
|            const statusCode = 200;
 | |
|            const connection = new XHRConnection(
 | |
|                sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
 | |
| 
 | |
|            connection.response.subscribe(res => {
 | |
|              expect(res.ok).toBe(true);
 | |
|              async.done();
 | |
|            });
 | |
| 
 | |
|            existingXHRs[0].setStatusCode(statusCode);
 | |
|            existingXHRs[0].dispatchEvent('load');
 | |
|          }));
 | |
| 
 | |
|       it('should set ok to false on 300 return',
 | |
|          inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
 | |
|            const statusCode = 300;
 | |
|            const connection = new XHRConnection(
 | |
|                sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
 | |
| 
 | |
|            connection.response.subscribe(
 | |
|                res => { throw 'should not be called'; },
 | |
|                errRes => {
 | |
|                  expect(errRes.ok).toBe(false);
 | |
|                  async.done();
 | |
|                });
 | |
| 
 | |
|            existingXHRs[0].setStatusCode(statusCode);
 | |
|            existingXHRs[0].dispatchEvent('load');
 | |
|          }));
 | |
| 
 | |
|       it('should call error and not complete on 300+ codes',
 | |
|          inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
 | |
|            let nextCalled = false;
 | |
|            const errorCalled = false;
 | |
|            const statusCode = 301;
 | |
|            const connection = new XHRConnection(
 | |
|                sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
 | |
| 
 | |
|            connection.response.subscribe(
 | |
|                (res: Response) => { nextCalled = true; },
 | |
|                errRes => {
 | |
|                  expect(errRes.status).toBe(statusCode);
 | |
|                  expect(nextCalled).toBe(false);
 | |
|                  async.done();
 | |
|                },
 | |
|                () => { throw 'should not be called'; });
 | |
| 
 | |
|            existingXHRs[0].setStatusCode(statusCode);
 | |
|            existingXHRs[0].dispatchEvent('load');
 | |
|          }));
 | |
| 
 | |
|       it('should normalize IE\'s 1223 status code into 204',
 | |
|          inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
 | |
|            const statusCode = 1223;
 | |
|            const normalizedCode = 204;
 | |
|            const connection = new XHRConnection(
 | |
|                sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
 | |
| 
 | |
|            connection.response.subscribe((res: Response) => {
 | |
|              expect(res.status).toBe(normalizedCode);
 | |
|              async.done();
 | |
|            });
 | |
| 
 | |
|            existingXHRs[0].setStatusCode(statusCode);
 | |
|            existingXHRs[0].dispatchEvent('load');
 | |
|          }));
 | |
| 
 | |
|       it('should ignore response body for 204 status code',
 | |
|          inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
 | |
|            const statusCode = 204;
 | |
|            const connection = new XHRConnection(
 | |
|                sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
 | |
| 
 | |
|            connection.response.subscribe((res: Response) => {
 | |
|              expect(res.text()).toBe('');
 | |
|              async.done();
 | |
|            });
 | |
| 
 | |
|            existingXHRs[0].setStatusCode(statusCode);
 | |
|            existingXHRs[0].setResponseText('Doge');
 | |
|            existingXHRs[0].dispatchEvent('load');
 | |
|          }));
 | |
| 
 | |
|       it('should normalize responseText and response',
 | |
|          inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
 | |
|            const responseBody = 'Doge';
 | |
| 
 | |
|            const connection1 =
 | |
|                new XHRConnection(sampleRequest, new MockBrowserXHR(), new ResponseOptions());
 | |
| 
 | |
|            const connection2 =
 | |
|                new XHRConnection(sampleRequest, new MockBrowserXHR(), new ResponseOptions());
 | |
| 
 | |
|            connection1.response.subscribe((res: Response) => {
 | |
|              expect(res.text()).toBe(responseBody);
 | |
| 
 | |
|              connection2.response.subscribe(ress => {
 | |
|                expect(ress.text()).toBe(responseBody);
 | |
|                async.done();
 | |
|              });
 | |
|              existingXHRs[1].setStatusCode(200);
 | |
|              existingXHRs[1].setResponse(responseBody);
 | |
|              existingXHRs[1].dispatchEvent('load');
 | |
|            });
 | |
|            existingXHRs[0].setStatusCode(200);
 | |
|            existingXHRs[0].setResponseText(responseBody);
 | |
|            existingXHRs[0].dispatchEvent('load');
 | |
|          }));
 | |
| 
 | |
|       it('should strip XSSI prefixes', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
 | |
|            const 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');
 | |
|          }));
 | |
| 
 | |
|       it('should strip XSSI prefixes', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
 | |
|            const 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');
 | |
|          }));
 | |
| 
 | |
|       it('should strip XSSI prefix from errors',
 | |
|          inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
 | |
|            const conn =
 | |
|                new XHRConnection(sampleRequest, new MockBrowserXHR(), new ResponseOptions());
 | |
|            conn.response.subscribe(null !, (res: Response) => {
 | |
|              expect(res.text()).toBe('{json: "object"}');
 | |
|              async.done();
 | |
|            });
 | |
|            existingXHRs[0].setStatusCode(404);
 | |
|            existingXHRs[0].setResponseText(')]}\'\n{json: "object"}');
 | |
|            existingXHRs[0].dispatchEvent('load');
 | |
|          }));
 | |
| 
 | |
|       it('should parse response headers and add them to the response',
 | |
|          inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
 | |
|            const statusCode = 200;
 | |
|            const connection = new XHRConnection(
 | |
|                sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
 | |
| 
 | |
|            const responseHeaderString = `Date: Fri, 20 Nov 2015 01:45:26 GMT
 | |
| Content-Type: application/json; charset=utf-8
 | |
| Transfer-Encoding: chunked
 | |
| Connection: keep-alive`;
 | |
| 
 | |
|            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();
 | |
|            });
 | |
| 
 | |
|            existingXHRs[0].setResponseHeaders(responseHeaderString);
 | |
|            existingXHRs[0].setStatusCode(statusCode);
 | |
|            existingXHRs[0].dispatchEvent('load');
 | |
|          }));
 | |
| 
 | |
|       it('should add the responseURL to the response',
 | |
|          inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
 | |
|            const statusCode = 200;
 | |
|            const connection = new XHRConnection(
 | |
|                sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
 | |
| 
 | |
|            connection.response.subscribe((res: Response) => {
 | |
|              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',
 | |
|          inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
 | |
|            const statusCode = 200;
 | |
|            const connection = new XHRConnection(
 | |
|                sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
 | |
|            const responseHeaders = `X-Request-URL: http://somedomain.com
 | |
|            Foo: Bar`;
 | |
| 
 | |
|            connection.response.subscribe((res: Response) => {
 | |
|              expect(res.url).toEqual('http://somedomain.com');
 | |
|              async.done();
 | |
|            });
 | |
| 
 | |
|            existingXHRs[0].setResponseHeaders(responseHeaders);
 | |
|            existingXHRs[0].setStatusCode(statusCode);
 | |
|            existingXHRs[0].dispatchEvent('load');
 | |
|          }));
 | |
| 
 | |
|       it('should return request url if it cannot be retrieved from response',
 | |
|          inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
 | |
|            const statusCode = 200;
 | |
|            const connection = new XHRConnection(
 | |
|                sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode}));
 | |
| 
 | |
|            connection.response.subscribe((res: Response) => {
 | |
|              expect(res.url).toEqual('https://google.com');
 | |
|              async.done();
 | |
|            });
 | |
| 
 | |
|            existingXHRs[0].setStatusCode(statusCode);
 | |
|            existingXHRs[0].dispatchEvent('load');
 | |
|          }));
 | |
| 
 | |
|       it('should set the status text property from the XMLHttpRequest instance if present',
 | |
|          inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
 | |
|            const statusText = 'test';
 | |
|            const 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) => {
 | |
|            const 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');
 | |
|          }));
 | |
| 
 | |
|       it('should set withCredentials to true when defined in request options for CORS situations',
 | |
|          inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
 | |
|            const statusCode = 200;
 | |
|            sampleRequest.withCredentials = true;
 | |
|            const mockXhr = new MockBrowserXHR();
 | |
|            const connection =
 | |
|                new XHRConnection(sampleRequest, mockXhr, new ResponseOptions({status: statusCode}));
 | |
|            const responseHeaders = `X-Request-URL: http://somedomain.com
 | |
|            Foo: Bar`;
 | |
| 
 | |
|            connection.response.subscribe((res: Response) => {
 | |
|              expect(res.url).toEqual('http://somedomain.com');
 | |
|              expect(existingXHRs[0].withCredentials).toBeTruthy();
 | |
|              async.done();
 | |
|            });
 | |
| 
 | |
|            existingXHRs[0].setResponseHeaders(responseHeaders);
 | |
|            existingXHRs[0].setStatusCode(statusCode);
 | |
|            existingXHRs[0].dispatchEvent('load');
 | |
|          }));
 | |
| 
 | |
|       it('should set the responseType attribute to blob when the corresponding response content type is present',
 | |
|          inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
 | |
|            const statusCode = 200;
 | |
|            const base = new BaseRequestOptions();
 | |
|            const 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');
 | |
|          }));
 | |
| 
 | |
|       it('should not throw invalidStateError if response without body and responseType not equal to text',
 | |
|          inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
 | |
|            const base = new BaseRequestOptions();
 | |
|            const connection = new XHRConnection(
 | |
|                new Request(
 | |
|                    base.merge(new RequestOptions({responseType: ResponseContentType.Json}))),
 | |
|                new MockBrowserXHR());
 | |
| 
 | |
|            connection.response.subscribe((res: Response) => {
 | |
|              expect(res.json()).toBe(null);
 | |
|              async.done();
 | |
|            });
 | |
| 
 | |
|            existingXHRs[0].setStatusCode(204);
 | |
|            existingXHRs[0].dispatchEvent('load');
 | |
|          }));
 | |
|     });
 | |
|   });
 | |
| }
 |