
committed by
Kara Erickson

parent
7b3bcc23af
commit
5eb7426216
413
packages/zone.js/test/zone-spec/async-test.spec.ts
Normal file
413
packages/zone.js/test/zone-spec/async-test.spec.ts
Normal 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']);
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
1473
packages/zone.js/test/zone-spec/fake-async-test.spec.ts
Normal file
1473
packages/zone.js/test/zone-spec/fake-async-test.spec.ts
Normal file
File diff suppressed because it is too large
Load Diff
185
packages/zone.js/test/zone-spec/long-stack-trace-zone.spec.ts
Normal file
185
packages/zone.js/test/zone-spec/long-stack-trace-zone.spec.ts
Normal 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);
|
||||
});
|
||||
});
|
||||
}));
|
179
packages/zone.js/test/zone-spec/proxy.spec.ts
Normal file
179
packages/zone.js/test/zone-spec/proxy.spec.ts
Normal 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);
|
||||
});
|
||||
});
|
||||
});
|
57
packages/zone.js/test/zone-spec/sync-test.spec.ts
Normal file
57
packages/zone.js/test/zone-spec/sync-test.spec.ts
Normal 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);
|
||||
}
|
||||
});
|
||||
});
|
||||
}));
|
||||
});
|
76
packages/zone.js/test/zone-spec/task-tracking.spec.ts
Normal file
76
packages/zone.js/test/zone-spec/task-tracking.spec.ts
Normal 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();
|
||||
});
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user