206 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
		
		
			
		
	
	
			206 lines
		
	
	
		
			8.5 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 {ifEnvSupports, ifEnvSupportsWithDone, isFirefox, isSafari} from '../test-util';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								declare const global: any;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe(
							 | 
						||
| 
								 | 
							
								    'fetch', ifEnvSupports('fetch', function() {
							 | 
						||
| 
								 | 
							
								      let testZone: Zone;
							 | 
						||
| 
								 | 
							
								      beforeEach(() => { testZone = Zone.current.fork({name: 'TestZone'}); });
							 | 
						||
| 
								 | 
							
								      it('should work for text response', function(done) {
							 | 
						||
| 
								 | 
							
								        testZone.run(function() {
							 | 
						||
| 
								 | 
							
								          global['fetch']('/base/angular/packages/zone.js/test/assets/sample.json')
							 | 
						||
| 
								 | 
							
								              .then(function(response: any) {
							 | 
						||
| 
								 | 
							
								                const fetchZone = Zone.current;
							 | 
						||
| 
								 | 
							
								                expect(fetchZone.name).toBe(testZone.name);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                response.text().then(function(text: string) {
							 | 
						||
| 
								 | 
							
								                  expect(Zone.current.name).toBe(fetchZone.name);
							 | 
						||
| 
								 | 
							
								                  expect(text.trim()).toEqual('{"hello": "world"}');
							 | 
						||
| 
								 | 
							
								                  done();
							 | 
						||
| 
								 | 
							
								                });
							 | 
						||
| 
								 | 
							
								              });
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      it('should work for json response', function(done) {
							 | 
						||
| 
								 | 
							
								        testZone.run(function() {
							 | 
						||
| 
								 | 
							
								          global['fetch']('/base/angular/packages/zone.js/test/assets/sample.json')
							 | 
						||
| 
								 | 
							
								              .then(function(response: any) {
							 | 
						||
| 
								 | 
							
								                const fetchZone = Zone.current;
							 | 
						||
| 
								 | 
							
								                expect(fetchZone.name).toBe(testZone.name);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                response.json().then(function(obj: any) {
							 | 
						||
| 
								 | 
							
								                  expect(Zone.current.name).toBe(fetchZone.name);
							 | 
						||
| 
								 | 
							
								                  expect(obj.hello).toEqual('world');
							 | 
						||
| 
								 | 
							
								                  done();
							 | 
						||
| 
								 | 
							
								                });
							 | 
						||
| 
								 | 
							
								              });
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      it('should work for blob response', function(done) {
							 | 
						||
| 
								 | 
							
								        testZone.run(function() {
							 | 
						||
| 
								 | 
							
								          global['fetch']('/base/angular/packages/zone.js/test/assets/sample.json')
							 | 
						||
| 
								 | 
							
								              .then(function(response: any) {
							 | 
						||
| 
								 | 
							
								                const fetchZone = Zone.current;
							 | 
						||
| 
								 | 
							
								                expect(fetchZone.name).toBe(testZone.name);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                // Android 4.3- doesn't support response.blob()
							 | 
						||
| 
								 | 
							
								                if (response.blob) {
							 | 
						||
| 
								 | 
							
								                  response.blob().then(function(blob: any) {
							 | 
						||
| 
								 | 
							
								                    expect(Zone.current.name).toBe(fetchZone.name);
							 | 
						||
| 
								 | 
							
								                    expect(blob instanceof Blob).toEqual(true);
							 | 
						||
| 
								 | 
							
								                    done();
							 | 
						||
| 
								 | 
							
								                  });
							 | 
						||
| 
								 | 
							
								                } else {
							 | 
						||
| 
								 | 
							
								                  done();
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								              });
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      it('should work for arrayBuffer response', function(done) {
							 | 
						||
| 
								 | 
							
								        testZone.run(function() {
							 | 
						||
| 
								 | 
							
								          global['fetch']('/base/angular/packages/zone.js/test/assets/sample.json')
							 | 
						||
| 
								 | 
							
								              .then(function(response: any) {
							 | 
						||
| 
								 | 
							
								                const fetchZone = Zone.current;
							 | 
						||
| 
								 | 
							
								                expect(fetchZone.name).toBe(testZone.name);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                // Android 4.3- doesn't support response.arrayBuffer()
							 | 
						||
| 
								 | 
							
								                if (response.arrayBuffer) {
							 | 
						||
| 
								 | 
							
								                  response.arrayBuffer().then(function(blob: any) {
							 | 
						||
| 
								 | 
							
								                    expect(Zone.current).toBe(fetchZone);
							 | 
						||
| 
								 | 
							
								                    expect(blob instanceof ArrayBuffer).toEqual(true);
							 | 
						||
| 
								 | 
							
								                    done();
							 | 
						||
| 
								 | 
							
								                  });
							 | 
						||
| 
								 | 
							
								                } else {
							 | 
						||
| 
								 | 
							
								                  done();
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								              });
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      it('should throw error when send crendential',
							 | 
						||
| 
								 | 
							
								         ifEnvSupportsWithDone(isFirefox, function(done: DoneFn) {
							 | 
						||
| 
								 | 
							
								           testZone.run(function() {
							 | 
						||
| 
								 | 
							
								             global['fetch']('http://user:password@example.com')
							 | 
						||
| 
								 | 
							
								                 .then(
							 | 
						||
| 
								 | 
							
								                     function(response: any) { fail('should not success'); },
							 | 
						||
| 
								 | 
							
								                     (error: any) => {
							 | 
						||
| 
								 | 
							
								                       expect(Zone.current.name).toEqual(testZone.name);
							 | 
						||
| 
								 | 
							
								                       expect(error.constructor.name).toEqual('TypeError');
							 | 
						||
| 
								 | 
							
								                       done();
							 | 
						||
| 
								 | 
							
								                     });
							 | 
						||
| 
								 | 
							
								           });
							 | 
						||
| 
								 | 
							
								         }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      describe('macroTask', () => {
							 | 
						||
| 
								 | 
							
								        const logs: string[] = [];
							 | 
						||
| 
								 | 
							
								        let fetchZone: Zone;
							 | 
						||
| 
								 | 
							
								        let fetchTask: any = null;
							 | 
						||
| 
								 | 
							
								        beforeEach(() => {
							 | 
						||
| 
								 | 
							
								          logs.splice(0);
							 | 
						||
| 
								 | 
							
								          fetchZone = Zone.current.fork({
							 | 
						||
| 
								 | 
							
								            name: 'fetch',
							 | 
						||
| 
								 | 
							
								            onScheduleTask: (delegate: ZoneDelegate, curr: Zone, target: Zone, task: Task) => {
							 | 
						||
| 
								 | 
							
								              if (task.type !== 'eventTask') {
							 | 
						||
| 
								 | 
							
								                logs.push(`scheduleTask:${task.source}:${task.type}`);
							 | 
						||
| 
								 | 
							
								              }
							 | 
						||
| 
								 | 
							
								              if (task.source === 'fetch') {
							 | 
						||
| 
								 | 
							
								                fetchTask = task;
							 | 
						||
| 
								 | 
							
								              }
							 | 
						||
| 
								 | 
							
								              return delegate.scheduleTask(target, task);
							 | 
						||
| 
								 | 
							
								            },
							 | 
						||
| 
								 | 
							
								            onInvokeTask: (delegate: ZoneDelegate, curr: Zone, target: Zone, task: Task,
							 | 
						||
| 
								 | 
							
								                           applyThis: any, applyArgs: any) => {
							 | 
						||
| 
								 | 
							
								              if (task.type !== 'eventTask') {
							 | 
						||
| 
								 | 
							
								                logs.push(`invokeTask:${task.source}:${task.type}`);
							 | 
						||
| 
								 | 
							
								              }
							 | 
						||
| 
								 | 
							
								              return delegate.invokeTask(target, task, applyThis, applyArgs);
							 | 
						||
| 
								 | 
							
								            },
							 | 
						||
| 
								 | 
							
								            onCancelTask: (delegate: ZoneDelegate, curr: Zone, target: Zone, task: Task) => {
							 | 
						||
| 
								 | 
							
								              if (task.type !== 'eventTask') {
							 | 
						||
| 
								 | 
							
								                logs.push(`cancelTask:${task.source}:${task.type}`);
							 | 
						||
| 
								 | 
							
								              }
							 | 
						||
| 
								 | 
							
								              return delegate.cancelTask(target, task);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								          });
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								        it('fetch should be considered as macroTask', (done: DoneFn) => {
							 | 
						||
| 
								 | 
							
								          fetchZone.run(() => {
							 | 
						||
| 
								 | 
							
								            global['fetch']('/base/angular/packages/zone.js/test/assets/sample.json')
							 | 
						||
| 
								 | 
							
								                .then(function(response: any) {
							 | 
						||
| 
								 | 
							
								                  expect(Zone.current.name).toBe(fetchZone.name);
							 | 
						||
| 
								 | 
							
								                  expect(logs).toEqual([
							 | 
						||
| 
								 | 
							
								                    'scheduleTask:fetch:macroTask', 'scheduleTask:Promise.then:microTask',
							 | 
						||
| 
								 | 
							
								                    'invokeTask:Promise.then:microTask', 'invokeTask:fetch:macroTask',
							 | 
						||
| 
								 | 
							
								                    'scheduleTask:Promise.then:microTask', 'invokeTask:Promise.then:microTask'
							 | 
						||
| 
								 | 
							
								                  ]);
							 | 
						||
| 
								 | 
							
								                  done();
							 | 
						||
| 
								 | 
							
								                });
							 | 
						||
| 
								 | 
							
								          });
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        it('cancel fetch should invoke onCancelTask',
							 | 
						||
| 
								 | 
							
								           ifEnvSupportsWithDone('AbortController', (done: DoneFn) => {
							 | 
						||
| 
								 | 
							
								             if (isSafari) {
							 | 
						||
| 
								 | 
							
								               // safari not work with AbortController
							 | 
						||
| 
								 | 
							
								               done();
							 | 
						||
| 
								 | 
							
								               return;
							 | 
						||
| 
								 | 
							
								             }
							 | 
						||
| 
								 | 
							
								             fetchZone.run(() => {
							 | 
						||
| 
								 | 
							
								               const AbortController = global['AbortController'];
							 | 
						||
| 
								 | 
							
								               const abort = new AbortController();
							 | 
						||
| 
								 | 
							
								               const signal = abort.signal;
							 | 
						||
| 
								 | 
							
								               global['fetch']('/base/angular/packages/zone.js/test/assets/sample.json', {signal})
							 | 
						||
| 
								 | 
							
								                   .then(function(response: any) { fail('should not get response'); })
							 | 
						||
| 
								 | 
							
								                   .catch(function(error: any) {
							 | 
						||
| 
								 | 
							
								                     expect(error.name).toEqual('AbortError');
							 | 
						||
| 
								 | 
							
								                     expect(logs).toEqual([
							 | 
						||
| 
								 | 
							
								                       'scheduleTask:fetch:macroTask', 'cancelTask:fetch:macroTask',
							 | 
						||
| 
								 | 
							
								                       'scheduleTask:Promise.then:microTask', 'invokeTask:Promise.then:microTask',
							 | 
						||
| 
								 | 
							
								                       'scheduleTask:Promise.then:microTask', 'invokeTask:Promise.then:microTask',
							 | 
						||
| 
								 | 
							
								                       'scheduleTask:Promise.then:microTask', 'invokeTask:Promise.then:microTask'
							 | 
						||
| 
								 | 
							
								                     ]);
							 | 
						||
| 
								 | 
							
								                     done();
							 | 
						||
| 
								 | 
							
								                   });
							 | 
						||
| 
								 | 
							
								               abort.abort();
							 | 
						||
| 
								 | 
							
								             });
							 | 
						||
| 
								 | 
							
								           }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        it('cancel fetchTask should trigger abort',
							 | 
						||
| 
								 | 
							
								           ifEnvSupportsWithDone('AbortController', (done: DoneFn) => {
							 | 
						||
| 
								 | 
							
								             if (isSafari) {
							 | 
						||
| 
								 | 
							
								               // safari not work with AbortController
							 | 
						||
| 
								 | 
							
								               done();
							 | 
						||
| 
								 | 
							
								               return;
							 | 
						||
| 
								 | 
							
								             }
							 | 
						||
| 
								 | 
							
								             fetchZone.run(() => {
							 | 
						||
| 
								 | 
							
								               const AbortController = global['AbortController'];
							 | 
						||
| 
								 | 
							
								               const abort = new AbortController();
							 | 
						||
| 
								 | 
							
								               const signal = abort.signal;
							 | 
						||
| 
								 | 
							
								               global['fetch']('/base/angular/packages/zone.js/test/assets/sample.json', {signal})
							 | 
						||
| 
								 | 
							
								                   .then(function(response: any) { fail('should not get response'); })
							 | 
						||
| 
								 | 
							
								                   .catch(function(error: any) {
							 | 
						||
| 
								 | 
							
								                     expect(error.name).toEqual('AbortError');
							 | 
						||
| 
								 | 
							
								                     expect(logs).toEqual([
							 | 
						||
| 
								 | 
							
								                       'scheduleTask:fetch:macroTask', 'cancelTask:fetch:macroTask',
							 | 
						||
| 
								 | 
							
								                       'scheduleTask:Promise.then:microTask', 'invokeTask:Promise.then:microTask',
							 | 
						||
| 
								 | 
							
								                       'scheduleTask:Promise.then:microTask', 'invokeTask:Promise.then:microTask',
							 | 
						||
| 
								 | 
							
								                       'scheduleTask:Promise.then:microTask', 'invokeTask:Promise.then:microTask'
							 | 
						||
| 
								 | 
							
								                     ]);
							 | 
						||
| 
								 | 
							
								                     done();
							 | 
						||
| 
								 | 
							
								                   });
							 | 
						||
| 
								 | 
							
								               fetchTask.zone.cancelTask(fetchTask);
							 | 
						||
| 
								 | 
							
								             });
							 | 
						||
| 
								 | 
							
								           }));
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								    }));
							 |