Update the license headers throughout the repository to reference Google LLC rather than Google Inc, for the required license headers. PR Close #37205
		
			
				
	
	
		
			436 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			436 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| /**
 | |
|  * @license
 | |
|  * Copyright Google LLC 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 {discardPeriodicTasks, fakeAsync, flush, flushMicrotasks, tick} from '@angular/core/testing';
 | |
| import {beforeEach, describe, inject, it, Log} from '@angular/core/testing/src/testing_internal';
 | |
| import {EventManager} from '@angular/platform-browser';
 | |
| import {expect} from '@angular/platform-browser/testing/src/matchers';
 | |
| 
 | |
| const resolvedPromise = Promise.resolve(null);
 | |
| const ProxyZoneSpec: {assertPresent: () => void} = (Zone as any)['ProxyZoneSpec'];
 | |
| 
 | |
| {
 | |
|   describe('fake async', () => {
 | |
|     it('should run synchronous code', () => {
 | |
|       let ran = false;
 | |
|       fakeAsync(() => {
 | |
|         ran = true;
 | |
|       })();
 | |
| 
 | |
|       expect(ran).toEqual(true);
 | |
|     });
 | |
| 
 | |
|     it('should pass arguments to the wrapped function', () => {
 | |
|       fakeAsync((foo: any /** TODO #9100 */, bar: any /** TODO #9100 */) => {
 | |
|         expect(foo).toEqual('foo');
 | |
|         expect(bar).toEqual('bar');
 | |
|       })('foo', 'bar');
 | |
|     });
 | |
| 
 | |
|     it('should work with inject()',
 | |
|        fakeAsync(inject([EventManager], (eventManager: EventManager) => {
 | |
|          expect(eventManager).toBeAnInstanceOf(EventManager);
 | |
|        })));
 | |
| 
 | |
|     it('should throw on nested calls', () => {
 | |
|       expect(() => {
 | |
|         fakeAsync(() => {
 | |
|           fakeAsync((): any /** TODO #9100 */ => null)();
 | |
|         })();
 | |
|       }).toThrowError('fakeAsync() calls can not be nested');
 | |
|     });
 | |
| 
 | |
|     it('should flush microtasks before returning', () => {
 | |
|       let thenRan = false;
 | |
| 
 | |
|       fakeAsync(() => {
 | |
|         resolvedPromise.then(_ => {
 | |
|           thenRan = true;
 | |
|         });
 | |
|       })();
 | |
| 
 | |
|       expect(thenRan).toEqual(true);
 | |
|     });
 | |
| 
 | |
| 
 | |
|     it('should propagate the return value', () => {
 | |
|       expect(fakeAsync(() => 'foo')()).toEqual('foo');
 | |
|     });
 | |
| 
 | |
|     describe('Promise', () => {
 | |
|       it('should run asynchronous code', fakeAsync(() => {
 | |
|            let thenRan = false;
 | |
|            resolvedPromise.then((_) => {
 | |
|              thenRan = true;
 | |
|            });
 | |
| 
 | |
|            expect(thenRan).toEqual(false);
 | |
| 
 | |
|            flushMicrotasks();
 | |
|            expect(thenRan).toEqual(true);
 | |
|          }));
 | |
| 
 | |
|       it('should run chained thens', fakeAsync(() => {
 | |
|            const log = new Log();
 | |
| 
 | |
|            resolvedPromise.then((_) => log.add(1)).then((_) => log.add(2));
 | |
| 
 | |
|            expect(log.result()).toEqual('');
 | |
| 
 | |
|            flushMicrotasks();
 | |
|            expect(log.result()).toEqual('1; 2');
 | |
|          }));
 | |
| 
 | |
|       it('should run Promise created in Promise', fakeAsync(() => {
 | |
|            const log = new Log();
 | |
| 
 | |
|            resolvedPromise.then((_) => {
 | |
|              log.add(1);
 | |
|              resolvedPromise.then((_) => log.add(2));
 | |
|            });
 | |
| 
 | |
|            expect(log.result()).toEqual('');
 | |
| 
 | |
|            flushMicrotasks();
 | |
|            expect(log.result()).toEqual('1; 2');
 | |
|          }));
 | |
| 
 | |
|       it('should complain if the test throws an exception during async calls', () => {
 | |
|         expect(() => {
 | |
|           fakeAsync(() => {
 | |
|             resolvedPromise.then((_) => {
 | |
|               throw new Error('async');
 | |
|             });
 | |
|             flushMicrotasks();
 | |
|           })();
 | |
|         }).toThrow();
 | |
|       });
 | |
| 
 | |
|       it('should complain if a test throws an exception', () => {
 | |
|         expect(() => {
 | |
|           fakeAsync(() => {
 | |
|             throw new Error('sync');
 | |
|           })();
 | |
|         }).toThrowError('sync');
 | |
|       });
 | |
|     });
 | |
