build: move zone.js to angular repo (#30962)

PR Close #30962
This commit is contained in:
JiaLiPassion
2019-06-01 00:56:07 +09:00
committed by Kara Erickson
parent 7b3bcc23af
commit 5eb7426216
271 changed files with 30890 additions and 19 deletions

View File

@ -0,0 +1,413 @@
/**
* @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} from '../test-util';
describe('AsyncTestZoneSpec', function() {
let log: string[];
const AsyncTestZoneSpec = (Zone as any)['AsyncTestZoneSpec'];
function finishCallback() { log.push('finish'); }
function failCallback() { log.push('fail'); }
beforeEach(() => { log = []; });
it('should call finish after zone is run in sync call', (done) => {
let finished = false;
const testZoneSpec = new AsyncTestZoneSpec(() => {
expect(finished).toBe(true);
done();
}, failCallback, 'name');
const atz = Zone.current.fork(testZoneSpec);
atz.run(function() { finished = true; });
});
it('should call finish after a setTimeout is done', (done) => {
let finished = false;
const testZoneSpec = new AsyncTestZoneSpec(
() => {
expect(finished).toBe(true);
done();
},
() => { done.fail('async zone called failCallback unexpectedly'); }, 'name');
const atz = Zone.current.fork(testZoneSpec);
atz.run(function() { setTimeout(() => { finished = true; }, 10); });
});
it('should call finish after microtasks are done', (done) => {
let finished = false;
const testZoneSpec = new AsyncTestZoneSpec(
() => {
expect(finished).toBe(true);
done();
},
() => { done.fail('async zone called failCallback unexpectedly'); }, 'name');
const atz = Zone.current.fork(testZoneSpec);
atz.run(function() { Promise.resolve().then(() => { finished = true; }); });
});
it('should call finish after both micro and macrotasks are done', (done) => {
let finished = false;
const testZoneSpec = new AsyncTestZoneSpec(
() => {
expect(finished).toBe(true);
done();
},
() => { done.fail('async zone called failCallback unexpectedly'); }, 'name');
const atz = Zone.current.fork(testZoneSpec);
atz.run(function() {
new Promise((resolve) => { setTimeout(() => { resolve(); }, 10); }).then(() => {
finished = true;
});
});
});
it('should call finish after both macro and microtasks are done', (done) => {
let finished = false;
const testZoneSpec = new AsyncTestZoneSpec(
() => {
expect(finished).toBe(true);
done();
},
() => { done.fail('async zone called failCallback unexpectedly'); }, 'name');
const atz = Zone.current.fork(testZoneSpec);
atz.run(function() {
Promise.resolve().then(() => { setTimeout(() => { finished = true; }, 10); });
});
});
describe('event tasks', ifEnvSupports('document', () => {
let button: HTMLButtonElement;
beforeEach(function() {
button = document.createElement('button');
document.body.appendChild(button);
});
afterEach(function() { document.body.removeChild(button); });
it('should call finish because an event task is considered as sync', (done) => {
let finished = false;
const testZoneSpec = new AsyncTestZoneSpec(
() => {
expect(finished).toBe(true);
done();
},
() => { done.fail('async zone called failCallback unexpectedly'); }, 'name');
const atz = Zone.current.fork(testZoneSpec);
atz.run(function() {
const listener = () => { finished = true; };
button.addEventListener('click', listener);
const clickEvent = document.createEvent('Event');
clickEvent.initEvent('click', true, true);
button.dispatchEvent(clickEvent);
});
});
it('should call finish after an event task is done asynchronously', (done) => {
let finished = false;
const testZoneSpec = new AsyncTestZoneSpec(
() => {
expect(finished).toBe(true);
done();
},
() => { done.fail('async zone called failCallback unexpectedly'); }, 'name');
const atz = Zone.current.fork(testZoneSpec);
atz.run(function() {
button.addEventListener(
'click', () => { setTimeout(() => { finished = true; }, 10); });
const clickEvent = document.createEvent('Event');
clickEvent.initEvent('click', true, true);
button.dispatchEvent(clickEvent);
});
});
}));
describe('XHRs', ifEnvSupports('XMLHttpRequest', () => {
it('should wait for XHRs to complete', function(done) {
let req: XMLHttpRequest;
let finished = false;
const testZoneSpec = new AsyncTestZoneSpec(
() => {
expect(finished).toBe(true);
done();
},
(err: Error) => { done.fail('async zone called failCallback unexpectedly'); },
'name');
const atz = Zone.current.fork(testZoneSpec);
atz.run(function() {
req = new XMLHttpRequest();
req.onreadystatechange = () => {
if (req.readyState === XMLHttpRequest.DONE) {
finished = true;
}
};
req.open('get', '/', true);
req.send();
});
});
it('should fail if an xhr fails', function(done) {
let req: XMLHttpRequest;
const testZoneSpec = new AsyncTestZoneSpec(
() => { done.fail('expected failCallback to be called'); },
(err: Error) => {
expect(err.message).toEqual('bad url failure');
done();
},
'name');
const atz = Zone.current.fork(testZoneSpec);
atz.run(function() {
req = new XMLHttpRequest();
req.onload = () => {
if (req.status != 200) {
throw new Error('bad url failure');
}
};
req.open('get', '/bad-url', true);
req.send();
});
});
}));
it('should not fail if setInterval is used and canceled', (done) => {
const testZoneSpec = new AsyncTestZoneSpec(
() => { done(); },
(err: Error) => { done.fail('async zone called failCallback unexpectedly'); }, 'name');
const atz = Zone.current.fork(testZoneSpec);
atz.run(function() { let id = setInterval(() => { clearInterval(id); }, 100); });
});
it('should fail if an error is thrown asynchronously', (done) => {
const testZoneSpec = new AsyncTestZoneSpec(
() => { done.fail('expected failCallback to be called'); },
(err: Error) => {
expect(err.message).toEqual('my error');
done();
},
'name');
const atz = Zone.current.fork(testZoneSpec);
atz.run(function() { setTimeout(() => { throw new Error('my error'); }, 10); });
});
it('should fail if a promise rejection is unhandled', (done) => {
const testZoneSpec = new AsyncTestZoneSpec(
() => { done.fail('expected failCallback to be called'); },
(err: Error) => {
expect(err.message).toEqual('Uncaught (in promise): my reason');
done();
},
'name');
const atz = Zone.current.fork(testZoneSpec);
atz.run(function() { Promise.reject('my reason'); });
});
const asyncTest: any = (Zone as any)[Zone.__symbol__('asyncTest')];
function wrapAsyncTest(fn: Function, doneFn?: Function) {
return function(done: Function) {
const asyncWrapper = asyncTest(fn);
return asyncWrapper.apply(this, [function() {
if (doneFn) {
doneFn();
}
return done.apply(this, arguments);
}]);
};
}
describe('async', () => {
describe('non zone aware async task in promise should be detected', () => {
let finished = false;
const _global: any =
typeof window !== 'undefined' && window || typeof self !== 'undefined' && self || global;
beforeEach(() => { _global[Zone.__symbol__('supportWaitUnResolvedChainedPromise')] = true; });
afterEach(() => { _global[Zone.__symbol__('supportWaitUnResolvedChainedPromise')] = false; });
it('should be able to detect non zone aware async task in promise',
wrapAsyncTest(
() => {
new Promise((res, rej) => {
const g: any = typeof window === 'undefined' ? global : window;
g[Zone.__symbol__('setTimeout')](res, 100);
}).then(() => { finished = true; });
},
() => { expect(finished).toBe(true); }));
});
describe('test without beforeEach', () => {
const logs: string[] = [];
it('should automatically done after async tasks finished',
wrapAsyncTest(
() => { setTimeout(() => { logs.push('timeout'); }, 100); },
() => {
expect(logs).toEqual(['timeout']);
logs.splice(0);
}));
it('should automatically done after all nested async tasks finished',
wrapAsyncTest(
() => {
setTimeout(() => {
logs.push('timeout');
setTimeout(() => { logs.push('nested timeout'); }, 100);
}, 100);
},
() => {
expect(logs).toEqual(['timeout', 'nested timeout']);
logs.splice(0);
}));
it('should automatically done after multiple async tasks finished',
wrapAsyncTest(
() => {
setTimeout(() => { logs.push('1st timeout'); }, 100);
setTimeout(() => { logs.push('2nd timeout'); }, 100);
},
() => {
expect(logs).toEqual(['1st timeout', '2nd timeout']);
logs.splice(0);
}));
});
describe('test with sync beforeEach', () => {
const logs: string[] = [];
beforeEach(() => {
logs.splice(0);
logs.push('beforeEach');
});
it('should automatically done after async tasks finished',
wrapAsyncTest(
() => { setTimeout(() => { logs.push('timeout'); }, 100); },
() => {
expect(logs).toEqual(['beforeEach', 'timeout']);
}));
});
describe('test with async beforeEach', () => {
const logs: string[] = [];
beforeEach(wrapAsyncTest(() => {
setTimeout(() => {
logs.splice(0);
logs.push('beforeEach');
}, 100);
}));
it('should automatically done after async tasks finished',
wrapAsyncTest(
() => { setTimeout(() => { logs.push('timeout'); }, 100); },
() => {
expect(logs).toEqual(['beforeEach', 'timeout']);
}));
it('should automatically done after all nested async tasks finished',
wrapAsyncTest(
() => {
setTimeout(() => {
logs.push('timeout');
setTimeout(() => { logs.push('nested timeout'); }, 100);
}, 100);
},
() => {
expect(logs).toEqual(['beforeEach', 'timeout', 'nested timeout']);
}));
it('should automatically done after multiple async tasks finished',
wrapAsyncTest(
() => {
setTimeout(() => { logs.push('1st timeout'); }, 100);
setTimeout(() => { logs.push('2nd timeout'); }, 100);
},
() => {
expect(logs).toEqual(['beforeEach', '1st timeout', '2nd timeout']);
}));
});
describe('test with async beforeEach and sync afterEach', () => {
const logs: string[] = [];
beforeEach(wrapAsyncTest(() => {
setTimeout(() => {
expect(logs).toEqual([]);
logs.push('beforeEach');
}, 100);
}));
afterEach(() => { logs.splice(0); });
it('should automatically done after async tasks finished',
wrapAsyncTest(
() => { setTimeout(() => { logs.push('timeout'); }, 100); },
() => {
expect(logs).toEqual(['beforeEach', 'timeout']);
}));
});
describe('test with async beforeEach and async afterEach', () => {
const logs: string[] = [];
beforeEach(wrapAsyncTest(() => {
setTimeout(() => {
expect(logs).toEqual([]);
logs.push('beforeEach');
}, 100);
}));
afterEach(wrapAsyncTest(() => { setTimeout(() => { logs.splice(0); }, 100); }));
it('should automatically done after async tasks finished',
wrapAsyncTest(
() => { setTimeout(() => { logs.push('timeout'); }, 100); },
() => {
expect(logs).toEqual(['beforeEach', 'timeout']);
}));
});
});
});

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,185 @@
/**
* @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 {isBrowser, isIE, zoneSymbol} from '../../lib/common/utils';
import {ifEnvSupports, isSafari, isSupportSetErrorStack} from '../test-util';
const defineProperty = (Object as any)[zoneSymbol('defineProperty')] || Object.defineProperty;
describe(
'longStackTraceZone', ifEnvSupports(isSupportSetErrorStack, function() {
let log: Error[];
let lstz: Zone;
let longStackTraceZoneSpec = (Zone as any)['longStackTraceZoneSpec'];
let defaultTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
beforeEach(function() {
lstz = Zone.current.fork(longStackTraceZoneSpec).fork({
name: 'long-stack-trace-zone-test',
onHandleError: (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone,
error: any): boolean => {
parentZoneDelegate.handleError(targetZone, error);
log.push(error);
return false;
}
});
log = [];
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
});
afterEach(function() { jasmine.DEFAULT_TIMEOUT_INTERVAL = defaultTimeout; });
function expectElapsed(stack: string, expectedCount: number) {
try {
let actualCount = stack.split('_Elapsed_').length;
if (actualCount !== expectedCount) {
expect(actualCount).toEqual(expectedCount);
console.log(stack);
}
} catch (e) {
expect(e).toBe(null);
}
}
it('should produce long stack traces', function(done) {
lstz.run(function() {
setTimeout(function() {
setTimeout(function() {
setTimeout(function() {
expectElapsed(log[0].stack !, 3);
done();
}, 0);
throw new Error('Hello');
}, 0);
}, 0);
});
});
it('should produce long stack traces for optimized eventTask',
ifEnvSupports(() => isBrowser, function() {
lstz.run(function() {
const button = document.createElement('button');
const clickEvent = document.createEvent('Event');
clickEvent.initEvent('click', true, true);
document.body.appendChild(button);
button.addEventListener('click', function() { expectElapsed(log[0].stack !, 1); });
button.dispatchEvent(clickEvent);
document.body.removeChild(button);
});
}));
it('should not overwrite long stack traces data for different optimized eventTasks',
ifEnvSupports(() => isBrowser, function() {
lstz.run(function() {
const button = document.createElement('button');
const clickEvent = document.createEvent('Event');
clickEvent.initEvent('click', true, true);
document.body.appendChild(button);
const div = document.createElement('div');
const enterEvent = document.createEvent('Event');
enterEvent.initEvent('mouseenter', true, true);
document.body.appendChild(div);
button.addEventListener('click', function() { throw new Error('clickError'); });
div.addEventListener('mouseenter', function() { throw new Error('enterError'); });
button.dispatchEvent(clickEvent);
div.dispatchEvent(enterEvent);
expect(log.length).toBe(2);
if (!isSafari() && !isIE()) {
expect(log[0].stack === log[1].stack).toBe(false);
}
document.body.removeChild(button);
document.body.removeChild(div);
});
}));
it('should produce a long stack trace even if stack setter throws', (done) => {
let wasStackAssigned = false;
let error = new Error('Expected error');
defineProperty(error, 'stack', {
configurable: false,
get: () => 'someStackTrace',
set: (v: any) => { throw new Error('no writes'); }
});
lstz.run(() => { setTimeout(() => { throw error; }); });
setTimeout(() => {
const e = log[0];
expect((e as any).longStack).toBeTruthy();
done();
});
});
it('should produce long stack traces when has uncaught error in promise', function(done) {
lstz.runGuarded(function() {
setTimeout(function() {
setTimeout(function() {
let promise = new Promise(function(resolve, reject) {
setTimeout(function() { reject(new Error('Hello Promise')); }, 0);
});
promise.then(function() { fail('should not get here'); });
setTimeout(function() {
expectElapsed(log[0].stack !, 5);
done();
}, 0);
}, 0);
}, 0);
});
});
it('should produce long stack traces when handling error in promise', function(done) {
lstz.runGuarded(function() {
setTimeout(function() {
setTimeout(function() {
let promise = new Promise(function(resolve, reject) {
setTimeout(function() {
try {
throw new Error('Hello Promise');
} catch (err) {
reject(err);
}
}, 0);
});
promise.catch(function(error) {
// should be able to get long stack trace
const longStackFrames: string = longStackTraceZoneSpec.getLongStackTrace(error);
expectElapsed(longStackFrames, 4);
done();
});
}, 0);
}, 0);
});
});
it('should not produce long stack traces if Error.stackTraceLimit = 0', function(done) {
const originalStackTraceLimit = Error.stackTraceLimit;
lstz.run(function() {
setTimeout(function() {
setTimeout(function() {
setTimeout(function() {
if (log[0].stack) {
expectElapsed(log[0].stack !, 1);
}
Error.stackTraceLimit = originalStackTraceLimit;
done();
}, 0);
Error.stackTraceLimit = 0;
throw new Error('Hello');
}, 0);
}, 0);
});
});
}));

View File

@ -0,0 +1,179 @@
/**
* @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);
});
});
});

View File

@ -0,0 +1,57 @@
/**
* @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} from '../test-util';
describe('SyncTestZoneSpec', () => {
const SyncTestZoneSpec = (Zone as any)['SyncTestZoneSpec'];
let testZoneSpec;
let syncTestZone: Zone;
beforeEach(() => {
testZoneSpec = new SyncTestZoneSpec('name');
syncTestZone = Zone.current.fork(testZoneSpec);
});
it('should fail on Promise.then', () => {
syncTestZone.run(() => {
expect(() => {
Promise.resolve().then(function() {});
}).toThrow(new Error('Cannot call Promise.then from within a sync test.'));
});
});
it('should fail on setTimeout', () => {
syncTestZone.run(() => {
expect(() => {
setTimeout(() => {}, 100);
}).toThrow(new Error('Cannot call setTimeout from within a sync test.'));
});
});
describe('event tasks', ifEnvSupports('document', () => {
it('should work with event tasks', () => {
syncTestZone.run(() => {
const button = document.createElement('button');
document.body.appendChild(button);
let x = 1;
try {
button.addEventListener('click', () => { x++; });
button.click();
expect(x).toEqual(2);
button.click();
expect(x).toEqual(3);
} finally {
document.body.removeChild(button);
}
});
});
}));
});

View File

@ -0,0 +1,76 @@
/**
* @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 {supportPatchXHROnProperty} from '../test-util';
declare const global: any;
describe('TaskTrackingZone', function() {
let _TaskTrackingZoneSpec: typeof TaskTrackingZoneSpec = (Zone as any)['TaskTrackingZoneSpec'];
let taskTrackingZoneSpec: TaskTrackingZoneSpec|null = null;
let taskTrackingZone: Zone;
beforeEach(() => {
taskTrackingZoneSpec = new _TaskTrackingZoneSpec();
taskTrackingZone = Zone.current.fork(taskTrackingZoneSpec);
});
it('should track tasks', (done: Function) => {
taskTrackingZone.run(() => {
taskTrackingZone.scheduleMicroTask('test1', () => {});
expect(taskTrackingZoneSpec !.microTasks.length).toBe(1);
expect(taskTrackingZoneSpec !.microTasks[0].source).toBe('test1');
setTimeout(() => {});
expect(taskTrackingZoneSpec !.macroTasks.length).toBe(1);
expect(taskTrackingZoneSpec !.macroTasks[0].source).toBe('setTimeout');
taskTrackingZone.cancelTask(taskTrackingZoneSpec !.macroTasks[0]);
expect(taskTrackingZoneSpec !.macroTasks.length).toBe(0);
setTimeout(() => {
// assert on execution it is null
expect(taskTrackingZoneSpec !.macroTasks.length).toBe(0);
expect(taskTrackingZoneSpec !.microTasks.length).toBe(0);
// If a browser does not have XMLHttpRequest, then end test here.
if (typeof global['XMLHttpRequest'] == 'undefined') return done();
const xhr = new XMLHttpRequest();
xhr.open('get', '/', true);
xhr.onreadystatechange = () => {
if (xhr.readyState == 4) {
// clear current event tasks using setTimeout
setTimeout(() => {
expect(taskTrackingZoneSpec !.macroTasks.length).toBe(0);
expect(taskTrackingZoneSpec !.microTasks.length).toBe(0);
if (supportPatchXHROnProperty()) {
expect(taskTrackingZoneSpec !.eventTasks.length).not.toBe(0);
}
taskTrackingZoneSpec !.clearEvents();
expect(taskTrackingZoneSpec !.eventTasks.length).toBe(0);
done();
});
}
};
xhr.send();
expect(taskTrackingZoneSpec !.macroTasks.length).toBe(1);
expect(taskTrackingZoneSpec !.macroTasks[0].source).toBe('XMLHttpRequest.send');
if (supportPatchXHROnProperty()) {
expect(taskTrackingZoneSpec !.eventTasks[0].source)
.toMatch(/\.addEventListener:readystatechange/);
}
});
});
});
it('should capture task creation stacktrace', (done) => {
taskTrackingZone.run(() => {
setTimeout(() => { done(); });
expect((taskTrackingZoneSpec !.macroTasks[0] as any)['creationLocation']).toBeTruthy();
});
});
});