fake-async-test.umd.js 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781
  1. 'use strict';
  2. var __assign = (this && this.__assign) || function () {
  3. __assign = Object.assign || function(t) {
  4. for (var s, i = 1, n = arguments.length; i < n; i++) {
  5. s = arguments[i];
  6. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
  7. t[p] = s[p];
  8. }
  9. return t;
  10. };
  11. return __assign.apply(this, arguments);
  12. };
  13. var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
  14. if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
  15. if (ar || !(i in from)) {
  16. if (!ar) ar = Array.prototype.slice.call(from, 0, i);
  17. ar[i] = from[i];
  18. }
  19. }
  20. return to.concat(ar || Array.prototype.slice.call(from));
  21. };
  22. /**
  23. * @license Angular v<unknown>
  24. * (c) 2010-2022 Google LLC. https://angular.io/
  25. * License: MIT
  26. */
  27. (function (factory) {
  28. typeof define === 'function' && define.amd ? define(factory) :
  29. factory();
  30. })((function () {
  31. 'use strict';
  32. (function (global) {
  33. var OriginalDate = global.Date;
  34. // Since when we compile this file to `es2015`, and if we define
  35. // this `FakeDate` as `class FakeDate`, and then set `FakeDate.prototype`
  36. // there will be an error which is `Cannot assign to read only property 'prototype'`
  37. // so we need to use function implementation here.
  38. function FakeDate() {
  39. if (arguments.length === 0) {
  40. var d = new OriginalDate();
  41. d.setTime(FakeDate.now());
  42. return d;
  43. }
  44. else {
  45. var args = Array.prototype.slice.call(arguments);
  46. return new (OriginalDate.bind.apply(OriginalDate, __spreadArray([void 0], args, false)))();
  47. }
  48. }
  49. FakeDate.now = function () {
  50. var fakeAsyncTestZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec');
  51. if (fakeAsyncTestZoneSpec) {
  52. return fakeAsyncTestZoneSpec.getFakeSystemTime();
  53. }
  54. return OriginalDate.now.apply(this, arguments);
  55. };
  56. FakeDate.UTC = OriginalDate.UTC;
  57. FakeDate.parse = OriginalDate.parse;
  58. // keep a reference for zone patched timer function
  59. var timers = {
  60. setTimeout: global.setTimeout,
  61. setInterval: global.setInterval,
  62. clearTimeout: global.clearTimeout,
  63. clearInterval: global.clearInterval
  64. };
  65. var Scheduler = /** @class */ (function () {
  66. function Scheduler() {
  67. // Scheduler queue with the tuple of end time and callback function - sorted by end time.
  68. this._schedulerQueue = [];
  69. // Current simulated time in millis.
  70. this._currentTickTime = 0;
  71. // Current fake system base time in millis.
  72. this._currentFakeBaseSystemTime = OriginalDate.now();
  73. // track requeuePeriodicTimer
  74. this._currentTickRequeuePeriodicEntries = [];
  75. }
  76. Scheduler.prototype.getCurrentTickTime = function () {
  77. return this._currentTickTime;
  78. };
  79. Scheduler.prototype.getFakeSystemTime = function () {
  80. return this._currentFakeBaseSystemTime + this._currentTickTime;
  81. };
  82. Scheduler.prototype.setFakeBaseSystemTime = function (fakeBaseSystemTime) {
  83. this._currentFakeBaseSystemTime = fakeBaseSystemTime;
  84. };
  85. Scheduler.prototype.getRealSystemTime = function () {
  86. return OriginalDate.now();
  87. };
  88. Scheduler.prototype.scheduleFunction = function (cb, delay, options) {
  89. options = __assign({
  90. args: [],
  91. isPeriodic: false,
  92. isRequestAnimationFrame: false,
  93. id: -1,
  94. isRequeuePeriodic: false
  95. }, options);
  96. var currentId = options.id < 0 ? Scheduler.nextId++ : options.id;
  97. var endTime = this._currentTickTime + delay;
  98. // Insert so that scheduler queue remains sorted by end time.
  99. var newEntry = {
  100. endTime: endTime,
  101. id: currentId,
  102. func: cb,
  103. args: options.args,
  104. delay: delay,
  105. isPeriodic: options.isPeriodic,
  106. isRequestAnimationFrame: options.isRequestAnimationFrame
  107. };
  108. if (options.isRequeuePeriodic) {
  109. this._currentTickRequeuePeriodicEntries.push(newEntry);
  110. }
  111. var i = 0;
  112. for (; i < this._schedulerQueue.length; i++) {
  113. var currentEntry = this._schedulerQueue[i];
  114. if (newEntry.endTime < currentEntry.endTime) {
  115. break;
  116. }
  117. }
  118. this._schedulerQueue.splice(i, 0, newEntry);
  119. return currentId;
  120. };
  121. Scheduler.prototype.removeScheduledFunctionWithId = function (id) {
  122. for (var i = 0; i < this._schedulerQueue.length; i++) {
  123. if (this._schedulerQueue[i].id == id) {
  124. this._schedulerQueue.splice(i, 1);
  125. break;
  126. }
  127. }
  128. };
  129. Scheduler.prototype.removeAll = function () {
  130. this._schedulerQueue = [];
  131. };
  132. Scheduler.prototype.getTimerCount = function () {
  133. return this._schedulerQueue.length;
  134. };
  135. Scheduler.prototype.tickToNext = function (step, doTick, tickOptions) {
  136. if (step === void 0) { step = 1; }
  137. if (this._schedulerQueue.length < step) {
  138. return;
  139. }
  140. // Find the last task currently queued in the scheduler queue and tick
  141. // till that time.
  142. var startTime = this._currentTickTime;
  143. var targetTask = this._schedulerQueue[step - 1];
  144. this.tick(targetTask.endTime - startTime, doTick, tickOptions);
  145. };
  146. Scheduler.prototype.tick = function (millis, doTick, tickOptions) {
  147. if (millis === void 0) { millis = 0; }
  148. var finalTime = this._currentTickTime + millis;
  149. var lastCurrentTime = 0;
  150. tickOptions = Object.assign({ processNewMacroTasksSynchronously: true }, tickOptions);
  151. // we need to copy the schedulerQueue so nested timeout
  152. // will not be wrongly called in the current tick
  153. // https://github.com/angular/angular/issues/33799
  154. var schedulerQueue = tickOptions.processNewMacroTasksSynchronously ?
  155. this._schedulerQueue :
  156. this._schedulerQueue.slice();
  157. if (schedulerQueue.length === 0 && doTick) {
  158. doTick(millis);
  159. return;
  160. }
  161. while (schedulerQueue.length > 0) {
  162. // clear requeueEntries before each loop
  163. this._currentTickRequeuePeriodicEntries = [];
  164. var current = schedulerQueue[0];
  165. if (finalTime < current.endTime) {
  166. // Done processing the queue since it's sorted by endTime.
  167. break;
  168. }
  169. else {
  170. // Time to run scheduled function. Remove it from the head of queue.
  171. var current_1 = schedulerQueue.shift();
  172. if (!tickOptions.processNewMacroTasksSynchronously) {
  173. var idx = this._schedulerQueue.indexOf(current_1);
  174. if (idx >= 0) {
  175. this._schedulerQueue.splice(idx, 1);
  176. }
  177. }
  178. lastCurrentTime = this._currentTickTime;
  179. this._currentTickTime = current_1.endTime;
  180. if (doTick) {
  181. doTick(this._currentTickTime - lastCurrentTime);
  182. }
  183. var retval = current_1.func.apply(global, current_1.isRequestAnimationFrame ? [this._currentTickTime] : current_1.args);
  184. if (!retval) {
  185. // Uncaught exception in the current scheduled function. Stop processing the queue.
  186. break;
  187. }
  188. // check is there any requeue periodic entry is added in
  189. // current loop, if there is, we need to add to current loop
  190. if (!tickOptions.processNewMacroTasksSynchronously) {
  191. this._currentTickRequeuePeriodicEntries.forEach(function (newEntry) {
  192. var i = 0;
  193. for (; i < schedulerQueue.length; i++) {
  194. var currentEntry = schedulerQueue[i];
  195. if (newEntry.endTime < currentEntry.endTime) {
  196. break;
  197. }
  198. }
  199. schedulerQueue.splice(i, 0, newEntry);
  200. });
  201. }
  202. }
  203. }
  204. lastCurrentTime = this._currentTickTime;
  205. this._currentTickTime = finalTime;
  206. if (doTick) {
  207. doTick(this._currentTickTime - lastCurrentTime);
  208. }
  209. };
  210. Scheduler.prototype.flushOnlyPendingTimers = function (doTick) {
  211. if (this._schedulerQueue.length === 0) {
  212. return 0;
  213. }
  214. // Find the last task currently queued in the scheduler queue and tick
  215. // till that time.
  216. var startTime = this._currentTickTime;
  217. var lastTask = this._schedulerQueue[this._schedulerQueue.length - 1];
  218. this.tick(lastTask.endTime - startTime, doTick, { processNewMacroTasksSynchronously: false });
  219. return this._currentTickTime - startTime;
  220. };
  221. Scheduler.prototype.flush = function (limit, flushPeriodic, doTick) {
  222. if (limit === void 0) { limit = 20; }
  223. if (flushPeriodic === void 0) { flushPeriodic = false; }
  224. if (flushPeriodic) {
  225. return this.flushPeriodic(doTick);
  226. }
  227. else {
  228. return this.flushNonPeriodic(limit, doTick);
  229. }
  230. };
  231. Scheduler.prototype.flushPeriodic = function (doTick) {
  232. if (this._schedulerQueue.length === 0) {
  233. return 0;
  234. }
  235. // Find the last task currently queued in the scheduler queue and tick
  236. // till that time.
  237. var startTime = this._currentTickTime;
  238. var lastTask = this._schedulerQueue[this._schedulerQueue.length - 1];
  239. this.tick(lastTask.endTime - startTime, doTick);
  240. return this._currentTickTime - startTime;
  241. };
  242. Scheduler.prototype.flushNonPeriodic = function (limit, doTick) {
  243. var startTime = this._currentTickTime;
  244. var lastCurrentTime = 0;
  245. var count = 0;
  246. while (this._schedulerQueue.length > 0) {
  247. count++;
  248. if (count > limit) {
  249. throw new Error('flush failed after reaching the limit of ' + limit +
  250. ' tasks. Does your code use a polling timeout?');
  251. }
  252. // flush only non-periodic timers.
  253. // If the only remaining tasks are periodic(or requestAnimationFrame), finish flushing.
  254. if (this._schedulerQueue.filter(function (task) { return !task.isPeriodic && !task.isRequestAnimationFrame; })
  255. .length === 0) {
  256. break;
  257. }
  258. var current = this._schedulerQueue.shift();
  259. lastCurrentTime = this._currentTickTime;
  260. this._currentTickTime = current.endTime;
  261. if (doTick) {
  262. // Update any secondary schedulers like Jasmine mock Date.
  263. doTick(this._currentTickTime - lastCurrentTime);
  264. }
  265. var retval = current.func.apply(global, current.args);
  266. if (!retval) {
  267. // Uncaught exception in the current scheduled function. Stop processing the queue.
  268. break;
  269. }
  270. }
  271. return this._currentTickTime - startTime;
  272. };
  273. return Scheduler;
  274. }());
  275. // Next scheduler id.
  276. Scheduler.nextId = 1;
  277. var FakeAsyncTestZoneSpec = /** @class */ (function () {
  278. function FakeAsyncTestZoneSpec(namePrefix, trackPendingRequestAnimationFrame, macroTaskOptions) {
  279. if (trackPendingRequestAnimationFrame === void 0) { trackPendingRequestAnimationFrame = false; }
  280. this.trackPendingRequestAnimationFrame = trackPendingRequestAnimationFrame;
  281. this.macroTaskOptions = macroTaskOptions;
  282. this._scheduler = new Scheduler();
  283. this._microtasks = [];
  284. this._lastError = null;
  285. this._uncaughtPromiseErrors = Promise[Zone.__symbol__('uncaughtPromiseErrors')];
  286. this.pendingPeriodicTimers = [];
  287. this.pendingTimers = [];
  288. this.patchDateLocked = false;
  289. this.properties = { 'FakeAsyncTestZoneSpec': this };
  290. this.name = 'fakeAsyncTestZone for ' + namePrefix;
  291. // in case user can't access the construction of FakeAsyncTestSpec
  292. // user can also define macroTaskOptions by define a global variable.
  293. if (!this.macroTaskOptions) {
  294. this.macroTaskOptions = global[Zone.__symbol__('FakeAsyncTestMacroTask')];
  295. }
  296. }
  297. FakeAsyncTestZoneSpec.assertInZone = function () {
  298. if (Zone.current.get('FakeAsyncTestZoneSpec') == null) {
  299. throw new Error('The code should be running in the fakeAsync zone to call this function');
  300. }
  301. };
  302. FakeAsyncTestZoneSpec.prototype._fnAndFlush = function (fn, completers) {
  303. var _this = this;
  304. return function () {
  305. var args = [];
  306. for (var _i = 0; _i < arguments.length; _i++) {
  307. args[_i] = arguments[_i];
  308. }
  309. fn.apply(global, args);
  310. if (_this._lastError === null) { // Success
  311. if (completers.onSuccess != null) {
  312. completers.onSuccess.apply(global);
  313. }
  314. // Flush microtasks only on success.
  315. _this.flushMicrotasks();
  316. }
  317. else { // Failure
  318. if (completers.onError != null) {
  319. completers.onError.apply(global);
  320. }
  321. }
  322. // Return true if there were no errors, false otherwise.
  323. return _this._lastError === null;
  324. };
  325. };
  326. FakeAsyncTestZoneSpec._removeTimer = function (timers, id) {
  327. var index = timers.indexOf(id);
  328. if (index > -1) {
  329. timers.splice(index, 1);
  330. }
  331. };
  332. FakeAsyncTestZoneSpec.prototype._dequeueTimer = function (id) {
  333. var _this = this;
  334. return function () {
  335. FakeAsyncTestZoneSpec._removeTimer(_this.pendingTimers, id);
  336. };
  337. };
  338. FakeAsyncTestZoneSpec.prototype._requeuePeriodicTimer = function (fn, interval, args, id) {
  339. var _this = this;
  340. return function () {
  341. // Requeue the timer callback if it's not been canceled.
  342. if (_this.pendingPeriodicTimers.indexOf(id) !== -1) {
  343. _this._scheduler.scheduleFunction(fn, interval, { args: args, isPeriodic: true, id: id, isRequeuePeriodic: true });
  344. }
  345. };
  346. };
  347. FakeAsyncTestZoneSpec.prototype._dequeuePeriodicTimer = function (id) {
  348. var _this = this;
  349. return function () {
  350. FakeAsyncTestZoneSpec._removeTimer(_this.pendingPeriodicTimers, id);
  351. };
  352. };
  353. FakeAsyncTestZoneSpec.prototype._setTimeout = function (fn, delay, args, isTimer) {
  354. if (isTimer === void 0) { isTimer = true; }
  355. var removeTimerFn = this._dequeueTimer(Scheduler.nextId);
  356. // Queue the callback and dequeue the timer on success and error.
  357. var cb = this._fnAndFlush(fn, { onSuccess: removeTimerFn, onError: removeTimerFn });
  358. var id = this._scheduler.scheduleFunction(cb, delay, { args: args, isRequestAnimationFrame: !isTimer });
  359. if (isTimer) {
  360. this.pendingTimers.push(id);
  361. }
  362. return id;
  363. };
  364. FakeAsyncTestZoneSpec.prototype._clearTimeout = function (id) {
  365. FakeAsyncTestZoneSpec._removeTimer(this.pendingTimers, id);
  366. this._scheduler.removeScheduledFunctionWithId(id);
  367. };
  368. FakeAsyncTestZoneSpec.prototype._setInterval = function (fn, interval, args) {
  369. var id = Scheduler.nextId;
  370. var completers = { onSuccess: null, onError: this._dequeuePeriodicTimer(id) };
  371. var cb = this._fnAndFlush(fn, completers);
  372. // Use the callback created above to requeue on success.
  373. completers.onSuccess = this._requeuePeriodicTimer(cb, interval, args, id);
  374. // Queue the callback and dequeue the periodic timer only on error.
  375. this._scheduler.scheduleFunction(cb, interval, { args: args, isPeriodic: true });
  376. this.pendingPeriodicTimers.push(id);
  377. return id;
  378. };
  379. FakeAsyncTestZoneSpec.prototype._clearInterval = function (id) {
  380. FakeAsyncTestZoneSpec._removeTimer(this.pendingPeriodicTimers, id);
  381. this._scheduler.removeScheduledFunctionWithId(id);
  382. };
  383. FakeAsyncTestZoneSpec.prototype._resetLastErrorAndThrow = function () {
  384. var error = this._lastError || this._uncaughtPromiseErrors[0];
  385. this._uncaughtPromiseErrors.length = 0;
  386. this._lastError = null;
  387. throw error;
  388. };
  389. FakeAsyncTestZoneSpec.prototype.getCurrentTickTime = function () {
  390. return this._scheduler.getCurrentTickTime();
  391. };
  392. FakeAsyncTestZoneSpec.prototype.getFakeSystemTime = function () {
  393. return this._scheduler.getFakeSystemTime();
  394. };
  395. FakeAsyncTestZoneSpec.prototype.setFakeBaseSystemTime = function (realTime) {
  396. this._scheduler.setFakeBaseSystemTime(realTime);
  397. };
  398. FakeAsyncTestZoneSpec.prototype.getRealSystemTime = function () {
  399. return this._scheduler.getRealSystemTime();
  400. };
  401. FakeAsyncTestZoneSpec.patchDate = function () {
  402. if (!!global[Zone.__symbol__('disableDatePatching')]) {
  403. // we don't want to patch global Date
  404. // because in some case, global Date
  405. // is already being patched, we need to provide
  406. // an option to let user still use their
  407. // own version of Date.
  408. return;
  409. }
  410. if (global['Date'] === FakeDate) {
  411. // already patched
  412. return;
  413. }
  414. global['Date'] = FakeDate;
  415. FakeDate.prototype = OriginalDate.prototype;
  416. // try check and reset timers
  417. // because jasmine.clock().install() may
  418. // have replaced the global timer
  419. FakeAsyncTestZoneSpec.checkTimerPatch();
  420. };
  421. FakeAsyncTestZoneSpec.resetDate = function () {
  422. if (global['Date'] === FakeDate) {
  423. global['Date'] = OriginalDate;
  424. }
  425. };
  426. FakeAsyncTestZoneSpec.checkTimerPatch = function () {
  427. if (global.setTimeout !== timers.setTimeout) {
  428. global.setTimeout = timers.setTimeout;
  429. global.clearTimeout = timers.clearTimeout;
  430. }
  431. if (global.setInterval !== timers.setInterval) {
  432. global.setInterval = timers.setInterval;
  433. global.clearInterval = timers.clearInterval;
  434. }
  435. };
  436. FakeAsyncTestZoneSpec.prototype.lockDatePatch = function () {
  437. this.patchDateLocked = true;
  438. FakeAsyncTestZoneSpec.patchDate();
  439. };
  440. FakeAsyncTestZoneSpec.prototype.unlockDatePatch = function () {
  441. this.patchDateLocked = false;
  442. FakeAsyncTestZoneSpec.resetDate();
  443. };
  444. FakeAsyncTestZoneSpec.prototype.tickToNext = function (steps, doTick, tickOptions) {
  445. if (steps === void 0) { steps = 1; }
  446. if (tickOptions === void 0) { tickOptions = { processNewMacroTasksSynchronously: true }; }
  447. if (steps <= 0) {
  448. return;
  449. }
  450. FakeAsyncTestZoneSpec.assertInZone();
  451. this.flushMicrotasks();
  452. this._scheduler.tickToNext(steps, doTick, tickOptions);
  453. if (this._lastError !== null) {
  454. this._resetLastErrorAndThrow();
  455. }
  456. };
  457. FakeAsyncTestZoneSpec.prototype.tick = function (millis, doTick, tickOptions) {
  458. if (millis === void 0) { millis = 0; }
  459. if (tickOptions === void 0) { tickOptions = { processNewMacroTasksSynchronously: true }; }
  460. FakeAsyncTestZoneSpec.assertInZone();
  461. this.flushMicrotasks();
  462. this._scheduler.tick(millis, doTick, tickOptions);
  463. if (this._lastError !== null) {
  464. this._resetLastErrorAndThrow();
  465. }
  466. };
  467. FakeAsyncTestZoneSpec.prototype.flushMicrotasks = function () {
  468. var _this = this;
  469. FakeAsyncTestZoneSpec.assertInZone();
  470. var flushErrors = function () {
  471. if (_this._lastError !== null || _this._uncaughtPromiseErrors.length) {
  472. // If there is an error stop processing the microtask queue and rethrow the error.
  473. _this._resetLastErrorAndThrow();
  474. }
  475. };
  476. while (this._microtasks.length > 0) {
  477. var microtask = this._microtasks.shift();
  478. microtask.func.apply(microtask.target, microtask.args);
  479. }
  480. flushErrors();
  481. };
  482. FakeAsyncTestZoneSpec.prototype.flush = function (limit, flushPeriodic, doTick) {
  483. FakeAsyncTestZoneSpec.assertInZone();
  484. this.flushMicrotasks();
  485. var elapsed = this._scheduler.flush(limit, flushPeriodic, doTick);
  486. if (this._lastError !== null) {
  487. this._resetLastErrorAndThrow();
  488. }
  489. return elapsed;
  490. };
  491. FakeAsyncTestZoneSpec.prototype.flushOnlyPendingTimers = function (doTick) {
  492. FakeAsyncTestZoneSpec.assertInZone();
  493. this.flushMicrotasks();
  494. var elapsed = this._scheduler.flushOnlyPendingTimers(doTick);
  495. if (this._lastError !== null) {
  496. this._resetLastErrorAndThrow();
  497. }
  498. return elapsed;
  499. };
  500. FakeAsyncTestZoneSpec.prototype.removeAllTimers = function () {
  501. FakeAsyncTestZoneSpec.assertInZone();
  502. this._scheduler.removeAll();
  503. this.pendingPeriodicTimers = [];
  504. this.pendingTimers = [];
  505. };
  506. FakeAsyncTestZoneSpec.prototype.getTimerCount = function () {
  507. return this._scheduler.getTimerCount() + this._microtasks.length;
  508. };
  509. FakeAsyncTestZoneSpec.prototype.onScheduleTask = function (delegate, current, target, task) {
  510. switch (task.type) {
  511. case 'microTask':
  512. var args = task.data && task.data.args;
  513. // should pass additional arguments to callback if have any
  514. // currently we know process.nextTick will have such additional
  515. // arguments
  516. var additionalArgs = void 0;
  517. if (args) {
  518. var callbackIndex = task.data.cbIdx;
  519. if (typeof args.length === 'number' && args.length > callbackIndex + 1) {
  520. additionalArgs = Array.prototype.slice.call(args, callbackIndex + 1);
  521. }
  522. }
  523. this._microtasks.push({
  524. func: task.invoke,
  525. args: additionalArgs,
  526. target: task.data && task.data.target
  527. });
  528. break;
  529. case 'macroTask':
  530. switch (task.source) {
  531. case 'setTimeout':
  532. task.data['handleId'] = this._setTimeout(task.invoke, task.data['delay'], Array.prototype.slice.call(task.data['args'], 2));
  533. break;
  534. case 'setImmediate':
  535. task.data['handleId'] = this._setTimeout(task.invoke, 0, Array.prototype.slice.call(task.data['args'], 1));
  536. break;
  537. case 'setInterval':
  538. task.data['handleId'] = this._setInterval(task.invoke, task.data['delay'], Array.prototype.slice.call(task.data['args'], 2));
  539. break;
  540. case 'XMLHttpRequest.send':
  541. throw new Error('Cannot make XHRs from within a fake async test. Request URL: ' +
  542. task.data['url']);
  543. case 'requestAnimationFrame':
  544. case 'webkitRequestAnimationFrame':
  545. case 'mozRequestAnimationFrame':
  546. // Simulate a requestAnimationFrame by using a setTimeout with 16 ms.
  547. // (60 frames per second)
  548. task.data['handleId'] = this._setTimeout(task.invoke, 16, task.data['args'], this.trackPendingRequestAnimationFrame);
  549. break;
  550. default:
  551. // user can define which macroTask they want to support by passing
  552. // macroTaskOptions
  553. var macroTaskOption = this.findMacroTaskOption(task);
  554. if (macroTaskOption) {
  555. var args_1 = task.data && task.data['args'];
  556. var delay = args_1 && args_1.length > 1 ? args_1[1] : 0;
  557. var callbackArgs = macroTaskOption.callbackArgs ? macroTaskOption.callbackArgs : args_1;
  558. if (!!macroTaskOption.isPeriodic) {
  559. // periodic macroTask, use setInterval to simulate
  560. task.data['handleId'] = this._setInterval(task.invoke, delay, callbackArgs);
  561. task.data.isPeriodic = true;
  562. }
  563. else {
  564. // not periodic, use setTimeout to simulate
  565. task.data['handleId'] = this._setTimeout(task.invoke, delay, callbackArgs);
  566. }
  567. break;
  568. }
  569. throw new Error('Unknown macroTask scheduled in fake async test: ' + task.source);
  570. }
  571. break;
  572. case 'eventTask':
  573. task = delegate.scheduleTask(target, task);
  574. break;
  575. }
  576. return task;
  577. };
  578. FakeAsyncTestZoneSpec.prototype.onCancelTask = function (delegate, current, target, task) {
  579. switch (task.source) {
  580. case 'setTimeout':
  581. case 'requestAnimationFrame':
  582. case 'webkitRequestAnimationFrame':
  583. case 'mozRequestAnimationFrame':
  584. return this._clearTimeout(task.data['handleId']);
  585. case 'setInterval':
  586. return this._clearInterval(task.data['handleId']);
  587. default:
  588. // user can define which macroTask they want to support by passing
  589. // macroTaskOptions
  590. var macroTaskOption = this.findMacroTaskOption(task);
  591. if (macroTaskOption) {
  592. var handleId = task.data['handleId'];
  593. return macroTaskOption.isPeriodic ? this._clearInterval(handleId) :
  594. this._clearTimeout(handleId);
  595. }
  596. return delegate.cancelTask(target, task);
  597. }
  598. };
  599. FakeAsyncTestZoneSpec.prototype.onInvoke = function (delegate, current, target, callback, applyThis, applyArgs, source) {
  600. try {
  601. FakeAsyncTestZoneSpec.patchDate();
  602. return delegate.invoke(target, callback, applyThis, applyArgs, source);
  603. }
  604. finally {
  605. if (!this.patchDateLocked) {
  606. FakeAsyncTestZoneSpec.resetDate();
  607. }
  608. }
  609. };
  610. FakeAsyncTestZoneSpec.prototype.findMacroTaskOption = function (task) {
  611. if (!this.macroTaskOptions) {
  612. return null;
  613. }
  614. for (var i = 0; i < this.macroTaskOptions.length; i++) {
  615. var macroTaskOption = this.macroTaskOptions[i];
  616. if (macroTaskOption.source === task.source) {
  617. return macroTaskOption;
  618. }
  619. }
  620. return null;
  621. };
  622. FakeAsyncTestZoneSpec.prototype.onHandleError = function (parentZoneDelegate, currentZone, targetZone, error) {
  623. this._lastError = error;
  624. return false; // Don't propagate error to parent zone.
  625. };
  626. return FakeAsyncTestZoneSpec;
  627. }());
  628. // Export the class so that new instances can be created with proper
  629. // constructor params.
  630. Zone['FakeAsyncTestZoneSpec'] = FakeAsyncTestZoneSpec;
  631. })(typeof window === 'object' && window || typeof self === 'object' && self || global);
  632. Zone.__load_patch('fakeasync', function (global, Zone, api) {
  633. var FakeAsyncTestZoneSpec = Zone && Zone['FakeAsyncTestZoneSpec'];
  634. function getProxyZoneSpec() {
  635. return Zone && Zone['ProxyZoneSpec'];
  636. }
  637. var _fakeAsyncTestZoneSpec = null;
  638. /**
  639. * Clears out the shared fake async zone for a test.
  640. * To be called in a global `beforeEach`.
  641. *
  642. * @experimental
  643. */
  644. function resetFakeAsyncZone() {
  645. if (_fakeAsyncTestZoneSpec) {
  646. _fakeAsyncTestZoneSpec.unlockDatePatch();
  647. }
  648. _fakeAsyncTestZoneSpec = null;
  649. // in node.js testing we may not have ProxyZoneSpec in which case there is nothing to reset.
  650. getProxyZoneSpec() && getProxyZoneSpec().assertPresent().resetDelegate();
  651. }
  652. /**
  653. * Wraps a function to be executed in the fakeAsync zone:
  654. * - microtasks are manually executed by calling `flushMicrotasks()`,
  655. * - timers are synchronous, `tick()` simulates the asynchronous passage of time.
  656. *
  657. * If there are any pending timers at the end of the function, an exception will be thrown.
  658. *
  659. * Can be used to wrap inject() calls.
  660. *
  661. * ## Example
  662. *
  663. * {@example core/testing/ts/fake_async.ts region='basic'}
  664. *
  665. * @param fn
  666. * @returns The function wrapped to be executed in the fakeAsync zone
  667. *
  668. * @experimental
  669. */
  670. function fakeAsync(fn) {
  671. // Not using an arrow function to preserve context passed from call site
  672. var fakeAsyncFn = function () {
  673. var args = [];
  674. for (var _i = 0; _i < arguments.length; _i++) {
  675. args[_i] = arguments[_i];
  676. }
  677. var ProxyZoneSpec = getProxyZoneSpec();
  678. if (!ProxyZoneSpec) {
  679. throw new Error('ProxyZoneSpec is needed for the async() test helper but could not be found. ' +
  680. 'Please make sure that your environment includes zone.js/plugins/proxy');
  681. }
  682. var proxyZoneSpec = ProxyZoneSpec.assertPresent();
  683. if (Zone.current.get('FakeAsyncTestZoneSpec')) {
  684. throw new Error('fakeAsync() calls can not be nested');
  685. }
  686. try {
  687. // in case jasmine.clock init a fakeAsyncTestZoneSpec
  688. if (!_fakeAsyncTestZoneSpec) {
  689. if (proxyZoneSpec.getDelegate() instanceof FakeAsyncTestZoneSpec) {
  690. throw new Error('fakeAsync() calls can not be nested');
  691. }
  692. _fakeAsyncTestZoneSpec = new FakeAsyncTestZoneSpec();
  693. }
  694. var res = void 0;
  695. var lastProxyZoneSpec = proxyZoneSpec.getDelegate();
  696. proxyZoneSpec.setDelegate(_fakeAsyncTestZoneSpec);
  697. _fakeAsyncTestZoneSpec.lockDatePatch();
  698. try {
  699. res = fn.apply(this, args);
  700. flushMicrotasks();
  701. }
  702. finally {
  703. proxyZoneSpec.setDelegate(lastProxyZoneSpec);
  704. }
  705. if (_fakeAsyncTestZoneSpec.pendingPeriodicTimers.length > 0) {
  706. throw new Error("".concat(_fakeAsyncTestZoneSpec.pendingPeriodicTimers.length, " ") +
  707. "periodic timer(s) still in the queue.");
  708. }
  709. if (_fakeAsyncTestZoneSpec.pendingTimers.length > 0) {
  710. throw new Error("".concat(_fakeAsyncTestZoneSpec.pendingTimers.length, " timer(s) still in the queue."));
  711. }
  712. return res;
  713. }
  714. finally {
  715. resetFakeAsyncZone();
  716. }
  717. };
  718. fakeAsyncFn.isFakeAsync = true;
  719. return fakeAsyncFn;
  720. }
  721. function _getFakeAsyncZoneSpec() {
  722. if (_fakeAsyncTestZoneSpec == null) {
  723. _fakeAsyncTestZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec');
  724. if (_fakeAsyncTestZoneSpec == null) {
  725. throw new Error('The code should be running in the fakeAsync zone to call this function');
  726. }
  727. }
  728. return _fakeAsyncTestZoneSpec;
  729. }
  730. /**
  731. * Simulates the asynchronous passage of time for the timers in the fakeAsync zone.
  732. *
  733. * The microtasks queue is drained at the very start of this function and after any timer callback
  734. * has been executed.
  735. *
  736. * ## Example
  737. *
  738. * {@example core/testing/ts/fake_async.ts region='basic'}
  739. *
  740. * @experimental
  741. */
  742. function tick(millis, ignoreNestedTimeout) {
  743. if (millis === void 0) { millis = 0; }
  744. if (ignoreNestedTimeout === void 0) { ignoreNestedTimeout = false; }
  745. _getFakeAsyncZoneSpec().tick(millis, null, ignoreNestedTimeout);
  746. }
  747. /**
  748. * Simulates the asynchronous passage of time for the timers in the fakeAsync zone by
  749. * draining the macrotask queue until it is empty. The returned value is the milliseconds
  750. * of time that would have been elapsed.
  751. *
  752. * @param maxTurns
  753. * @returns The simulated time elapsed, in millis.
  754. *
  755. * @experimental
  756. */
  757. function flush(maxTurns) {
  758. return _getFakeAsyncZoneSpec().flush(maxTurns);
  759. }
  760. /**
  761. * Discard all remaining periodic tasks.
  762. *
  763. * @experimental
  764. */
  765. function discardPeriodicTasks() {
  766. var zoneSpec = _getFakeAsyncZoneSpec();
  767. zoneSpec.pendingPeriodicTimers;
  768. zoneSpec.pendingPeriodicTimers.length = 0;
  769. }
  770. /**
  771. * Flush any pending microtasks.
  772. *
  773. * @experimental
  774. */
  775. function flushMicrotasks() {
  776. _getFakeAsyncZoneSpec().flushMicrotasks();
  777. }
  778. Zone[api.symbol('fakeAsyncTest')] =
  779. { resetFakeAsyncZone: resetFakeAsyncZone, flushMicrotasks: flushMicrotasks, discardPeriodicTasks: discardPeriodicTasks, tick: tick, flush: flush, fakeAsync: fakeAsync };
  780. }, true);
  781. }));