The API changes are due to enabling strict checks in TypeScript (via `strict: true`). The payload size changes in `polyfills.js` are due to more browser APIs being patched in recent versions (e.g. `fetch`, `customElement v1`). PR Close #28219
		
			
				
	
	
		
			384 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			384 lines
		
	
	
		
			13 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 {EventEmitter} from '@angular/core';
 | 
						|
import {Injectable} from '@angular/core/src/di';
 | 
						|
import {PendingMacrotask, Testability, TestabilityRegistry} from '@angular/core/src/testability/testability';
 | 
						|
import {NgZone} from '@angular/core/src/zone/ng_zone';
 | 
						|
import {async, fakeAsync, flush, tick} from '@angular/core/testing';
 | 
						|
import {SpyObject, beforeEach, describe, expect, it} from '@angular/core/testing/src/testing_internal';
 | 
						|
 | 
						|
import {scheduleMicroTask} from '../../src/util/microtask';
 | 
						|
 | 
						|
// Schedules a microtasks (using a resolved promise .then())
 | 
						|
function microTask(fn: Function): void {
 | 
						|
  scheduleMicroTask(() => {
 | 
						|
    // We do double dispatch so that we  can wait for scheduleMicrotask in the Testability when
 | 
						|
    // NgZone becomes stable.
 | 
						|
    scheduleMicroTask(fn);
 | 
						|
  });
 | 
						|
}
 | 
						|
 | 
						|
@Injectable()
 | 
						|