| 
 | |
|     describe('timers', () => {
 | |
|       it('should run queued zero duration timer on zero tick', fakeAsync(() => {
 | |
|            let ran = false;
 | |
|            setTimeout(() => {
 | |
|              ran = true;
 | |
|            }, 0);
 | |
| 
 | |
|            expect(ran).toEqual(false);
 | |
| 
 | |
|            tick();
 | |
|            expect(ran).toEqual(true);
 | |
|          }));
 | |
| 
 | |
| 
 | |
|       it('should run queued timer after sufficient clock ticks', fakeAsync(() => {
 | |
|            let ran = false;
 | |
|            setTimeout(() => {
 | |
|              ran = true;
 | |
|            }, 10);
 | |
| 
 | |
|            tick(6);
 | |
|            expect(ran).toEqual(false);
 | |
| 
 | |
|            tick(6);
 | |
|            expect(ran).toEqual(true);
 | |
|          }));
 | |
| 
 | |
|       it('should run new macro tasks created by timer callback', fakeAsync(() => {
 | |
|            function nestedTimer(callback: () => any): void {
 | |
|              setTimeout(() => setTimeout(() => callback()));
 | |
|            }
 | |
|            const callback = jasmine.createSpy('callback');
 | |
|            nestedTimer(callback);
 | |
|            expect(callback).not.toHaveBeenCalled();
 | |
|            tick(0);
 | |
|            expect(callback).toHaveBeenCalled();
 | |
|          }));
 | |
| 
 | |
|       it('should not queue nested timer on tick with processNewMacroTasksSynchronously=false',
 | |
|          fakeAsync(() => {
 | |
|            function nestedTimer(callback: () => any): void {
 | |
|              setTimeout(() => setTimeout(() => callback()));
 | |
|            }
 | |
|            const callback = jasmine.createSpy('callback');
 | |
|            nestedTimer(callback);
 | |
|            expect(callback).not.toHaveBeenCalled();
 | |
|            tick(0, {processNewMacroTasksSynchronously: false});
 | |
|            expect(callback).not.toHaveBeenCalled();
 | |
|            flush();
 | |
|            expect(callback).toHaveBeenCalled();
 | |
|          }));
 | |
| 
 | |
|       it('should run queued timer only once', fakeAsync(() => {
 | |
|            let cycles = 0;
 | |
|            setTimeout(() => {
 | |
|              cycles++;
 | |
|            }, 10);
 | |
| 
 | |
|            tick(10);
 | |
|            expect(cycles).toEqual(1);
 | |
| 
 | |
|            tick(10);
 | |
|            expect(cycles).toEqual(1);
 | |
| 
 | |
|            tick(10);
 | |
|            expect(cycles).toEqual(1);
 | |
|          }));
 | |
| 
 | |
|       it('should not run cancelled timer', fakeAsync(() => {
 | |
|            let ran = false;
 | |
|            const id = setTimeout(() => {
 | |
|              ran = true;
 | |
|            }, 10);
 | |
|            clearTimeout(id);
 | |
| 
 | |
|            tick(10);
 | |
|            expect(ran).toEqual(false);
 | |
|          }));
 | |
| 
 | |
|       it('should throw an error on dangling timers', () => {
 | |
|         expect(() => {
 | |
|           fakeAsync(() => {
 | |
|             setTimeout(() => {}, 10);
 | |
|           })();
 | |
|         }).toThrowError('1 timer(s) still in the queue.');
 | |
|       });
 | |
| 
 | |
|       it('should throw an error on dangling periodic timers', () => {
 | |
|         expect(() => {
 | |
|           fakeAsync(() => {
 | |
|             setInterval(() => {}, 10);
 | |
|           })();
 | |
|         }).toThrowError('1 periodic timer(s) still in the queue.');
 | |
|       });
 | |
| 
 | |
|       it('should run periodic timers', fakeAsync(() => {
 | |
|            let cycles = 0;
 | |
|            const id = setInterval(() => {
 | |
|              cycles++;
 | |
|            }, 10);
 | |
| 
 | |
|            tick(10);
 | |
|            expect(cycles).toEqual(1);
 | |
| 
 | |
|            tick(10);
 | |
|            expect(cycles).toEqual(2);
 | |
| 
 | |
|            tick(10);
 | |
|            expect(cycles).toEqual(3);
 | |
|            clearInterval(id);
 | |
|          }));
 | |
| 
 | |
|       it('should not run cancelled periodic timer', fakeAsync(() => {
 | |
|            let ran = false;
 | |
|            const id = setInterval(() => {
 | |
|              ran = true;
 | |
|            }, 10);
 | |
|            clearInterval(id);
 | |
| 
 | |
|            tick(10);
 | |
|            expect(ran).toEqual(false);
 | |
|          }));
 | |
| 
 | |
|       it('should be able to cancel periodic timers from a callback', fakeAsync(() => {
 | |
|            let cycles = 0;
 | |
|            let id: any /** TODO #9100 */;
 | |
| 
 | |
|            id = setInterval(() => {
 | |
|              cycles++;
 | |
|              clearInterval(id);
 | |
|            }, 10);
 | |
| 
 | |
|            tick(10);
 | |
|            expect(cycles).toEqual(1);
 | |
| 
 | |
|            tick(10);
 | |
|            expect(cycles).toEqual(1);
 | |
|          }));
 | |
| 
 | |
|       it('should clear periodic timers', fakeAsync(() => {
 | |
|            let cycles = 0;
 | |
|            const id = setInterval(() => {
 | |
|              cycles++;
 | |
|            }, 10);
 | |
| 
 | |
|            tick(10);
 | |
|            expect(cycles).toEqual(1);
 | |
| 
 | |
|            discardPeriodicTasks();
 | |
| 
 | |
|            // Tick once to clear out the timer which already started.
 | |
|            tick(10);
 | |
|            expect(cycles).toEqual(2);
 | |
| 
 | |
|            tick(10);
 | |
|            // Nothing should change
 | |
|            expect(cycles).toEqual(2);
 | |
|          }));
 | |
| 
 | |
|       it('should process microtasks before timers', fakeAsync(() => {
 | |
|            const log = new Log();
 | |
| 
 | |
|            resolvedPromise.then((_) => log.add('microtask'));
 | |
| 
 | |
|            setTimeout(() => log.add('timer'), 9);
 | |
| 
 | |
|            const id = setInterval(() => log.add('periodic timer'), 10);
 | |
| 
 | |
|            expect(log.result()).toEqual('');
 | |
| 
 | |
|            tick(10);
 | |
|            expect(log.result()).toEqual('microtask; timer; periodic timer');
 | |
|            clearInterval(id);
 | |
|          }));
 | |
| 
 | |
|       it('should process micro-tasks created in timers before next timers', fakeAsync(() => {
 | |
|            const log = new Log();
 | |
| 
 | |
|            resolvedPromise.then((_) => log.add('microtask'));
 | |
| 
 | |
|            setTimeout(() => {
 | |
|              log.add('timer');
 | |
|              resolvedPromise.then((_) => log.add('t microtask'));
 | |
|            }, 9);
 | |
| 
 | |
|            const id = setInterval(() => {
 | |
|              log.add('periodic timer');
 | |
|              resolvedPromise.then((_) => log.add('pt microtask'));
 | |
|            }, 10);
 | |
| 
 | |
|            tick(10);
 | |
|            expect(log.result())
 | |
|                .toEqual('microtask; timer; t microtask; periodic timer; pt microtask');
 | |
| 
 | |
|            tick(10);
 | |
|            expect(log.result())
 | |
|                .toEqual(
 | |
|                    'microtask; timer; t microtask; periodic timer; pt microtask; periodic timer; pt microtask');
 | |
|            clearInterval(id);
 | |
|          }));
 | |
| 
 | |
|       it('should flush tasks', fakeAsync(() => {
 | |
|            let ran = false;
 | |
|            setTimeout(() => {
 | |
|              ran = true;
 | |
|            }, 10);
 | |
| 
 | |
|            flush();
 | |
|            expect(ran).toEqual(true);
 | |
|          }));
 | |
| 
 | |
|       it('should flush multiple tasks', fakeAsync(() => {
 | |
|            let ran = false;
 | |
|            let ran2 = false;
 | |
|            setTimeout(() => {
 | |
|              ran = true;
 | |
|            }, 10);
 | |
|            setTimeout(() => {
 | |
|              ran2 = true;
 | |
|            }, 30);
 | |
| 
 | |
|            let elapsed = flush();
 | |
| 
 | |
|            expect(ran).toEqual(true);
 | |
|            expect(ran2).toEqual(true);
 | |
|            expect(elapsed).toEqual(30);
 | |
|          }));
 | |
| 
 | |
|       it('should move periodic tasks', fakeAsync(() => {
 | |
|            let ran = false;
 | |
|            let count = 0;
 | |
|            setInterval(() => {
 | |
|              count++;
 | |
|            }, 10);
 | |
|            setTimeout(() => {
 | |
|              ran = true;
 | |
|            }, 35);
 | |
| 
 | |
|            let elapsed = flush();
 | |
| 
 | |
|            expect(count).toEqual(3);
 | |
|            expect(ran).toEqual(true);
 | |
|            expect(elapsed).toEqual(35);
 | |
| 
 | |
|            discardPeriodicTasks();
 | |
|          }));
 | |
|     });
 | |
