fake-async-test.umd.js 38 KB

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