class MockNgZone extends NgZone {
 | 
						|
  /** @internal */
 | 
						|
  onUnstable: EventEmitter<any>;
 | 
						|
 | 
						|
  /** @internal */
 | 
						|
  onStable: EventEmitter<any>;
 | 
						|
 | 
						|
  constructor() {
 | 
						|
    super({enableLongStackTrace: false});
 | 
						|
    this.onUnstable = new EventEmitter(false);
 | 
						|
    this.onStable = new EventEmitter(false);
 | 
						|
  }
 | 
						|
 | 
						|
  unstable(): void { this.onUnstable.emit(null); }
 | 
						|
 | 
						|
  stable(): void { this.onStable.emit(null); }
 | 
						|
}
 | 
						|
 | 
						|
{
 | 
						|
  describe('Testability', () => {
 | 
						|
    let testability: Testability;
 | 
						|
    let execute: any;
 | 
						|
    let execute2: any;
 | 
						|
    let updateCallback: any;
 | 
						|
    let ngZone: MockNgZone;
 | 
						|
 | 
						|
    beforeEach(async(() => {
 | 
						|
      ngZone = new MockNgZone();
 | 
						|
      testability = new Testability(ngZone);
 | 
						|
      execute = new SpyObject().spy('execute');
 | 
						|
      execute2 = new SpyObject().spy('execute');
 | 
						|
      updateCallback = new SpyObject().spy('execute');
 | 
						|
    }));
 | 
						|
 | 
						|
    describe('Pending count logic', () => {
 | 
						|
      it('should start with a pending count of 0',
 | 
						|
         () => { expect(testability.getPendingRequestCount()).toEqual(0); });
 | 
						|
 | 
						|
      it('should fire whenstable callbacks if pending count is 0', async(() => {
 | 
						|
           testability.whenStable(execute);
 | 
						|
 | 
						|
           microTask(() => { expect(execute).toHaveBeenCalled(); });
 | 
						|
         }));
 | 
						|
 | 
						|
      it('should not fire whenstable callbacks synchronously if pending count is 0', () => {
 | 
						|
        testability.whenStable(execute);
 | 
						|
        expect(execute).not.toHaveBeenCalled();
 | 
						|
      });
 | 
						|
 | 
						|
      it('should not call whenstable callbacks when there are pending counts', async(() => {
 | 
						|
           testability.increasePendingRequestCount();
 | 
						|
           testability.increasePendingRequestCount();
 | 
						|
           testability.whenStable(execute);
 | 
						|
 | 
						|
           microTask(() => {
 | 
						|
             expect(execute).not.toHaveBeenCalled();
 | 
						|
             testability.decreasePendingRequestCount();
 | 
						|
 | 
						|
             microTask(() => { expect(execute).not.toHaveBeenCalled(); });
 | 
						|
           });
 | 
						|
         }));
 | 
						|
 | 
						|
      it('should fire whenstable callbacks when pending drops to 0', async(() => {
 | 
						|
           testability.increasePendingRequestCount();
 | 
						|
           testability.whenStable(execute);
 | 
						|
 | 
						|
           microTask(() => {
 | 
						|
             expect(execute).not.toHaveBeenCalled();
 | 
						|
             testability.decreasePendingRequestCount();
 | 
						|
 | 
						|
             microTask(() => { expect(execute).toHaveBeenCalled(); });
 | 
						|
           });
 | 
						|
         }));
 | 
						|
 | 
						|
      it('should not fire whenstable callbacks synchronously when pending drops to 0', async(() => {
 | 
						|
           testability.increasePendingRequestCount();
 | 
						|
           testability.whenStable(execute);
 | 
						|
           testability.decreasePendingRequestCount();
 | 
						|
 | 
						|
           expect(execute).not.toHaveBeenCalled();
 | 
						|
         }));
 | 
						|
 | 
						|
      it('should fire whenstable callbacks with didWork if pending count is 0', async(() => {
 | 
						|
           microTask(() => {
 | 
						|
             testability.whenStable(execute);
 | 
						|
 | 
						|
             microTask(() => { expect(execute).toHaveBeenCalledWith(false); });
 | 
						|
           });
 | 
						|
         }));
 | 
						|
 | 
						|
      it('should fire whenstable callbacks with didWork when pending drops to 0', async(() => {
 | 
						|
           testability.increasePendingRequestCount();
 | 
						|
           testability.whenStable(execute);
 | 
						|
 | 
						|
           testability.decreasePendingRequestCount();
 | 
						|
 | 
						|
           microTask(() => {
 | 
						|
             expect(execute).toHaveBeenCalledWith(true);
 | 
						|
             testability.whenStable(execute2);
 | 
						|
 | 
						|
             microTask(() => { expect(execute2).toHaveBeenCalledWith(false); });
 | 
						|
           });
 | 
						|
         }));
 | 
						|
 | 
						|
    });
 | 
						|
 | 
						|
    describe('NgZone callback logic', () => {
 | 
						|
      describe('whenStable with timeout', () => {
 | 
						|
        it('should list pending tasks when the timeout is hit', fakeAsync(() => {
 | 
						|
             const id = ngZone.run(() => setTimeout(() => {}, 1000));
 | 
						|
             testability.whenStable(execute, 200);
 | 
						|
 | 
						|
             expect(execute).not.toHaveBeenCalled();
 | 
						|
             tick(200);
 | 
						|
             expect(execute).toHaveBeenCalled();
 | 
						|
             const tasks = execute.calls.mostRecent().args[1] as PendingMacrotask[];
 | 
						|
 | 
						|
             expect(tasks.length).toEqual(1);
 | 
						|
             expect(tasks[0].data).toBeTruthy();
 | 
						|
             expect(tasks[0].data !.delay).toEqual(1000);
 | 
						|
             expect(tasks[0].source).toEqual('setTimeout');
 | 
						|
             expect(tasks[0].data !.isPeriodic).toEqual(false);
 | 
						|
 | 
						|
             clearTimeout(id);
 | 
						|
           }));
 | 
						|
 | 
						|
        it('should fire if Angular is already stable', async(() => {
 | 
						|
             testability.whenStable(execute, 200);
 | 
						|
 | 
						|
             microTask(() => { expect(execute).toHaveBeenCalled(); });
 | 
						|
           }));
 | 
						|
 | 
						|
        it('should fire when macroTasks are cancelled', fakeAsync(() => {
 | 
						|
             const id = ngZone.run(() => setTimeout(() => {}, 1000));
 | 
						|
             testability.whenStable(execute, 500);
 | 
						|
 | 
						|
             tick(200);
 | 
						|
             ngZone.run(() => clearTimeout(id));
 | 
						|
             // fakeAsync doesn't trigger NgZones whenStable
 | 
						|
             ngZone.stable();
 | 
						|
 | 
						|
             tick(1);
 | 
						|
             expect(execute).toHaveBeenCalled();
 | 
						|
           }));
 | 
						|
 | 
						|
        it('calls the done callback when angular is stable', fakeAsync(() => {
 | 
						|
             let timeout1Done = false;
 | 
						|
             ngZone.run(() => setTimeout(() => timeout1Done = true, 500));
 | 
						|
             testability.whenStable(execute, 1000);
 | 
						|
 | 
						|
             tick(600);
 | 
						|
             ngZone.stable();
 | 
						|
             tick();
 | 
						|
 | 
						|
             expect(timeout1Done).toEqual(true);
 | 
						|
             expect(execute).toHaveBeenCalled();
 | 
						|
 | 
						|
             // Should cancel the done timeout.
 | 
						|
             tick(500);
 | 
						|
             ngZone.stable();
 | 
						|
             tick();
 | 
						|
             expect(execute.calls.count()).toEqual(1);
 | 
						|
           }));
 | 
						|
 | 
						|
 | 
						|
        it('calls update when macro tasks change', fakeAsync(() => {
 | 
						|
             let timeout1Done = false;
 | 
						|
             let timeout2Done = false;
 | 
						|
             ngZone.run(() => setTimeout(() => timeout1Done = true, 500));
 | 
						|
             tick();
 | 
						|
             testability.whenStable(execute, 1000, updateCallback);
 | 
						|
 | 
						|
             tick(100);
 | 
						|
             ngZone.run(() => setTimeout(() => timeout2Done = true, 300));
 | 
						|
             expect(updateCallback.calls.count()).toEqual(1);
 | 
						|
             tick(600);
 | 
						|
 | 
						|
             expect(timeout1Done).toEqual(true);
 | 
						|
             expect(timeout2Done).toEqual(true);
 | 
						|
             expect(updateCallback.calls.count()).toEqual(3);
 | 
						|
             expect(execute).toHaveBeenCalled();
 | 
						|
 | 
						|
             const update1 = updateCallback.calls.all()[0].args[0] as PendingMacrotask[];
 | 
						|
             expect(update1[0].data !.delay).toEqual(500);
 | 
						|
 | 
						|
             const update2 = updateCallback.calls.all()[1].args[0] as PendingMacrotask[];
 | 
						|
             expect(update2[0].data !.delay).toEqual(500);
 | 
						|
             expect(update2[1].data !.delay).toEqual(300);
 | 
						|
           }));
 | 
						|
 | 
						|
        it('cancels the done callback if the update callback returns true', fakeAsync(() => {
 | 
						|
             let timeoutDone = false;
 | 
						|
             ngZone.unstable();
 | 
						|
             execute2.and.returnValue(true);
 | 
						|
             testability.whenStable(execute, 1000, execute2);
 | 
						|
 | 
						|
             tick(100);
 | 
						|
             ngZone.run(() => setTimeout(() => timeoutDone = true, 500));
 | 
						|
             ngZone.stable();
 | 
						|
             expect(execute2).toHaveBeenCalled();
 | 
						|
 | 
						|
             tick(500);
 | 
						|
             ngZone.stable();
 | 
						|
             tick();
 | 
						|
 | 
						|
             expect(execute).not.toHaveBeenCalled();
 | 
						|
           }));
 | 
						|
      });
 | 
						|
 | 
						|
      it('should fire whenstable callback if event is already finished', fakeAsync(() => {
 | 
						|
           ngZone.unstable();
 | 
						|
           ngZone.stable();
 | 
						|
           testability.whenStable(execute);
 | 
						|
 | 
						|
           tick();
 | 
						|
           expect(execute).toHaveBeenCalled();
 | 
						|
         }));
 | 
						|
 | 
						|
      it('should not fire whenstable callbacks synchronously if event is already finished', () => {
 | 
						|
        ngZone.unstable();
 | 
						|
        ngZone.stable();
 | 
						|
        testability.whenStable(execute);
 | 
						|
 | 
						|
        expect(execute).not.toHaveBeenCalled();
 | 
						|
      });
 | 
						|
 | 
						|
      it('should fire whenstable callback when event finishes', fakeAsync(() => {
 | 
						|
           ngZone.unstable();
 | 
						|
           testability.whenStable(execute);
 | 
						|
 | 
						|
           tick();
 | 
						|
           expect(execute).not.toHaveBeenCalled();
 | 
						|
           ngZone.stable();
 | 
						|
 | 
						|
           tick();
 | 
						|
           expect(execute).toHaveBeenCalled();
 | 
						|
         }));
 | 
						|
 | 
						|
      it('should not fire whenstable callbacks synchronously when event finishes', () => {
 | 
						|
        ngZone.unstable();
 | 
						|
        testability.whenStable(execute);
 | 
						|
        ngZone.stable();
 | 
						|
 | 
						|
        expect(execute).not.toHaveBeenCalled();
 | 
						|
      });
 | 
						|
 | 
						|
      it('should not fire whenstable callback when event did not finish', fakeAsync(() => {
 | 
						|
           ngZone.unstable();
 | 
						|
           testability.increasePendingRequestCount();
 | 
						|
           testability.whenStable(execute);
 | 
						|
 | 
						|
           tick();
 | 
						|
           expect(execute).not.toHaveBeenCalled();
 | 
						|
           testability.decreasePendingRequestCount();
 | 
						|
 | 
						|
           tick();
 | 
						|
           expect(execute).not.toHaveBeenCalled();
 | 
						|
           ngZone.stable();
 | 
						|
 | 
						|
           tick();
 | 
						|
           expect(execute).toHaveBeenCalled();
 | 
						|
         }));
 | 
						|
 | 
						|
      it('should not fire whenstable callback when there are pending counts', fakeAsync(() => {
 | 
						|
           ngZone.unstable();
 | 
						|
           testability.increasePendingRequestCount();
 | 
						|
           testability.increasePendingRequestCount();
 | 
						|
           testability.whenStable(execute);
 | 
						|
 | 
						|
           tick();
 | 
						|
           expect(execute).not.toHaveBeenCalled();
 | 
						|
           ngZone.stable();
 | 
						|
 | 
						|
           tick();
 | 
						|
           expect(execute).not.toHaveBeenCalled();
 | 
						|
           testability.decreasePendingRequestCount();
 | 
						|
 | 
						|
           tick();
 | 
						|
           expect(execute).not.toHaveBeenCalled();
 | 
						|
           testability.decreasePendingRequestCount();
 | 
						|
 | 
						|
           tick();
 | 
						|
           expect(execute).toHaveBeenCalled();
 | 
						|
         }));
 | 
						|
 | 
						|
      it('should fire whenstable callback with didWork if event is already finished',
 | 
						|
         fakeAsync(() => {
 | 
						|
           ngZone.unstable();
 | 
						|
           ngZone.stable();
 | 
						|
           testability.whenStable(execute);
 | 
						|
 | 
						|
           tick();
 | 
						|
           expect(execute).toHaveBeenCalledWith(true);
 | 
						|
           testability.whenStable(execute2);
 | 
						|
 | 
						|
           tick();
 | 
						|
           expect(execute2).toHaveBeenCalledWith(false);
 | 
						|
         }));
 | 
						|
 | 
						|
      it('should fire whenstable callback with didwork when event finishes', fakeAsync(() => {
 | 
						|
           ngZone.unstable();
 | 
						|
           testability.whenStable(execute);
 | 
						|
 | 
						|
           tick();
 | 
						|
           ngZone.stable();
 | 
						|
 | 
						|
           tick();
 | 
						|
           expect(execute).toHaveBeenCalledWith(true);
 | 
						|
           testability.whenStable(execute2);
 | 
						|
 | 
						|
           tick();
 | 
						|
           expect(execute2).toHaveBeenCalledWith(false);
 | 
						|
         }));
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('TestabilityRegistry', () => {
 | 
						|
    let testability1: Testability;
 | 
						|
    let testability2: Testability;
 | 
						|
    let registry: TestabilityRegistry;
 | 
						|
    let ngZone: MockNgZone;
 | 
						|
 | 
						|
    beforeEach(async(() => {
 | 
						|
      ngZone = new MockNgZone();
 | 
						|
      testability1 = new Testability(ngZone);
 | 
						|
      testability2 = new Testability(ngZone);
 | 
						|
      registry = new TestabilityRegistry();
 | 
						|
    }));
 | 
						|
    describe('unregister testability', () => {
 | 
						|
      it('should remove the testability when unregistering an existing testability', () => {
 | 
						|
        registry.registerApplication('testability1', testability1);
 | 
						|
        registry.registerApplication('testability2', testability2);
 | 
						|
        registry.unregisterApplication('testability2');
 | 
						|
        expect(registry.getAllTestabilities().length).toEqual(1);
 | 
						|
        expect(registry.getTestability('testability1')).toEqual(testability1);
 | 
						|
      });
 | 
						|
 | 
						|
      it('should remain the same when unregistering a non-existing testability', () => {
 | 
						|
        expect(registry.getAllTestabilities().length).toEqual(0);
 | 
						|
        registry.registerApplication('testability1', testability1);
 | 
						|
        registry.registerApplication('testability2', testability2);
 | 
						|
        registry.unregisterApplication('testability3');
 | 
						|
        expect(registry.getAllTestabilities().length).toEqual(2);
 | 
						|
        expect(registry.getTestability('testability1')).toEqual(testability1);
 | 
						|
        expect(registry.getTestability('testability2')).toEqual(testability2);
 | 
						|
      });
 | 
						|
 | 
						|
      it('should remove all the testability when unregistering all testabilities', () => {
 | 
						|
        registry.registerApplication('testability1', testability1);
 | 
						|
        registry.registerApplication('testability2', testability2);
 | 
						|
        registry.unregisterAllApplications();
 | 
						|
        expect(registry.getAllTestabilities().length).toEqual(0);
 | 
						|
      });
 | 
						|
    });
 | 
						|
  });
 | 
						|
}
 |