/** * @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 */ describe('ProxySpec', () => { let ProxyZoneSpec: any; let delegate: ZoneSpec; let proxyZoneSpec: any; let proxyZone: Zone; beforeEach(() => { ProxyZoneSpec = (Zone as any)['ProxyZoneSpec']; expect(typeof ProxyZoneSpec).toBe('function'); delegate = {name: 'delegate'}; proxyZoneSpec = new ProxyZoneSpec(delegate); proxyZone = Zone.current.fork(proxyZoneSpec); }); describe('properties', () => { it('should expose ProxyZone in the properties', () => { expect(proxyZone.get('ProxyZoneSpec')).toBe(proxyZoneSpec); }); it('should assert that it is in or out of ProxyZone', () => { let rootZone = Zone.current; while (rootZone.parent) { rootZone = rootZone.parent; } rootZone.run(() => { expect(() => ProxyZoneSpec.assertPresent()).toThrow(); expect(ProxyZoneSpec.isLoaded()).toBe(false); expect(ProxyZoneSpec.get()).toBe(undefined); proxyZone.run(() => { expect(ProxyZoneSpec.isLoaded()).toBe(true); expect(() => ProxyZoneSpec.assertPresent()).not.toThrow(); expect(ProxyZoneSpec.get()).toBe(proxyZoneSpec); }); }); }); it('should reset properties', () => { expect(proxyZone.get('myTestKey')).toBe(undefined); proxyZoneSpec.setDelegate({name: 'd1', properties: {'myTestKey': 'myTestValue'}}); expect(proxyZone.get('myTestKey')).toBe('myTestValue'); proxyZoneSpec.resetDelegate(); expect(proxyZone.get('myTestKey')).toBe(undefined); }); }); describe('delegate', () => { it('should set/reset delegate', () => { const defaultDelegate: ZoneSpec = {name: 'defaultDelegate'}; const otherDelegate: ZoneSpec = {name: 'otherDelegate'}; const proxyZoneSpec = new ProxyZoneSpec(defaultDelegate); const proxyZone = Zone.current.fork(proxyZoneSpec); expect(proxyZoneSpec.getDelegate()).toEqual(defaultDelegate); proxyZoneSpec.setDelegate(otherDelegate); expect(proxyZoneSpec.getDelegate()).toEqual(otherDelegate); proxyZoneSpec.resetDelegate(); expect(proxyZoneSpec.getDelegate()).toEqual(defaultDelegate); }); }); describe('forwarding', () => { beforeEach(() => { proxyZoneSpec = new ProxyZoneSpec(); proxyZone = Zone.current.fork(proxyZoneSpec); }); it('should fork', () => { const forkedZone = proxyZone.fork({name: 'fork'}); expect(forkedZone).not.toBe(proxyZone); expect(forkedZone.name).toBe('fork'); let called = false; proxyZoneSpec.setDelegate({ name: '.', onFork: (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, zoneSpec: ZoneSpec) => { expect(currentZone).toBe(proxyZone); expect(targetZone).toBe(proxyZone), expect(zoneSpec.name).toBe('fork2'); called = true; } }); proxyZone.fork({name: 'fork2'}); expect(called).toBe(true); }); it('should intercept', () => { const fn = (a: any) => a; expect(proxyZone.wrap(fn, 'test')('works')).toEqual('works'); proxyZoneSpec.setDelegate({ name: '.', onIntercept: (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, delegate: Function, source: string): Function => { return () => '(works)'; } }); expect(proxyZone.wrap(fn, 'test')('works')).toEqual('(works)'); }); it('should invoke', () => { const fn = () => 'works'; expect(proxyZone.run(fn)).toEqual('works'); proxyZoneSpec.setDelegate({ name: '.', onInvoke: (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, delegate: Function, applyThis: any, applyArgs: any[], source: string) => { return `(${ parentZoneDelegate.invoke(targetZone, delegate, applyThis, applyArgs, source)})`; } }); expect(proxyZone.run(fn)).toEqual('(works)'); }); it('should handleError', () => { const error = new Error('TestError'); const fn = () => { throw error; }; expect(() => proxyZone.run(fn)).toThrow(error); proxyZoneSpec.setDelegate({ name: '.', onHandleError: (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, error: any): boolean => { expect(error).toEqual(error); return false; } }); expect(() => proxyZone.runGuarded(fn)).not.toThrow(); }); it('should Task', () => { const fn = (): any => null; const task = proxyZone.scheduleMacroTask('test', fn, {}, () => null, () => null); expect(task.source).toEqual('test'); proxyZone.cancelTask(task); }); }); describe('delegateSpec change', () => { let log: string[] = []; beforeEach(() => { log = []; }); it('should trigger hasTask when invoke', (done: Function) => { const zoneSpec1 = { name: 'zone1', onHasTask: (delegate: ZoneDelegate, curr: Zone, target: Zone, hasTask: HasTaskState) => { log.push(`zoneSpec1 hasTask: ${hasTask.microTask},${hasTask.macroTask}`); return delegate.hasTask(target, hasTask); } }; const zoneSpec2 = { name: 'zone2', onHasTask: (delegate: ZoneDelegate, curr: Zone, target: Zone, hasTask: HasTaskState) => { log.push(`zoneSpec2 hasTask: ${hasTask.microTask},${hasTask.macroTask}`); return delegate.hasTask(target, hasTask); } }; proxyZoneSpec.setDelegate(zoneSpec1); proxyZone.run(() => { setTimeout(() => { log.push('timeout in zoneSpec1'); }, 50); }); proxyZoneSpec.setDelegate(zoneSpec2); proxyZone.run(() => { Promise.resolve(1).then(() => { log.push('then in zoneSpec2'); }); }); proxyZoneSpec.setDelegate(null); proxyZone.run(() => { setTimeout(() => { log.push('timeout in null spec'); }, 50); }); proxyZoneSpec.setDelegate(zoneSpec2); proxyZone.run(() => { Promise.resolve(1).then(() => { log.push('then in zoneSpec2'); }); }); setTimeout(() => { expect(log).toEqual([ 'zoneSpec1 hasTask: false,true', 'zoneSpec2 hasTask: false,true', 'zoneSpec2 hasTask: true,true', 'zoneSpec2 hasTask: true,true', 'then in zoneSpec2', 'then in zoneSpec2', 'zoneSpec2 hasTask: false,true', 'timeout in zoneSpec1', 'timeout in null spec', 'zoneSpec2 hasTask: false,false' ]); done(); }, 300); }); }); });