132 lines
3.6 KiB
Plaintext
132 lines
3.6 KiB
Plaintext
|
import {BaseException, global} from 'angular2/src/facade/lang';
|
||
|
import {ListWrapper} from 'angular2/src/facade/collection';
|
||
|
|
||
|
var _scheduler;
|
||
|
var _microtasks:List<Function> = [];
|
||
|
var _pendingPeriodicTimers: List<number> = [];
|
||
|
var _pendingTimers: List<number> = [];
|
||
|
var _error = null;
|
||
|
|
||
|
/**
|
||
|
* Wraps a function to be executed in the fakeAsync zone:
|
||
|
* - microtasks are manually executed by calling `flushMicrotasks()`,
|
||
|
* - timers are synchronous, `tick()` simulates the asynchronous passage of time.
|
||
|
*
|
||
|
* If there are any pending timers at the end of the function, an exception will be thrown.
|
||
|
*
|
||
|
* @param fn
|
||
|
* @returns {Function} The function wrapped to be executed in the fakeAsync zone
|
||
|
*/
|
||
|
export function fakeAsync(fn: Function): Function {
|
||
|
// TODO(vicb) re-enable once the jasmine patch from zone.js is applied
|
||
|
//if (global.zone._inFakeAsyncZone) {
|
||
|
// throw new Error('fakeAsync() calls can not be nested');
|
||
|
//}
|
||
|
|
||
|
var fakeAsyncZone = global.zone.fork({
|
||
|
setTimeout: _setTimeout,
|
||
|
clearTimeout: _clearTimeout,
|
||
|
setInterval: _setInterval,
|
||
|
clearInterval: _clearInterval,
|
||
|
scheduleMicrotask: _scheduleMicrotask,
|
||
|
_inFakeAsyncZone: true
|
||
|
});
|
||
|
|
||
|
return function(...args) {
|
||
|
_scheduler = global.jasmine.DelayedFunctionScheduler();
|
||
|
ListWrapper.clear(_microtasks);
|
||
|
ListWrapper.clear(_pendingPeriodicTimers);
|
||
|
ListWrapper.clear(_pendingTimers);
|
||
|
|
||
|
var res = fakeAsyncZone.run(() => {
|
||
|
var res = fn(...args);
|
||
|
});
|
||
|
|
||
|
if (_pendingPeriodicTimers.length > 0) {
|
||
|
throw new BaseException(`${_pendingPeriodicTimers.length} periodic timer(s) still in the queue.`);
|
||
|
}
|
||
|
|
||
|
if (_pendingTimers.length > 0) {
|
||
|
throw new BaseException(`${_pendingTimers.length} timer(s) still in the queue.`);
|
||
|
}
|
||
|
|
||
|
_scheduler = null;
|
||
|
ListWrapper.clear(_microtasks);
|
||
|
|
||
|
return res;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Simulates the asynchronous passage of time for the timers in the fakeAsync zone.
|
||
|
*
|
||
|
* The microtasks queue is drained at the very start of this function and after any timer callback has been executed.
|
||
|
*
|
||
|
* @param {number} millis Number of millisecond, defaults to 0
|
||
|
*/
|
||
|
export function tick(millis: number = 0): void {
|
||
|
_assertInFakeAsyncZone();
|
||
|
flushMicrotasks();
|
||
|
_scheduler.tick(millis);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Flush any pending microtasks.
|
||
|
*/
|
||
|
export function flushMicrotasks(): void {
|
||
|
_assertInFakeAsyncZone();
|
||
|
while (_microtasks.length > 0) {
|
||
|
var microtask = ListWrapper.removeAt(_microtasks, 0);
|
||
|
microtask();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function _setTimeout(fn: Function, delay: number, ...args): number {
|
||
|
var cb = _fnAndFlush(fn);
|
||
|
var id = _scheduler.scheduleFunction(cb, delay, args);
|
||
|
ListWrapper.push(_pendingTimers, id);
|
||
|
_scheduler.scheduleFunction(_dequeueTimer(id), delay);
|
||
|
return id;
|
||
|
}
|
||
|
|
||
|
function _clearTimeout(id: number) {
|
||
|
_dequeueTimer(id);
|
||
|
return _scheduler.removeFunctionWithId(id);
|
||
|
}
|
||
|
|
||
|
function _setInterval(fn: Function, interval: number, ...args) {
|
||
|
var cb = _fnAndFlush(fn);
|
||
|
var id = _scheduler.scheduleFunction(cb, interval, args, true);
|
||
|
_pendingPeriodicTimers.push(id);
|
||
|
return id;
|
||
|
}
|
||
|
|
||
|
function _clearInterval(id: number) {
|
||
|
ListWrapper.remove(_pendingPeriodicTimers, id);
|
||
|
return _scheduler.removeFunctionWithId(id);
|
||
|
}
|
||
|
|
||
|
function _fnAndFlush(fn: Function): void {
|
||
|
return () => {
|
||
|
fn.apply(global, arguments);
|
||
|
flushMicrotasks();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function _scheduleMicrotask(microtask: Function): void {
|
||
|
ListWrapper.push(_microtasks, microtask);
|
||
|
}
|
||
|
|
||
|
function _dequeueTimer(id: number): Function {
|
||
|
return function() {
|
||
|
ListWrapper.remove(_pendingTimers, id);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function _assertInFakeAsyncZone(): void {
|
||
|
if (!global.zone._inFakeAsyncZone) {
|
||
|
throw new Error('The code should be running in the fakeAsync zone to call this function');
|
||
|
}
|
||
|
}
|
||
|
|