fake-async-test.umd.js 39 KB

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