| 
 | |
|     describe('outside of the fakeAsync zone', () => {
 | |
|       it('calling flushMicrotasks should throw', () => {
 | |
|         expect(() => {
 | |
|           flushMicrotasks();
 | |
|         }).toThrowError('The code should be running in the fakeAsync zone to call this function');
 | |
|       });
 | |
| 
 | |
|       it('calling tick should throw', () => {
 | |
|         expect(() => {
 | |
|           tick();
 | |
|         }).toThrowError('The code should be running in the fakeAsync zone to call this function');
 | |
|       });
 | |
| 
 | |
|       it('calling flush should throw', () => {
 | |
|         expect(() => {
 | |
|           flush();
 | |
|         }).toThrowError('The code should be running in the fakeAsync zone to call this function');
 | |
|       });
 | |
| 
 | |
|       it('calling discardPeriodicTasks should throw', () => {
 | |
|         expect(() => {
 | |
|           discardPeriodicTasks();
 | |
|         }).toThrowError('The code should be running in the fakeAsync zone to call this function');
 | |
|       });
 | |
|     });
 | |
| 
 | |
|     describe('only one `fakeAsync` zone per test', () => {
 | |
|       let zoneInBeforeEach: Zone;
 | |
|       let zoneInTest1: Zone;
 | |
|       beforeEach(fakeAsync(() => {
 | |
|         zoneInBeforeEach = Zone.current;
 | |
|       }));
 | |
| 
 | |
|       it('should use the same zone as in beforeEach', fakeAsync(() => {
 | |
|            zoneInTest1 = Zone.current;
 | |
|            expect(zoneInTest1).toBe(zoneInBeforeEach);
 | |
|          }));
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   describe('ProxyZone', () => {
 | |
|     beforeEach(() => {
 | |
|       ProxyZoneSpec.assertPresent();
 | |
|     });
 | |
| 
 | |
|     afterEach(() => {
 | |
|       ProxyZoneSpec.assertPresent();
 | |
|     });
 | |
| 
 | |
|     it('should allow fakeAsync zone to retroactively set a zoneSpec outside of fakeAsync', () => {
 | |
|       ProxyZoneSpec.assertPresent();
 | |
|       let state: string = 'not run';
 | |
|       const testZone = Zone.current.fork({name: 'test-zone'});
 | |
|       (fakeAsync(() => {
 | |
|         testZone.run(() => {
 | |
|           Promise.resolve('works').then((v) => state = v);
 | |
|           expect(state).toEqual('not run');
 | |
|           flushMicrotasks();
 | |
|           expect(state).toEqual('works');
 | |
|         });
 | |
|       }))();
 | |
|       expect(state).toEqual('works');
 | |
|     });
 | |
|   });
 | |
| }
 |