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); | ||
|  |              }); | ||
|  |            })); | ||
|  |       }); | ||
|  |     })); |