|
28 | 28 | // Current simulated time in millis.
|
29 | 29 | this._currentTime = 0;
|
30 | 30 | }
|
31 |
| - Scheduler.prototype.scheduleFunction = function (cb, delay, args, isPeriodic, id) { |
| 31 | + Scheduler.prototype.scheduleFunction = function (cb, delay, args, isPeriodic, isRequestAnimationFrame, id) { |
32 | 32 | if (args === void 0) { args = []; }
|
33 | 33 | if (isPeriodic === void 0) { isPeriodic = false; }
|
| 34 | + if (isRequestAnimationFrame === void 0) { isRequestAnimationFrame = false; } |
34 | 35 | if (id === void 0) { id = -1; }
|
35 | 36 | var currentId = id < 0 ? this.nextId++ : id;
|
36 | 37 | var endTime = this._currentTime + delay;
|
|
41 | 42 | func: cb,
|
42 | 43 | args: args,
|
43 | 44 | delay: delay,
|
44 |
| - isPeriodic: isPeriodic |
| 45 | + isPeriodic: isPeriodic, |
| 46 | + isRequestAnimationFrame: isRequestAnimationFrame |
45 | 47 | };
|
46 | 48 | var i = 0;
|
47 | 49 | for (; i < this._schedulerQueue.length; i++) {
|
|
83 | 85 | }
|
84 | 86 | this._currentTime = finalTime;
|
85 | 87 | };
|
86 |
| - Scheduler.prototype.flush = function (limit) { |
| 88 | + Scheduler.prototype.flush = function (limit, flushPeriodic) { |
| 89 | + var _this = this; |
87 | 90 | if (limit === void 0) { limit = 20; }
|
| 91 | + if (flushPeriodic === void 0) { flushPeriodic = false; } |
88 | 92 | var startTime = this._currentTime;
|
89 | 93 | var count = 0;
|
| 94 | + var seenTimers = []; |
90 | 95 | while (this._schedulerQueue.length > 0) {
|
91 | 96 | count++;
|
92 | 97 | if (count > limit) {
|
93 | 98 | throw new Error('flush failed after reaching the limit of ' + limit +
|
94 | 99 | ' tasks. Does your code use a polling timeout?');
|
95 | 100 | }
|
96 |
| - // If the only remaining tasks are periodic, finish flushing. |
97 |
| - if (!(this._schedulerQueue.filter(function (task) { return !task.isPeriodic; }).length)) { |
98 |
| - break; |
| 101 | + if (!flushPeriodic) { |
| 102 | + // flush only non-periodic timers. |
| 103 | + // If the only remaining tasks are periodic(or requestAnimationFrame), finish flushing. |
| 104 | + if (this._schedulerQueue.filter(function (task) { return !task.isPeriodic && !task.isRequestAnimationFrame; }) |
| 105 | + .length === 0) { |
| 106 | + break; |
| 107 | + } |
| 108 | + } |
| 109 | + else { |
| 110 | + // flushPeriodic has been requested. |
| 111 | + // Stop when all timer id-s have been seen at least once. |
| 112 | + if (this._schedulerQueue |
| 113 | + .filter(function (task) { |
| 114 | + return seenTimers.indexOf(task.id) === -1 || _this._currentTime === task.endTime; |
| 115 | + }) |
| 116 | + .length === 0) { |
| 117 | + break; |
| 118 | + } |
99 | 119 | }
|
100 | 120 | var current = this._schedulerQueue.shift();
|
| 121 | + if (seenTimers.indexOf(current.id) === -1) { |
| 122 | + seenTimers.push(current.id); |
| 123 | + } |
101 | 124 | this._currentTime = current.endTime;
|
102 | 125 | var retval = current.func.apply(global, current.args);
|
103 | 126 | if (!retval) {
|
|
110 | 133 | return Scheduler;
|
111 | 134 | }());
|
112 | 135 | var FakeAsyncTestZoneSpec = (function () {
|
113 |
| - function FakeAsyncTestZoneSpec(namePrefix) { |
| 136 | + function FakeAsyncTestZoneSpec(namePrefix, trackPendingRequestAnimationFrame) { |
| 137 | + if (trackPendingRequestAnimationFrame === void 0) { trackPendingRequestAnimationFrame = false; } |
| 138 | + this.trackPendingRequestAnimationFrame = trackPendingRequestAnimationFrame; |
114 | 139 | this._scheduler = new Scheduler();
|
115 | 140 | this._microtasks = [];
|
116 | 141 | this._lastError = null;
|
|
166 | 191 | return function () {
|
167 | 192 | // Requeue the timer callback if it's not been canceled.
|
168 | 193 | if (_this.pendingPeriodicTimers.indexOf(id) !== -1) {
|
169 |
| - _this._scheduler.scheduleFunction(fn, interval, args, true, id); |
| 194 | + _this._scheduler.scheduleFunction(fn, interval, args, true, false, id); |
170 | 195 | }
|
171 | 196 | };
|
172 | 197 | };
|
|
176 | 201 | FakeAsyncTestZoneSpec._removeTimer(_this.pendingPeriodicTimers, id);
|
177 | 202 | };
|
178 | 203 | };
|
179 |
| - FakeAsyncTestZoneSpec.prototype._setTimeout = function (fn, delay, args) { |
| 204 | + FakeAsyncTestZoneSpec.prototype._setTimeout = function (fn, delay, args, isTimer) { |
| 205 | + if (isTimer === void 0) { isTimer = true; } |
180 | 206 | var removeTimerFn = this._dequeueTimer(this._scheduler.nextId);
|
181 | 207 | // Queue the callback and dequeue the timer on success and error.
|
182 | 208 | var cb = this._fnAndFlush(fn, { onSuccess: removeTimerFn, onError: removeTimerFn });
|
183 |
| - var id = this._scheduler.scheduleFunction(cb, delay, args); |
184 |
| - this.pendingTimers.push(id); |
| 209 | + var id = this._scheduler.scheduleFunction(cb, delay, args, false, !isTimer); |
| 210 | + if (isTimer) { |
| 211 | + this.pendingTimers.push(id); |
| 212 | + } |
185 | 213 | return id;
|
186 | 214 | };
|
187 | 215 | FakeAsyncTestZoneSpec.prototype._clearTimeout = function (id) {
|
|
237 | 265 | }
|
238 | 266 | flushErrors();
|
239 | 267 | };
|
240 |
| - FakeAsyncTestZoneSpec.prototype.flush = function (limit) { |
| 268 | + FakeAsyncTestZoneSpec.prototype.flush = function (limit, flushPeriodic) { |
241 | 269 | FakeAsyncTestZoneSpec.assertInZone();
|
242 | 270 | this.flushMicrotasks();
|
243 |
| - var elapsed = this._scheduler.flush(limit); |
| 271 | + var elapsed = this._scheduler.flush(limit, flushPeriodic); |
244 | 272 | if (this._lastError !== null) {
|
245 | 273 | this._resetLastErrorAndThrow();
|
246 | 274 | }
|
|
283 | 311 | case 'mozRequestAnimationFrame':
|
284 | 312 | // Simulate a requestAnimationFrame by using a setTimeout with 16 ms.
|
285 | 313 | // (60 frames per second)
|
286 |
| - task.data['handleId'] = this._setTimeout(task.invoke, 16, task.data['args']); |
| 314 | + task.data['handleId'] = this._setTimeout(task.invoke, 16, task.data['args'], this.trackPendingRequestAnimationFrame); |
287 | 315 | break;
|
288 | 316 | default:
|
289 | 317 | throw new Error('Unknown macroTask scheduled in fake async test: ' + task.source);
|
|
0 commit comments