zone-testing.js 91 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125
  1. 'use strict';
  2. /**
  3. * @license Angular v<unknown>
  4. * (c) 2010-2022 Google LLC. https://angular.io/
  5. * License: MIT
  6. */
  7. /**
  8. * @fileoverview
  9. * @suppress {globalThis}
  10. */
  11. const NEWLINE = '\n';
  12. const IGNORE_FRAMES = {};
  13. const creationTrace = '__creationTrace__';
  14. const ERROR_TAG = 'STACKTRACE TRACKING';
  15. const SEP_TAG = '__SEP_TAG__';
  16. let sepTemplate = SEP_TAG + '@[native]';
  17. class LongStackTrace {
  18. constructor() {
  19. this.error = getStacktrace();
  20. this.timestamp = new Date();
  21. }
  22. }
  23. function getStacktraceWithUncaughtError() {
  24. return new Error(ERROR_TAG);
  25. }
  26. function getStacktraceWithCaughtError() {
  27. try {
  28. throw getStacktraceWithUncaughtError();
  29. }
  30. catch (err) {
  31. return err;
  32. }
  33. }
  34. // Some implementations of exception handling don't create a stack trace if the exception
  35. // isn't thrown, however it's faster not to actually throw the exception.
  36. const error = getStacktraceWithUncaughtError();
  37. const caughtError = getStacktraceWithCaughtError();
  38. const getStacktrace = error.stack ?
  39. getStacktraceWithUncaughtError :
  40. (caughtError.stack ? getStacktraceWithCaughtError : getStacktraceWithUncaughtError);
  41. function getFrames(error) {
  42. return error.stack ? error.stack.split(NEWLINE) : [];
  43. }
  44. function addErrorStack(lines, error) {
  45. let trace = getFrames(error);
  46. for (let i = 0; i < trace.length; i++) {
  47. const frame = trace[i];
  48. // Filter out the Frames which are part of stack capturing.
  49. if (!IGNORE_FRAMES.hasOwnProperty(frame)) {
  50. lines.push(trace[i]);
  51. }
  52. }
  53. }
  54. function renderLongStackTrace(frames, stack) {
  55. const longTrace = [stack ? stack.trim() : ''];
  56. if (frames) {
  57. let timestamp = new Date().getTime();
  58. for (let i = 0; i < frames.length; i++) {
  59. const traceFrames = frames[i];
  60. const lastTime = traceFrames.timestamp;
  61. let separator = `____________________Elapsed ${timestamp - lastTime.getTime()} ms; At: ${lastTime}`;
  62. separator = separator.replace(/[^\w\d]/g, '_');
  63. longTrace.push(sepTemplate.replace(SEP_TAG, separator));
  64. addErrorStack(longTrace, traceFrames.error);
  65. timestamp = lastTime.getTime();
  66. }
  67. }
  68. return longTrace.join(NEWLINE);
  69. }
  70. // if Error.stackTraceLimit is 0, means stack trace
  71. // is disabled, so we don't need to generate long stack trace
  72. // this will improve performance in some test(some test will
  73. // set stackTraceLimit to 0, https://github.com/angular/zone.js/issues/698
  74. function stackTracesEnabled() {
  75. // Cast through any since this property only exists on Error in the nodejs
  76. // typings.
  77. return Error.stackTraceLimit > 0;
  78. }
  79. Zone['longStackTraceZoneSpec'] = {
  80. name: 'long-stack-trace',
  81. longStackTraceLimit: 10,
  82. // add a getLongStackTrace method in spec to
  83. // handle handled reject promise error.
  84. getLongStackTrace: function (error) {
  85. if (!error) {
  86. return undefined;
  87. }
  88. const trace = error[Zone.__symbol__('currentTaskTrace')];
  89. if (!trace) {
  90. return error.stack;
  91. }
  92. return renderLongStackTrace(trace, error.stack);
  93. },
  94. onScheduleTask: function (parentZoneDelegate, currentZone, targetZone, task) {
  95. if (stackTracesEnabled()) {
  96. const currentTask = Zone.currentTask;
  97. let trace = currentTask && currentTask.data && currentTask.data[creationTrace] || [];
  98. trace = [new LongStackTrace()].concat(trace);
  99. if (trace.length > this.longStackTraceLimit) {
  100. trace.length = this.longStackTraceLimit;
  101. }
  102. if (!task.data)
  103. task.data = {};
  104. if (task.type === 'eventTask') {
  105. // Fix issue https://github.com/angular/zone.js/issues/1195,
  106. // For event task of browser, by default, all task will share a
  107. // singleton instance of data object, we should create a new one here
  108. // The cast to `any` is required to workaround a closure bug which wrongly applies
  109. // URL sanitization rules to .data access.
  110. task.data = { ...task.data };
  111. }
  112. task.data[creationTrace] = trace;
  113. }
  114. return parentZoneDelegate.scheduleTask(targetZone, task);
  115. },
  116. onHandleError: function (parentZoneDelegate, currentZone, targetZone, error) {
  117. if (stackTracesEnabled()) {
  118. const parentTask = Zone.currentTask || error.task;
  119. if (error instanceof Error && parentTask) {
  120. const longStack = renderLongStackTrace(parentTask.data && parentTask.data[creationTrace], error.stack);
  121. try {
  122. error.stack = error.longStack = longStack;
  123. }
  124. catch (err) {
  125. }
  126. }
  127. }
  128. return parentZoneDelegate.handleError(targetZone, error);
  129. }
  130. };
  131. function captureStackTraces(stackTraces, count) {
  132. if (count > 0) {
  133. stackTraces.push(getFrames((new LongStackTrace()).error));
  134. captureStackTraces(stackTraces, count - 1);
  135. }
  136. }
  137. function computeIgnoreFrames() {
  138. if (!stackTracesEnabled()) {
  139. return;
  140. }
  141. const frames = [];
  142. captureStackTraces(frames, 2);
  143. const frames1 = frames[0];
  144. const frames2 = frames[1];
  145. for (let i = 0; i < frames1.length; i++) {
  146. const frame1 = frames1[i];
  147. if (frame1.indexOf(ERROR_TAG) == -1) {
  148. let match = frame1.match(/^\s*at\s+/);
  149. if (match) {
  150. sepTemplate = match[0] + SEP_TAG + ' (http://localhost)';
  151. break;
  152. }
  153. }
  154. }
  155. for (let i = 0; i < frames1.length; i++) {
  156. const frame1 = frames1[i];
  157. const frame2 = frames2[i];
  158. if (frame1 === frame2) {
  159. IGNORE_FRAMES[frame1] = true;
  160. }
  161. else {
  162. break;
  163. }
  164. }
  165. }
  166. computeIgnoreFrames();
  167. class ProxyZoneSpec {
  168. static get() {
  169. return Zone.current.get('ProxyZoneSpec');
  170. }
  171. static isLoaded() {
  172. return ProxyZoneSpec.get() instanceof ProxyZoneSpec;
  173. }
  174. static assertPresent() {
  175. if (!ProxyZoneSpec.isLoaded()) {
  176. throw new Error(`Expected to be running in 'ProxyZone', but it was not found.`);
  177. }
  178. return ProxyZoneSpec.get();
  179. }
  180. constructor(defaultSpecDelegate = null) {
  181. this.defaultSpecDelegate = defaultSpecDelegate;
  182. this.name = 'ProxyZone';
  183. this._delegateSpec = null;
  184. this.properties = { 'ProxyZoneSpec': this };
  185. this.propertyKeys = null;
  186. this.lastTaskState = null;
  187. this.isNeedToTriggerHasTask = false;
  188. this.tasks = [];
  189. this.setDelegate(defaultSpecDelegate);
  190. }
  191. setDelegate(delegateSpec) {
  192. const isNewDelegate = this._delegateSpec !== delegateSpec;
  193. this._delegateSpec = delegateSpec;
  194. this.propertyKeys && this.propertyKeys.forEach((key) => delete this.properties[key]);
  195. this.propertyKeys = null;
  196. if (delegateSpec && delegateSpec.properties) {
  197. this.propertyKeys = Object.keys(delegateSpec.properties);
  198. this.propertyKeys.forEach((k) => this.properties[k] = delegateSpec.properties[k]);
  199. }
  200. // if a new delegateSpec was set, check if we need to trigger hasTask
  201. if (isNewDelegate && this.lastTaskState &&
  202. (this.lastTaskState.macroTask || this.lastTaskState.microTask)) {
  203. this.isNeedToTriggerHasTask = true;
  204. }
  205. }
  206. getDelegate() {
  207. return this._delegateSpec;
  208. }
  209. resetDelegate() {
  210. this.getDelegate();
  211. this.setDelegate(this.defaultSpecDelegate);
  212. }
  213. tryTriggerHasTask(parentZoneDelegate, currentZone, targetZone) {
  214. if (this.isNeedToTriggerHasTask && this.lastTaskState) {
  215. // last delegateSpec has microTask or macroTask
  216. // should call onHasTask in current delegateSpec
  217. this.isNeedToTriggerHasTask = false;
  218. this.onHasTask(parentZoneDelegate, currentZone, targetZone, this.lastTaskState);
  219. }
  220. }
  221. removeFromTasks(task) {
  222. if (!this.tasks) {
  223. return;
  224. }
  225. for (let i = 0; i < this.tasks.length; i++) {
  226. if (this.tasks[i] === task) {
  227. this.tasks.splice(i, 1);
  228. return;
  229. }
  230. }
  231. }
  232. getAndClearPendingTasksInfo() {
  233. if (this.tasks.length === 0) {
  234. return '';
  235. }
  236. const taskInfo = this.tasks.map((task) => {
  237. const dataInfo = task.data &&
  238. Object.keys(task.data)
  239. .map((key) => {
  240. return key + ':' + task.data[key];
  241. })
  242. .join(',');
  243. return `type: ${task.type}, source: ${task.source}, args: {${dataInfo}}`;
  244. });
  245. const pendingTasksInfo = '--Pending async tasks are: [' + taskInfo + ']';
  246. // clear tasks
  247. this.tasks = [];
  248. return pendingTasksInfo;
  249. }
  250. onFork(parentZoneDelegate, currentZone, targetZone, zoneSpec) {
  251. if (this._delegateSpec && this._delegateSpec.onFork) {
  252. return this._delegateSpec.onFork(parentZoneDelegate, currentZone, targetZone, zoneSpec);
  253. }
  254. else {
  255. return parentZoneDelegate.fork(targetZone, zoneSpec);
  256. }
  257. }
  258. onIntercept(parentZoneDelegate, currentZone, targetZone, delegate, source) {
  259. if (this._delegateSpec && this._delegateSpec.onIntercept) {
  260. return this._delegateSpec.onIntercept(parentZoneDelegate, currentZone, targetZone, delegate, source);
  261. }
  262. else {
  263. return parentZoneDelegate.intercept(targetZone, delegate, source);
  264. }
  265. }
  266. onInvoke(parentZoneDelegate, currentZone, targetZone, delegate, applyThis, applyArgs, source) {
  267. this.tryTriggerHasTask(parentZoneDelegate, currentZone, targetZone);
  268. if (this._delegateSpec && this._delegateSpec.onInvoke) {
  269. return this._delegateSpec.onInvoke(parentZoneDelegate, currentZone, targetZone, delegate, applyThis, applyArgs, source);
  270. }
  271. else {
  272. return parentZoneDelegate.invoke(targetZone, delegate, applyThis, applyArgs, source);
  273. }
  274. }
  275. onHandleError(parentZoneDelegate, currentZone, targetZone, error) {
  276. if (this._delegateSpec && this._delegateSpec.onHandleError) {
  277. return this._delegateSpec.onHandleError(parentZoneDelegate, currentZone, targetZone, error);
  278. }
  279. else {
  280. return parentZoneDelegate.handleError(targetZone, error);
  281. }
  282. }
  283. onScheduleTask(parentZoneDelegate, currentZone, targetZone, task) {
  284. if (task.type !== 'eventTask') {
  285. this.tasks.push(task);
  286. }
  287. if (this._delegateSpec && this._delegateSpec.onScheduleTask) {
  288. return this._delegateSpec.onScheduleTask(parentZoneDelegate, currentZone, targetZone, task);
  289. }
  290. else {
  291. return parentZoneDelegate.scheduleTask(targetZone, task);
  292. }
  293. }
  294. onInvokeTask(parentZoneDelegate, currentZone, targetZone, task, applyThis, applyArgs) {
  295. if (task.type !== 'eventTask') {
  296. this.removeFromTasks(task);
  297. }
  298. this.tryTriggerHasTask(parentZoneDelegate, currentZone, targetZone);
  299. if (this._delegateSpec && this._delegateSpec.onInvokeTask) {
  300. return this._delegateSpec.onInvokeTask(parentZoneDelegate, currentZone, targetZone, task, applyThis, applyArgs);
  301. }
  302. else {
  303. return parentZoneDelegate.invokeTask(targetZone, task, applyThis, applyArgs);
  304. }
  305. }
  306. onCancelTask(parentZoneDelegate, currentZone, targetZone, task) {
  307. if (task.type !== 'eventTask') {
  308. this.removeFromTasks(task);
  309. }
  310. this.tryTriggerHasTask(parentZoneDelegate, currentZone, targetZone);
  311. if (this._delegateSpec && this._delegateSpec.onCancelTask) {
  312. return this._delegateSpec.onCancelTask(parentZoneDelegate, currentZone, targetZone, task);
  313. }
  314. else {
  315. return parentZoneDelegate.cancelTask(targetZone, task);
  316. }
  317. }
  318. onHasTask(delegate, current, target, hasTaskState) {
  319. this.lastTaskState = hasTaskState;
  320. if (this._delegateSpec && this._delegateSpec.onHasTask) {
  321. this._delegateSpec.onHasTask(delegate, current, target, hasTaskState);
  322. }
  323. else {
  324. delegate.hasTask(target, hasTaskState);
  325. }
  326. }
  327. }
  328. // Export the class so that new instances can be created with proper
  329. // constructor params.
  330. Zone['ProxyZoneSpec'] = ProxyZoneSpec;
  331. class SyncTestZoneSpec {
  332. constructor(namePrefix) {
  333. this.runZone = Zone.current;
  334. this.name = 'syncTestZone for ' + namePrefix;
  335. }
  336. onScheduleTask(delegate, current, target, task) {
  337. switch (task.type) {
  338. case 'microTask':
  339. case 'macroTask':
  340. throw new Error(`Cannot call ${task.source} from within a sync test (${this.name}).`);
  341. case 'eventTask':
  342. task = delegate.scheduleTask(target, task);
  343. break;
  344. }
  345. return task;
  346. }
  347. }
  348. // Export the class so that new instances can be created with proper
  349. // constructor params.
  350. Zone['SyncTestZoneSpec'] = SyncTestZoneSpec;
  351. /// <reference types="jasmine"/>
  352. Zone.__load_patch('jasmine', (global, Zone, api) => {
  353. const __extends = function (d, b) {
  354. for (const p in b)
  355. if (b.hasOwnProperty(p))
  356. d[p] = b[p];
  357. function __() {
  358. this.constructor = d;
  359. }
  360. d.prototype = b === null ? Object.create(b) : ((__.prototype = b.prototype), new __());
  361. };
  362. // Patch jasmine's describe/it/beforeEach/afterEach functions so test code always runs
  363. // in a testZone (ProxyZone). (See: angular/zone.js#91 & angular/angular#10503)
  364. if (!Zone)
  365. throw new Error('Missing: zone.js');
  366. if (typeof jest !== 'undefined') {
  367. // return if jasmine is a light implementation inside jest
  368. // in this case, we are running inside jest not jasmine
  369. return;
  370. }
  371. if (typeof jasmine == 'undefined' || jasmine['__zone_patch__']) {
  372. return;
  373. }
  374. jasmine['__zone_patch__'] = true;
  375. const SyncTestZoneSpec = Zone['SyncTestZoneSpec'];
  376. const ProxyZoneSpec = Zone['ProxyZoneSpec'];
  377. if (!SyncTestZoneSpec)
  378. throw new Error('Missing: SyncTestZoneSpec');
  379. if (!ProxyZoneSpec)
  380. throw new Error('Missing: ProxyZoneSpec');
  381. const ambientZone = Zone.current;
  382. const symbol = Zone.__symbol__;
  383. // whether patch jasmine clock when in fakeAsync
  384. const disablePatchingJasmineClock = global[symbol('fakeAsyncDisablePatchingClock')] === true;
  385. // the original variable name fakeAsyncPatchLock is not accurate, so the name will be
  386. // fakeAsyncAutoFakeAsyncWhenClockPatched and if this enablePatchingJasmineClock is false, we also
  387. // automatically disable the auto jump into fakeAsync feature
  388. const enableAutoFakeAsyncWhenClockPatched = !disablePatchingJasmineClock &&
  389. ((global[symbol('fakeAsyncPatchLock')] === true) ||
  390. (global[symbol('fakeAsyncAutoFakeAsyncWhenClockPatched')] === true));
  391. const ignoreUnhandledRejection = global[symbol('ignoreUnhandledRejection')] === true;
  392. if (!ignoreUnhandledRejection) {
  393. const globalErrors = jasmine.GlobalErrors;
  394. if (globalErrors && !jasmine[symbol('GlobalErrors')]) {
  395. jasmine[symbol('GlobalErrors')] = globalErrors;
  396. jasmine.GlobalErrors = function () {
  397. const instance = new globalErrors();
  398. const originalInstall = instance.install;
  399. if (originalInstall && !instance[symbol('install')]) {
  400. instance[symbol('install')] = originalInstall;
  401. instance.install = function () {
  402. const isNode = typeof process !== 'undefined' && !!process.on;
  403. // Note: Jasmine checks internally if `process` and `process.on` is defined. Otherwise,
  404. // it installs the browser rejection handler through the `global.addEventListener`.
  405. // This code may be run in the browser environment where `process` is not defined, and
  406. // this will lead to a runtime exception since Webpack 5 removed automatic Node.js
  407. // polyfills. Note, that events are named differently, it's `unhandledRejection` in
  408. // Node.js and `unhandledrejection` in the browser.
  409. const originalHandlers = isNode ? process.listeners('unhandledRejection') :
  410. global.eventListeners('unhandledrejection');
  411. const result = originalInstall.apply(this, arguments);
  412. isNode ? process.removeAllListeners('unhandledRejection') :
  413. global.removeAllListeners('unhandledrejection');
  414. if (originalHandlers) {
  415. originalHandlers.forEach(handler => {
  416. if (isNode) {
  417. process.on('unhandledRejection', handler);
  418. }
  419. else {
  420. global.addEventListener('unhandledrejection', handler);
  421. }
  422. });
  423. }
  424. return result;
  425. };
  426. }
  427. return instance;
  428. };
  429. }
  430. }
  431. // Monkey patch all of the jasmine DSL so that each function runs in appropriate zone.
  432. const jasmineEnv = jasmine.getEnv();
  433. ['describe', 'xdescribe', 'fdescribe'].forEach(methodName => {
  434. let originalJasmineFn = jasmineEnv[methodName];
  435. jasmineEnv[methodName] = function (description, specDefinitions) {
  436. return originalJasmineFn.call(this, description, wrapDescribeInZone(description, specDefinitions));
  437. };
  438. });
  439. ['it', 'xit', 'fit'].forEach(methodName => {
  440. let originalJasmineFn = jasmineEnv[methodName];
  441. jasmineEnv[symbol(methodName)] = originalJasmineFn;
  442. jasmineEnv[methodName] = function (description, specDefinitions, timeout) {
  443. arguments[1] = wrapTestInZone(specDefinitions);
  444. return originalJasmineFn.apply(this, arguments);
  445. };
  446. });
  447. ['beforeEach', 'afterEach', 'beforeAll', 'afterAll'].forEach(methodName => {
  448. let originalJasmineFn = jasmineEnv[methodName];
  449. jasmineEnv[symbol(methodName)] = originalJasmineFn;
  450. jasmineEnv[methodName] = function (specDefinitions, timeout) {
  451. arguments[0] = wrapTestInZone(specDefinitions);
  452. return originalJasmineFn.apply(this, arguments);
  453. };
  454. });
  455. if (!disablePatchingJasmineClock) {
  456. // need to patch jasmine.clock().mockDate and jasmine.clock().tick() so
  457. // they can work properly in FakeAsyncTest
  458. const originalClockFn = (jasmine[symbol('clock')] = jasmine['clock']);
  459. jasmine['clock'] = function () {
  460. const clock = originalClockFn.apply(this, arguments);
  461. if (!clock[symbol('patched')]) {
  462. clock[symbol('patched')] = symbol('patched');
  463. const originalTick = (clock[symbol('tick')] = clock.tick);
  464. clock.tick = function () {
  465. const fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec');
  466. if (fakeAsyncZoneSpec) {
  467. return fakeAsyncZoneSpec.tick.apply(fakeAsyncZoneSpec, arguments);
  468. }
  469. return originalTick.apply(this, arguments);
  470. };
  471. const originalMockDate = (clock[symbol('mockDate')] = clock.mockDate);
  472. clock.mockDate = function () {
  473. const fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec');
  474. if (fakeAsyncZoneSpec) {
  475. const dateTime = arguments.length > 0 ? arguments[0] : new Date();
  476. return fakeAsyncZoneSpec.setFakeBaseSystemTime.apply(fakeAsyncZoneSpec, dateTime && typeof dateTime.getTime === 'function' ? [dateTime.getTime()] :
  477. arguments);
  478. }
  479. return originalMockDate.apply(this, arguments);
  480. };
  481. // for auto go into fakeAsync feature, we need the flag to enable it
  482. if (enableAutoFakeAsyncWhenClockPatched) {
  483. ['install', 'uninstall'].forEach(methodName => {
  484. const originalClockFn = (clock[symbol(methodName)] = clock[methodName]);
  485. clock[methodName] = function () {
  486. const FakeAsyncTestZoneSpec = Zone['FakeAsyncTestZoneSpec'];
  487. if (FakeAsyncTestZoneSpec) {
  488. jasmine[symbol('clockInstalled')] = 'install' === methodName;
  489. return;
  490. }
  491. return originalClockFn.apply(this, arguments);
  492. };
  493. });
  494. }
  495. }
  496. return clock;
  497. };
  498. }
  499. // monkey patch createSpyObj to make properties enumerable to true
  500. if (!jasmine[Zone.__symbol__('createSpyObj')]) {
  501. const originalCreateSpyObj = jasmine.createSpyObj;
  502. jasmine[Zone.__symbol__('createSpyObj')] = originalCreateSpyObj;
  503. jasmine.createSpyObj = function () {
  504. const args = Array.prototype.slice.call(arguments);
  505. const propertyNames = args.length >= 3 ? args[2] : null;
  506. let spyObj;
  507. if (propertyNames) {
  508. const defineProperty = Object.defineProperty;
  509. Object.defineProperty = function (obj, p, attributes) {
  510. return defineProperty.call(this, obj, p, { ...attributes, configurable: true, enumerable: true });
  511. };
  512. try {
  513. spyObj = originalCreateSpyObj.apply(this, args);
  514. }
  515. finally {
  516. Object.defineProperty = defineProperty;
  517. }
  518. }
  519. else {
  520. spyObj = originalCreateSpyObj.apply(this, args);
  521. }
  522. return spyObj;
  523. };
  524. }
  525. /**
  526. * Gets a function wrapping the body of a Jasmine `describe` block to execute in a
  527. * synchronous-only zone.
  528. */
  529. function wrapDescribeInZone(description, describeBody) {
  530. return function () {
  531. // Create a synchronous-only zone in which to run `describe` blocks in order to raise an
  532. // error if any asynchronous operations are attempted inside of a `describe`.
  533. const syncZone = ambientZone.fork(new SyncTestZoneSpec(`jasmine.describe#${description}`));
  534. return syncZone.run(describeBody, this, arguments);
  535. };
  536. }
  537. function runInTestZone(testBody, applyThis, queueRunner, done) {
  538. const isClockInstalled = !!jasmine[symbol('clockInstalled')];
  539. queueRunner.testProxyZoneSpec;
  540. const testProxyZone = queueRunner.testProxyZone;
  541. if (isClockInstalled && enableAutoFakeAsyncWhenClockPatched) {
  542. // auto run a fakeAsync
  543. const fakeAsyncModule = Zone[Zone.__symbol__('fakeAsyncTest')];
  544. if (fakeAsyncModule && typeof fakeAsyncModule.fakeAsync === 'function') {
  545. testBody = fakeAsyncModule.fakeAsync(testBody);
  546. }
  547. }
  548. if (done) {
  549. return testProxyZone.run(testBody, applyThis, [done]);
  550. }
  551. else {
  552. return testProxyZone.run(testBody, applyThis);
  553. }
  554. }
  555. /**
  556. * Gets a function wrapping the body of a Jasmine `it/beforeEach/afterEach` block to
  557. * execute in a ProxyZone zone.
  558. * This will run in `testProxyZone`. The `testProxyZone` will be reset by the `ZoneQueueRunner`
  559. */
  560. function wrapTestInZone(testBody) {
  561. // The `done` callback is only passed through if the function expects at least one argument.
  562. // Note we have to make a function with correct number of arguments, otherwise jasmine will
  563. // think that all functions are sync or async.
  564. return (testBody && (testBody.length ? function (done) {
  565. return runInTestZone(testBody, this, this.queueRunner, done);
  566. } : function () {
  567. return runInTestZone(testBody, this, this.queueRunner);
  568. }));
  569. }
  570. const QueueRunner = jasmine.QueueRunner;
  571. jasmine.QueueRunner = (function (_super) {
  572. __extends(ZoneQueueRunner, _super);
  573. function ZoneQueueRunner(attrs) {
  574. if (attrs.onComplete) {
  575. attrs.onComplete = (fn => () => {
  576. // All functions are done, clear the test zone.
  577. this.testProxyZone = null;
  578. this.testProxyZoneSpec = null;
  579. ambientZone.scheduleMicroTask('jasmine.onComplete', fn);
  580. })(attrs.onComplete);
  581. }
  582. const nativeSetTimeout = global[Zone.__symbol__('setTimeout')];
  583. const nativeClearTimeout = global[Zone.__symbol__('clearTimeout')];
  584. if (nativeSetTimeout) {
  585. // should run setTimeout inside jasmine outside of zone
  586. attrs.timeout = {
  587. setTimeout: nativeSetTimeout ? nativeSetTimeout : global.setTimeout,
  588. clearTimeout: nativeClearTimeout ? nativeClearTimeout : global.clearTimeout
  589. };
  590. }
  591. // create a userContext to hold the queueRunner itself
  592. // so we can access the testProxy in it/xit/beforeEach ...
  593. if (jasmine.UserContext) {
  594. if (!attrs.userContext) {
  595. attrs.userContext = new jasmine.UserContext();
  596. }
  597. attrs.userContext.queueRunner = this;
  598. }
  599. else {
  600. if (!attrs.userContext) {
  601. attrs.userContext = {};
  602. }
  603. attrs.userContext.queueRunner = this;
  604. }
  605. // patch attrs.onException
  606. const onException = attrs.onException;
  607. attrs.onException = function (error) {
  608. if (error &&
  609. error.message ===
  610. 'Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.') {
  611. // jasmine timeout, we can make the error message more
  612. // reasonable to tell what tasks are pending
  613. const proxyZoneSpec = this && this.testProxyZoneSpec;
  614. if (proxyZoneSpec) {
  615. const pendingTasksInfo = proxyZoneSpec.getAndClearPendingTasksInfo();
  616. try {
  617. // try catch here in case error.message is not writable
  618. error.message += pendingTasksInfo;
  619. }
  620. catch (err) {
  621. }
  622. }
  623. }
  624. if (onException) {
  625. onException.call(this, error);
  626. }
  627. };
  628. _super.call(this, attrs);
  629. }
  630. ZoneQueueRunner.prototype.execute = function () {
  631. let zone = Zone.current;
  632. let isChildOfAmbientZone = false;
  633. while (zone) {
  634. if (zone === ambientZone) {
  635. isChildOfAmbientZone = true;
  636. break;
  637. }
  638. zone = zone.parent;
  639. }
  640. if (!isChildOfAmbientZone)
  641. throw new Error('Unexpected Zone: ' + Zone.current.name);
  642. // This is the zone which will be used for running individual tests.
  643. // It will be a proxy zone, so that the tests function can retroactively install
  644. // different zones.
  645. // Example:
  646. // - In beforeEach() do childZone = Zone.current.fork(...);
  647. // - In it() try to do fakeAsync(). The issue is that because the beforeEach forked the
  648. // zone outside of fakeAsync it will be able to escape the fakeAsync rules.
  649. // - Because ProxyZone is parent fo `childZone` fakeAsync can retroactively add
  650. // fakeAsync behavior to the childZone.
  651. this.testProxyZoneSpec = new ProxyZoneSpec();
  652. this.testProxyZone = ambientZone.fork(this.testProxyZoneSpec);
  653. if (!Zone.currentTask) {
  654. // if we are not running in a task then if someone would register a
  655. // element.addEventListener and then calling element.click() the
  656. // addEventListener callback would think that it is the top most task and would
  657. // drain the microtask queue on element.click() which would be incorrect.
  658. // For this reason we always force a task when running jasmine tests.
  659. Zone.current.scheduleMicroTask('jasmine.execute().forceTask', () => QueueRunner.prototype.execute.call(this));
  660. }
  661. else {
  662. _super.prototype.execute.call(this);
  663. }
  664. };
  665. return ZoneQueueRunner;
  666. })(QueueRunner);
  667. });
  668. Zone.__load_patch('jest', (context, Zone, api) => {
  669. if (typeof jest === 'undefined' || jest['__zone_patch__']) {
  670. return;
  671. }
  672. // From jest 29 and jest-preset-angular v13, the module transform logic
  673. // changed, and now jest-preset-angular use the use the tsconfig target
  674. // other than the hardcoded one, https://github.com/thymikee/jest-preset-angular/issues/2010
  675. // But jest-angular-preset doesn't introduce the @babel/plugin-transform-async-to-generator
  676. // which is needed by angular since `async/await` still need to be transformed
  677. // to promise for ES2017+ target.
  678. // So for now, we disable to output the uncaught error console log for a temp solution,
  679. // until jest-preset-angular find a proper solution.
  680. Zone[api.symbol('ignoreConsoleErrorUncaughtError')] = true;
  681. jest['__zone_patch__'] = true;
  682. const ProxyZoneSpec = Zone['ProxyZoneSpec'];
  683. const SyncTestZoneSpec = Zone['SyncTestZoneSpec'];
  684. if (!ProxyZoneSpec) {
  685. throw new Error('Missing ProxyZoneSpec');
  686. }
  687. const rootZone = Zone.current;
  688. const syncZone = rootZone.fork(new SyncTestZoneSpec('jest.describe'));
  689. const proxyZoneSpec = new ProxyZoneSpec();
  690. const proxyZone = rootZone.fork(proxyZoneSpec);
  691. function wrapDescribeFactoryInZone(originalJestFn) {
  692. return function (...tableArgs) {
  693. const originalDescribeFn = originalJestFn.apply(this, tableArgs);
  694. return function (...args) {
  695. args[1] = wrapDescribeInZone(args[1]);
  696. return originalDescribeFn.apply(this, args);
  697. };
  698. };
  699. }
  700. function wrapTestFactoryInZone(originalJestFn) {
  701. return function (...tableArgs) {
  702. return function (...args) {
  703. args[1] = wrapTestInZone(args[1]);
  704. return originalJestFn.apply(this, tableArgs).apply(this, args);
  705. };
  706. };
  707. }
  708. /**
  709. * Gets a function wrapping the body of a jest `describe` block to execute in a
  710. * synchronous-only zone.
  711. */
  712. function wrapDescribeInZone(describeBody) {
  713. return function (...args) {
  714. return syncZone.run(describeBody, this, args);
  715. };
  716. }
  717. /**
  718. * Gets a function wrapping the body of a jest `it/beforeEach/afterEach` block to
  719. * execute in a ProxyZone zone.
  720. * This will run in the `proxyZone`.
  721. */
  722. function wrapTestInZone(testBody, isTestFunc = false) {
  723. if (typeof testBody !== 'function') {
  724. return testBody;
  725. }
  726. const wrappedFunc = function () {
  727. if (Zone[api.symbol('useFakeTimersCalled')] === true && testBody &&
  728. !testBody.isFakeAsync) {
  729. // jest.useFakeTimers is called, run into fakeAsyncTest automatically.
  730. const fakeAsyncModule = Zone[Zone.__symbol__('fakeAsyncTest')];
  731. if (fakeAsyncModule && typeof fakeAsyncModule.fakeAsync === 'function') {
  732. testBody = fakeAsyncModule.fakeAsync(testBody);
  733. }
  734. }
  735. proxyZoneSpec.isTestFunc = isTestFunc;
  736. return proxyZone.run(testBody, null, arguments);
  737. };
  738. // Update the length of wrappedFunc to be the same as the length of the testBody
  739. // So jest core can handle whether the test function has `done()` or not correctly
  740. Object.defineProperty(wrappedFunc, 'length', { configurable: true, writable: true, enumerable: false });
  741. wrappedFunc.length = testBody.length;
  742. return wrappedFunc;
  743. }
  744. ['describe', 'xdescribe', 'fdescribe'].forEach(methodName => {
  745. let originalJestFn = context[methodName];
  746. if (context[Zone.__symbol__(methodName)]) {
  747. return;
  748. }
  749. context[Zone.__symbol__(methodName)] = originalJestFn;
  750. context[methodName] = function (...args) {
  751. args[1] = wrapDescribeInZone(args[1]);
  752. return originalJestFn.apply(this, args);
  753. };
  754. context[methodName].each = wrapDescribeFactoryInZone(originalJestFn.each);
  755. });
  756. context.describe.only = context.fdescribe;
  757. context.describe.skip = context.xdescribe;
  758. ['it', 'xit', 'fit', 'test', 'xtest'].forEach(methodName => {
  759. let originalJestFn = context[methodName];
  760. if (context[Zone.__symbol__(methodName)]) {
  761. return;
  762. }
  763. context[Zone.__symbol__(methodName)] = originalJestFn;
  764. context[methodName] = function (...args) {
  765. args[1] = wrapTestInZone(args[1], true);
  766. return originalJestFn.apply(this, args);
  767. };
  768. context[methodName].each = wrapTestFactoryInZone(originalJestFn.each);
  769. context[methodName].todo = originalJestFn.todo;
  770. });
  771. context.it.only = context.fit;
  772. context.it.skip = context.xit;
  773. context.test.only = context.fit;
  774. context.test.skip = context.xit;
  775. ['beforeEach', 'afterEach', 'beforeAll', 'afterAll'].forEach(methodName => {
  776. let originalJestFn = context[methodName];
  777. if (context[Zone.__symbol__(methodName)]) {
  778. return;
  779. }
  780. context[Zone.__symbol__(methodName)] = originalJestFn;
  781. context[methodName] = function (...args) {
  782. args[0] = wrapTestInZone(args[0]);
  783. return originalJestFn.apply(this, args);
  784. };
  785. });
  786. Zone.patchJestObject = function patchJestObject(Timer, isModern = false) {
  787. // check whether currently the test is inside fakeAsync()
  788. function isPatchingFakeTimer() {
  789. const fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec');
  790. return !!fakeAsyncZoneSpec;
  791. }
  792. // check whether the current function is inside `test/it` or other methods
  793. // such as `describe/beforeEach`
  794. function isInTestFunc() {
  795. const proxyZoneSpec = Zone.current.get('ProxyZoneSpec');
  796. return proxyZoneSpec && proxyZoneSpec.isTestFunc;
  797. }
  798. if (Timer[api.symbol('fakeTimers')]) {
  799. return;
  800. }
  801. Timer[api.symbol('fakeTimers')] = true;
  802. // patch jest fakeTimer internal method to make sure no console.warn print out
  803. api.patchMethod(Timer, '_checkFakeTimers', delegate => {
  804. return function (self, args) {
  805. if (isPatchingFakeTimer()) {
  806. return true;
  807. }
  808. else {
  809. return delegate.apply(self, args);
  810. }
  811. };
  812. });
  813. // patch useFakeTimers(), set useFakeTimersCalled flag, and make test auto run into fakeAsync
  814. api.patchMethod(Timer, 'useFakeTimers', delegate => {
  815. return function (self, args) {
  816. Zone[api.symbol('useFakeTimersCalled')] = true;
  817. if (isModern || isInTestFunc()) {
  818. return delegate.apply(self, args);
  819. }
  820. return self;
  821. };
  822. });
  823. // patch useRealTimers(), unset useFakeTimers flag
  824. api.patchMethod(Timer, 'useRealTimers', delegate => {
  825. return function (self, args) {
  826. Zone[api.symbol('useFakeTimersCalled')] = false;
  827. if (isModern || isInTestFunc()) {
  828. return delegate.apply(self, args);
  829. }
  830. return self;
  831. };
  832. });
  833. // patch setSystemTime(), call setCurrentRealTime() in the fakeAsyncTest
  834. api.patchMethod(Timer, 'setSystemTime', delegate => {
  835. return function (self, args) {
  836. const fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec');
  837. if (fakeAsyncZoneSpec && isPatchingFakeTimer()) {
  838. fakeAsyncZoneSpec.setFakeBaseSystemTime(args[0]);
  839. }
  840. else {
  841. return delegate.apply(self, args);
  842. }
  843. };
  844. });
  845. // patch getSystemTime(), call getCurrentRealTime() in the fakeAsyncTest
  846. api.patchMethod(Timer, 'getRealSystemTime', delegate => {
  847. return function (self, args) {
  848. const fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec');
  849. if (fakeAsyncZoneSpec && isPatchingFakeTimer()) {
  850. return fakeAsyncZoneSpec.getRealSystemTime();
  851. }
  852. else {
  853. return delegate.apply(self, args);
  854. }
  855. };
  856. });
  857. // patch runAllTicks(), run all microTasks inside fakeAsync
  858. api.patchMethod(Timer, 'runAllTicks', delegate => {
  859. return function (self, args) {
  860. const fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec');
  861. if (fakeAsyncZoneSpec) {
  862. fakeAsyncZoneSpec.flushMicrotasks();
  863. }
  864. else {
  865. return delegate.apply(self, args);
  866. }
  867. };
  868. });
  869. // patch runAllTimers(), run all macroTasks inside fakeAsync
  870. api.patchMethod(Timer, 'runAllTimers', delegate => {
  871. return function (self, args) {
  872. const fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec');
  873. if (fakeAsyncZoneSpec) {
  874. fakeAsyncZoneSpec.flush(100, true);
  875. }
  876. else {
  877. return delegate.apply(self, args);
  878. }
  879. };
  880. });
  881. // patch advanceTimersByTime(), call tick() in the fakeAsyncTest
  882. api.patchMethod(Timer, 'advanceTimersByTime', delegate => {
  883. return function (self, args) {
  884. const fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec');
  885. if (fakeAsyncZoneSpec) {
  886. fakeAsyncZoneSpec.tick(args[0]);
  887. }
  888. else {
  889. return delegate.apply(self, args);
  890. }
  891. };
  892. });
  893. // patch runOnlyPendingTimers(), call flushOnlyPendingTimers() in the fakeAsyncTest
  894. api.patchMethod(Timer, 'runOnlyPendingTimers', delegate => {
  895. return function (self, args) {
  896. const fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec');
  897. if (fakeAsyncZoneSpec) {
  898. fakeAsyncZoneSpec.flushOnlyPendingTimers();
  899. }
  900. else {
  901. return delegate.apply(self, args);
  902. }
  903. };
  904. });
  905. // patch advanceTimersToNextTimer(), call tickToNext() in the fakeAsyncTest
  906. api.patchMethod(Timer, 'advanceTimersToNextTimer', delegate => {
  907. return function (self, args) {
  908. const fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec');
  909. if (fakeAsyncZoneSpec) {
  910. fakeAsyncZoneSpec.tickToNext(args[0]);
  911. }
  912. else {
  913. return delegate.apply(self, args);
  914. }
  915. };
  916. });
  917. // patch clearAllTimers(), call removeAllTimers() in the fakeAsyncTest
  918. api.patchMethod(Timer, 'clearAllTimers', delegate => {
  919. return function (self, args) {
  920. const fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec');
  921. if (fakeAsyncZoneSpec) {
  922. fakeAsyncZoneSpec.removeAllTimers();
  923. }
  924. else {
  925. return delegate.apply(self, args);
  926. }
  927. };
  928. });
  929. // patch getTimerCount(), call getTimerCount() in the fakeAsyncTest
  930. api.patchMethod(Timer, 'getTimerCount', delegate => {
  931. return function (self, args) {
  932. const fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec');
  933. if (fakeAsyncZoneSpec) {
  934. return fakeAsyncZoneSpec.getTimerCount();
  935. }
  936. else {
  937. return delegate.apply(self, args);
  938. }
  939. };
  940. });
  941. };
  942. });
  943. Zone.__load_patch('mocha', (global, Zone) => {
  944. const Mocha = global.Mocha;
  945. if (typeof Mocha === 'undefined') {
  946. // return if Mocha is not available, because now zone-testing
  947. // will load mocha patch with jasmine/jest patch
  948. return;
  949. }
  950. if (typeof Zone === 'undefined') {
  951. throw new Error('Missing Zone.js');
  952. }
  953. const ProxyZoneSpec = Zone['ProxyZoneSpec'];
  954. const SyncTestZoneSpec = Zone['SyncTestZoneSpec'];
  955. if (!ProxyZoneSpec) {
  956. throw new Error('Missing ProxyZoneSpec');
  957. }
  958. if (Mocha['__zone_patch__']) {
  959. throw new Error('"Mocha" has already been patched with "Zone".');
  960. }
  961. Mocha['__zone_patch__'] = true;
  962. const rootZone = Zone.current;
  963. const syncZone = rootZone.fork(new SyncTestZoneSpec('Mocha.describe'));
  964. let testZone = null;
  965. const suiteZone = rootZone.fork(new ProxyZoneSpec());
  966. const mochaOriginal = {
  967. after: global.after,
  968. afterEach: global.afterEach,
  969. before: global.before,
  970. beforeEach: global.beforeEach,
  971. describe: global.describe,
  972. it: global.it
  973. };
  974. function modifyArguments(args, syncTest, asyncTest) {
  975. for (let i = 0; i < args.length; i++) {
  976. let arg = args[i];
  977. if (typeof arg === 'function') {
  978. // The `done` callback is only passed through if the function expects at
  979. // least one argument.
  980. // Note we have to make a function with correct number of arguments,
  981. // otherwise mocha will
  982. // think that all functions are sync or async.
  983. args[i] = (arg.length === 0) ? syncTest(arg) : asyncTest(arg);
  984. // Mocha uses toString to view the test body in the result list, make sure we return the
  985. // correct function body
  986. args[i].toString = function () {
  987. return arg.toString();
  988. };
  989. }
  990. }
  991. return args;
  992. }
  993. function wrapDescribeInZone(args) {
  994. const syncTest = function (fn) {
  995. return function () {
  996. return syncZone.run(fn, this, arguments);
  997. };
  998. };
  999. return modifyArguments(args, syncTest);
  1000. }
  1001. function wrapTestInZone(args) {
  1002. const asyncTest = function (fn) {
  1003. return function (done) {
  1004. return testZone.run(fn, this, [done]);
  1005. };
  1006. };
  1007. const syncTest = function (fn) {
  1008. return function () {
  1009. return testZone.run(fn, this);
  1010. };
  1011. };
  1012. return modifyArguments(args, syncTest, asyncTest);
  1013. }
  1014. function wrapSuiteInZone(args) {
  1015. const asyncTest = function (fn) {
  1016. return function (done) {
  1017. return suiteZone.run(fn, this, [done]);
  1018. };
  1019. };
  1020. const syncTest = function (fn) {
  1021. return function () {
  1022. return suiteZone.run(fn, this);
  1023. };
  1024. };
  1025. return modifyArguments(args, syncTest, asyncTest);
  1026. }
  1027. global.describe = global.suite = function () {
  1028. return mochaOriginal.describe.apply(this, wrapDescribeInZone(arguments));
  1029. };
  1030. global.xdescribe = global.suite.skip = global.describe.skip = function () {
  1031. return mochaOriginal.describe.skip.apply(this, wrapDescribeInZone(arguments));
  1032. };
  1033. global.describe.only = global.suite.only = function () {
  1034. return mochaOriginal.describe.only.apply(this, wrapDescribeInZone(arguments));
  1035. };
  1036. global.it = global.specify = global.test = function () {
  1037. return mochaOriginal.it.apply(this, wrapTestInZone(arguments));
  1038. };
  1039. global.xit = global.xspecify = global.it.skip = function () {
  1040. return mochaOriginal.it.skip.apply(this, wrapTestInZone(arguments));
  1041. };
  1042. global.it.only = global.test.only = function () {
  1043. return mochaOriginal.it.only.apply(this, wrapTestInZone(arguments));
  1044. };
  1045. global.after = global.suiteTeardown = function () {
  1046. return mochaOriginal.after.apply(this, wrapSuiteInZone(arguments));
  1047. };
  1048. global.afterEach = global.teardown = function () {
  1049. return mochaOriginal.afterEach.apply(this, wrapTestInZone(arguments));
  1050. };
  1051. global.before = global.suiteSetup = function () {
  1052. return mochaOriginal.before.apply(this, wrapSuiteInZone(arguments));
  1053. };
  1054. global.beforeEach = global.setup = function () {
  1055. return mochaOriginal.beforeEach.apply(this, wrapTestInZone(arguments));
  1056. };
  1057. ((originalRunTest, originalRun) => {
  1058. Mocha.Runner.prototype.runTest = function (fn) {
  1059. Zone.current.scheduleMicroTask('mocha.forceTask', () => {
  1060. originalRunTest.call(this, fn);
  1061. });
  1062. };
  1063. Mocha.Runner.prototype.run = function (fn) {
  1064. this.on('test', (e) => {
  1065. testZone = rootZone.fork(new ProxyZoneSpec());
  1066. });
  1067. this.on('fail', (test, err) => {
  1068. const proxyZoneSpec = testZone && testZone.get('ProxyZoneSpec');
  1069. if (proxyZoneSpec && err) {
  1070. try {
  1071. // try catch here in case err.message is not writable
  1072. err.message += proxyZoneSpec.getAndClearPendingTasksInfo();
  1073. }
  1074. catch (error) {
  1075. }
  1076. }
  1077. });
  1078. return originalRun.call(this, fn);
  1079. };
  1080. })(Mocha.Runner.prototype.runTest, Mocha.Runner.prototype.run);
  1081. });
  1082. (function (_global) {
  1083. class AsyncTestZoneSpec {
  1084. static { this.symbolParentUnresolved = Zone.__symbol__('parentUnresolved'); }
  1085. constructor(finishCallback, failCallback, namePrefix) {
  1086. this.finishCallback = finishCallback;
  1087. this.failCallback = failCallback;
  1088. this._pendingMicroTasks = false;
  1089. this._pendingMacroTasks = false;
  1090. this._alreadyErrored = false;
  1091. this._isSync = false;
  1092. this._existingFinishTimer = null;
  1093. this.entryFunction = null;
  1094. this.runZone = Zone.current;
  1095. this.unresolvedChainedPromiseCount = 0;
  1096. this.supportWaitUnresolvedChainedPromise = false;
  1097. this.name = 'asyncTestZone for ' + namePrefix;
  1098. this.properties = { 'AsyncTestZoneSpec': this };
  1099. this.supportWaitUnresolvedChainedPromise =
  1100. _global[Zone.__symbol__('supportWaitUnResolvedChainedPromise')] === true;
  1101. }
  1102. isUnresolvedChainedPromisePending() {
  1103. return this.unresolvedChainedPromiseCount > 0;
  1104. }
  1105. _finishCallbackIfDone() {
  1106. // NOTE: Technically the `onHasTask` could fire together with the initial synchronous
  1107. // completion in `onInvoke`. `onHasTask` might call this method when it captured e.g.
  1108. // microtasks in the proxy zone that now complete as part of this async zone run.
  1109. // Consider the following scenario:
  1110. // 1. A test `beforeEach` schedules a microtask in the ProxyZone.
  1111. // 2. An actual empty `it` spec executes in the AsyncTestZone` (using e.g. `waitForAsync`).
  1112. // 3. The `onInvoke` invokes `_finishCallbackIfDone` because the spec runs synchronously.
  1113. // 4. We wait the scheduled timeout (see below) to account for unhandled promises.
  1114. // 5. The microtask from (1) finishes and `onHasTask` is invoked.
  1115. // --> We register a second `_finishCallbackIfDone` even though we have scheduled a timeout.
  1116. // If the finish timeout from below is already scheduled, terminate the existing scheduled
  1117. // finish invocation, avoiding calling `jasmine` `done` multiple times. *Note* that we would
  1118. // want to schedule a new finish callback in case the task state changes again.
  1119. if (this._existingFinishTimer !== null) {
  1120. clearTimeout(this._existingFinishTimer);
  1121. this._existingFinishTimer = null;
  1122. }
  1123. if (!(this._pendingMicroTasks || this._pendingMacroTasks ||
  1124. (this.supportWaitUnresolvedChainedPromise && this.isUnresolvedChainedPromisePending()))) {
  1125. // We wait until the next tick because we would like to catch unhandled promises which could
  1126. // cause test logic to be executed. In such cases we cannot finish with tasks pending then.
  1127. this.runZone.run(() => {
  1128. this._existingFinishTimer = setTimeout(() => {
  1129. if (!this._alreadyErrored && !(this._pendingMicroTasks || this._pendingMacroTasks)) {
  1130. this.finishCallback();
  1131. }
  1132. }, 0);
  1133. });
  1134. }
  1135. }
  1136. patchPromiseForTest() {
  1137. if (!this.supportWaitUnresolvedChainedPromise) {
  1138. return;
  1139. }
  1140. const patchPromiseForTest = Promise[Zone.__symbol__('patchPromiseForTest')];
  1141. if (patchPromiseForTest) {
  1142. patchPromiseForTest();
  1143. }
  1144. }
  1145. unPatchPromiseForTest() {
  1146. if (!this.supportWaitUnresolvedChainedPromise) {
  1147. return;
  1148. }
  1149. const unPatchPromiseForTest = Promise[Zone.__symbol__('unPatchPromiseForTest')];
  1150. if (unPatchPromiseForTest) {
  1151. unPatchPromiseForTest();
  1152. }
  1153. }
  1154. onScheduleTask(delegate, current, target, task) {
  1155. if (task.type !== 'eventTask') {
  1156. this._isSync = false;
  1157. }
  1158. if (task.type === 'microTask' && task.data && task.data instanceof Promise) {
  1159. // check whether the promise is a chained promise
  1160. if (task.data[AsyncTestZoneSpec.symbolParentUnresolved] === true) {
  1161. // chained promise is being scheduled
  1162. this.unresolvedChainedPromiseCount--;
  1163. }
  1164. }
  1165. return delegate.scheduleTask(target, task);
  1166. }
  1167. onInvokeTask(delegate, current, target, task, applyThis, applyArgs) {
  1168. if (task.type !== 'eventTask') {
  1169. this._isSync = false;
  1170. }
  1171. return delegate.invokeTask(target, task, applyThis, applyArgs);
  1172. }
  1173. onCancelTask(delegate, current, target, task) {
  1174. if (task.type !== 'eventTask') {
  1175. this._isSync = false;
  1176. }
  1177. return delegate.cancelTask(target, task);
  1178. }
  1179. // Note - we need to use onInvoke at the moment to call finish when a test is
  1180. // fully synchronous. TODO(juliemr): remove this when the logic for
  1181. // onHasTask changes and it calls whenever the task queues are dirty.
  1182. // updated by(JiaLiPassion), only call finish callback when no task
  1183. // was scheduled/invoked/canceled.
  1184. onInvoke(parentZoneDelegate, currentZone, targetZone, delegate, applyThis, applyArgs, source) {
  1185. if (!this.entryFunction) {
  1186. this.entryFunction = delegate;
  1187. }
  1188. try {
  1189. this._isSync = true;
  1190. return parentZoneDelegate.invoke(targetZone, delegate, applyThis, applyArgs, source);
  1191. }
  1192. finally {
  1193. // We need to check the delegate is the same as entryFunction or not.
  1194. // Consider the following case.
  1195. //
  1196. // asyncTestZone.run(() => { // Here the delegate will be the entryFunction
  1197. // Zone.current.run(() => { // Here the delegate will not be the entryFunction
  1198. // });
  1199. // });
  1200. //
  1201. // We only want to check whether there are async tasks scheduled
  1202. // for the entry function.
  1203. if (this._isSync && this.entryFunction === delegate) {
  1204. this._finishCallbackIfDone();
  1205. }
  1206. }
  1207. }
  1208. onHandleError(parentZoneDelegate, currentZone, targetZone, error) {
  1209. // Let the parent try to handle the error.
  1210. const result = parentZoneDelegate.handleError(targetZone, error);
  1211. if (result) {
  1212. this.failCallback(error);
  1213. this._alreadyErrored = true;
  1214. }
  1215. return false;
  1216. }
  1217. onHasTask(delegate, current, target, hasTaskState) {
  1218. delegate.hasTask(target, hasTaskState);
  1219. // We should only trigger finishCallback when the target zone is the AsyncTestZone
  1220. // Consider the following cases.
  1221. //
  1222. // const childZone = asyncTestZone.fork({
  1223. // name: 'child',
  1224. // onHasTask: ...
  1225. // });
  1226. //
  1227. // So we have nested zones declared the onHasTask hook, in this case,
  1228. // the onHasTask will be triggered twice, and cause the finishCallbackIfDone()
  1229. // is also be invoked twice. So we need to only trigger the finishCallbackIfDone()
  1230. // when the current zone is the same as the target zone.
  1231. if (current !== target) {
  1232. return;
  1233. }
  1234. if (hasTaskState.change == 'microTask') {
  1235. this._pendingMicroTasks = hasTaskState.microTask;
  1236. this._finishCallbackIfDone();
  1237. }
  1238. else if (hasTaskState.change == 'macroTask') {
  1239. this._pendingMacroTasks = hasTaskState.macroTask;
  1240. this._finishCallbackIfDone();
  1241. }
  1242. }
  1243. }
  1244. // Export the class so that new instances can be created with proper
  1245. // constructor params.
  1246. Zone['AsyncTestZoneSpec'] = AsyncTestZoneSpec;
  1247. })(typeof window !== 'undefined' && window || typeof self !== 'undefined' && self || global);
  1248. Zone.__load_patch('asynctest', (global, Zone, api) => {
  1249. /**
  1250. * Wraps a test function in an asynchronous test zone. The test will automatically
  1251. * complete when all asynchronous calls within this zone are done.
  1252. */
  1253. Zone[api.symbol('asyncTest')] = function asyncTest(fn) {
  1254. // If we're running using the Jasmine test framework, adapt to call the 'done'
  1255. // function when asynchronous activity is finished.
  1256. if (global.jasmine) {
  1257. // Not using an arrow function to preserve context passed from call site
  1258. return function (done) {
  1259. if (!done) {
  1260. // if we run beforeEach in @angular/core/testing/testing_internal then we get no done
  1261. // fake it here and assume sync.
  1262. done = function () { };
  1263. done.fail = function (e) {
  1264. throw e;
  1265. };
  1266. }
  1267. runInTestZone(fn, this, done, (err) => {
  1268. if (typeof err === 'string') {
  1269. return done.fail(new Error(err));
  1270. }
  1271. else {
  1272. done.fail(err);
  1273. }
  1274. });
  1275. };
  1276. }
  1277. // Otherwise, return a promise which will resolve when asynchronous activity
  1278. // is finished. This will be correctly consumed by the Mocha framework with
  1279. // it('...', async(myFn)); or can be used in a custom framework.
  1280. // Not using an arrow function to preserve context passed from call site
  1281. return function () {
  1282. return new Promise((finishCallback, failCallback) => {
  1283. runInTestZone(fn, this, finishCallback, failCallback);
  1284. });
  1285. };
  1286. };
  1287. function runInTestZone(fn, context, finishCallback, failCallback) {
  1288. const currentZone = Zone.current;
  1289. const AsyncTestZoneSpec = Zone['AsyncTestZoneSpec'];
  1290. if (AsyncTestZoneSpec === undefined) {
  1291. throw new Error('AsyncTestZoneSpec is needed for the async() test helper but could not be found. ' +
  1292. 'Please make sure that your environment includes zone.js/plugins/async-test');
  1293. }
  1294. const ProxyZoneSpec = Zone['ProxyZoneSpec'];
  1295. if (!ProxyZoneSpec) {
  1296. throw new Error('ProxyZoneSpec is needed for the async() test helper but could not be found. ' +
  1297. 'Please make sure that your environment includes zone.js/plugins/proxy');
  1298. }
  1299. const proxyZoneSpec = ProxyZoneSpec.get();
  1300. ProxyZoneSpec.assertPresent();
  1301. // We need to create the AsyncTestZoneSpec outside the ProxyZone.
  1302. // If we do it in ProxyZone then we will get to infinite recursion.
  1303. const proxyZone = Zone.current.getZoneWith('ProxyZoneSpec');
  1304. const previousDelegate = proxyZoneSpec.getDelegate();
  1305. proxyZone.parent.run(() => {
  1306. const testZoneSpec = new AsyncTestZoneSpec(() => {
  1307. // Need to restore the original zone.
  1308. if (proxyZoneSpec.getDelegate() == testZoneSpec) {
  1309. // Only reset the zone spec if it's
  1310. // still this one. Otherwise, assume
  1311. // it's OK.
  1312. proxyZoneSpec.setDelegate(previousDelegate);
  1313. }
  1314. testZoneSpec.unPatchPromiseForTest();
  1315. currentZone.run(() => {
  1316. finishCallback();
  1317. });
  1318. }, (error) => {
  1319. // Need to restore the original zone.
  1320. if (proxyZoneSpec.getDelegate() == testZoneSpec) {
  1321. // Only reset the zone spec if it's sill this one. Otherwise, assume it's OK.
  1322. proxyZoneSpec.setDelegate(previousDelegate);
  1323. }
  1324. testZoneSpec.unPatchPromiseForTest();
  1325. currentZone.run(() => {
  1326. failCallback(error);
  1327. });
  1328. }, 'test');
  1329. proxyZoneSpec.setDelegate(testZoneSpec);
  1330. testZoneSpec.patchPromiseForTest();
  1331. });
  1332. return Zone.current.runGuarded(fn, context);
  1333. }
  1334. });
  1335. (function (global) {
  1336. const OriginalDate = global.Date;
  1337. // Since when we compile this file to `es2015`, and if we define
  1338. // this `FakeDate` as `class FakeDate`, and then set `FakeDate.prototype`
  1339. // there will be an error which is `Cannot assign to read only property 'prototype'`
  1340. // so we need to use function implementation here.
  1341. function FakeDate() {
  1342. if (arguments.length === 0) {
  1343. const d = new OriginalDate();
  1344. d.setTime(FakeDate.now());
  1345. return d;
  1346. }
  1347. else {
  1348. const args = Array.prototype.slice.call(arguments);
  1349. return new OriginalDate(...args);
  1350. }
  1351. }
  1352. FakeDate.now = function () {
  1353. const fakeAsyncTestZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec');
  1354. if (fakeAsyncTestZoneSpec) {
  1355. return fakeAsyncTestZoneSpec.getFakeSystemTime();
  1356. }
  1357. return OriginalDate.now.apply(this, arguments);
  1358. };
  1359. FakeDate.UTC = OriginalDate.UTC;
  1360. FakeDate.parse = OriginalDate.parse;
  1361. // keep a reference for zone patched timer function
  1362. const timers = {
  1363. setTimeout: global.setTimeout,
  1364. setInterval: global.setInterval,
  1365. clearTimeout: global.clearTimeout,
  1366. clearInterval: global.clearInterval
  1367. };
  1368. class Scheduler {
  1369. // Next scheduler id.
  1370. static { this.nextId = 1; }
  1371. constructor() {
  1372. // Scheduler queue with the tuple of end time and callback function - sorted by end time.
  1373. this._schedulerQueue = [];
  1374. // Current simulated time in millis.
  1375. this._currentTickTime = 0;
  1376. // Current fake system base time in millis.
  1377. this._currentFakeBaseSystemTime = OriginalDate.now();
  1378. // track requeuePeriodicTimer
  1379. this._currentTickRequeuePeriodicEntries = [];
  1380. }
  1381. getCurrentTickTime() {
  1382. return this._currentTickTime;
  1383. }
  1384. getFakeSystemTime() {
  1385. return this._currentFakeBaseSystemTime + this._currentTickTime;
  1386. }
  1387. setFakeBaseSystemTime(fakeBaseSystemTime) {
  1388. this._currentFakeBaseSystemTime = fakeBaseSystemTime;
  1389. }
  1390. getRealSystemTime() {
  1391. return OriginalDate.now();
  1392. }
  1393. scheduleFunction(cb, delay, options) {
  1394. options = {
  1395. ...{
  1396. args: [],
  1397. isPeriodic: false,
  1398. isRequestAnimationFrame: false,
  1399. id: -1,
  1400. isRequeuePeriodic: false
  1401. },
  1402. ...options
  1403. };
  1404. let currentId = options.id < 0 ? Scheduler.nextId++ : options.id;
  1405. let endTime = this._currentTickTime + delay;
  1406. // Insert so that scheduler queue remains sorted by end time.
  1407. let newEntry = {
  1408. endTime: endTime,
  1409. id: currentId,
  1410. func: cb,
  1411. args: options.args,
  1412. delay: delay,
  1413. isPeriodic: options.isPeriodic,
  1414. isRequestAnimationFrame: options.isRequestAnimationFrame
  1415. };
  1416. if (options.isRequeuePeriodic) {
  1417. this._currentTickRequeuePeriodicEntries.push(newEntry);
  1418. }
  1419. let i = 0;
  1420. for (; i < this._schedulerQueue.length; i++) {
  1421. let currentEntry = this._schedulerQueue[i];
  1422. if (newEntry.endTime < currentEntry.endTime) {
  1423. break;
  1424. }
  1425. }
  1426. this._schedulerQueue.splice(i, 0, newEntry);
  1427. return currentId;
  1428. }
  1429. removeScheduledFunctionWithId(id) {
  1430. for (let i = 0; i < this._schedulerQueue.length; i++) {
  1431. if (this._schedulerQueue[i].id == id) {
  1432. this._schedulerQueue.splice(i, 1);
  1433. break;
  1434. }
  1435. }
  1436. }
  1437. removeAll() {
  1438. this._schedulerQueue = [];
  1439. }
  1440. getTimerCount() {
  1441. return this._schedulerQueue.length;
  1442. }
  1443. tickToNext(step = 1, doTick, tickOptions) {
  1444. if (this._schedulerQueue.length < step) {
  1445. return;
  1446. }
  1447. // Find the last task currently queued in the scheduler queue and tick
  1448. // till that time.
  1449. const startTime = this._currentTickTime;
  1450. const targetTask = this._schedulerQueue[step - 1];
  1451. this.tick(targetTask.endTime - startTime, doTick, tickOptions);
  1452. }
  1453. tick(millis = 0, doTick, tickOptions) {
  1454. let finalTime = this._currentTickTime + millis;
  1455. let lastCurrentTime = 0;
  1456. tickOptions = Object.assign({ processNewMacroTasksSynchronously: true }, tickOptions);
  1457. // we need to copy the schedulerQueue so nested timeout
  1458. // will not be wrongly called in the current tick
  1459. // https://github.com/angular/angular/issues/33799
  1460. const schedulerQueue = tickOptions.processNewMacroTasksSynchronously ?
  1461. this._schedulerQueue :
  1462. this._schedulerQueue.slice();
  1463. if (schedulerQueue.length === 0 && doTick) {
  1464. doTick(millis);
  1465. return;
  1466. }
  1467. while (schedulerQueue.length > 0) {
  1468. // clear requeueEntries before each loop
  1469. this._currentTickRequeuePeriodicEntries = [];
  1470. let current = schedulerQueue[0];
  1471. if (finalTime < current.endTime) {
  1472. // Done processing the queue since it's sorted by endTime.
  1473. break;
  1474. }
  1475. else {
  1476. // Time to run scheduled function. Remove it from the head of queue.
  1477. let current = schedulerQueue.shift();
  1478. if (!tickOptions.processNewMacroTasksSynchronously) {
  1479. const idx = this._schedulerQueue.indexOf(current);
  1480. if (idx >= 0) {
  1481. this._schedulerQueue.splice(idx, 1);
  1482. }
  1483. }
  1484. lastCurrentTime = this._currentTickTime;
  1485. this._currentTickTime = current.endTime;
  1486. if (doTick) {
  1487. doTick(this._currentTickTime - lastCurrentTime);
  1488. }
  1489. let retval = current.func.apply(global, current.isRequestAnimationFrame ? [this._currentTickTime] : current.args);
  1490. if (!retval) {
  1491. // Uncaught exception in the current scheduled function. Stop processing the queue.
  1492. break;
  1493. }
  1494. // check is there any requeue periodic entry is added in
  1495. // current loop, if there is, we need to add to current loop
  1496. if (!tickOptions.processNewMacroTasksSynchronously) {
  1497. this._currentTickRequeuePeriodicEntries.forEach(newEntry => {
  1498. let i = 0;
  1499. for (; i < schedulerQueue.length; i++) {
  1500. const currentEntry = schedulerQueue[i];
  1501. if (newEntry.endTime < currentEntry.endTime) {
  1502. break;
  1503. }
  1504. }
  1505. schedulerQueue.splice(i, 0, newEntry);
  1506. });
  1507. }
  1508. }
  1509. }
  1510. lastCurrentTime = this._currentTickTime;
  1511. this._currentTickTime = finalTime;
  1512. if (doTick) {
  1513. doTick(this._currentTickTime - lastCurrentTime);
  1514. }
  1515. }
  1516. flushOnlyPendingTimers(doTick) {
  1517. if (this._schedulerQueue.length === 0) {
  1518. return 0;
  1519. }
  1520. // Find the last task currently queued in the scheduler queue and tick
  1521. // till that time.
  1522. const startTime = this._currentTickTime;
  1523. const lastTask = this._schedulerQueue[this._schedulerQueue.length - 1];
  1524. this.tick(lastTask.endTime - startTime, doTick, { processNewMacroTasksSynchronously: false });
  1525. return this._currentTickTime - startTime;
  1526. }
  1527. flush(limit = 20, flushPeriodic = false, doTick) {
  1528. if (flushPeriodic) {
  1529. return this.flushPeriodic(doTick);
  1530. }
  1531. else {
  1532. return this.flushNonPeriodic(limit, doTick);
  1533. }
  1534. }
  1535. flushPeriodic(doTick) {
  1536. if (this._schedulerQueue.length === 0) {
  1537. return 0;
  1538. }
  1539. // Find the last task currently queued in the scheduler queue and tick
  1540. // till that time.
  1541. const startTime = this._currentTickTime;
  1542. const lastTask = this._schedulerQueue[this._schedulerQueue.length - 1];
  1543. this.tick(lastTask.endTime - startTime, doTick);
  1544. return this._currentTickTime - startTime;
  1545. }
  1546. flushNonPeriodic(limit, doTick) {
  1547. const startTime = this._currentTickTime;
  1548. let lastCurrentTime = 0;
  1549. let count = 0;
  1550. while (this._schedulerQueue.length > 0) {
  1551. count++;
  1552. if (count > limit) {
  1553. throw new Error('flush failed after reaching the limit of ' + limit +
  1554. ' tasks. Does your code use a polling timeout?');
  1555. }
  1556. // flush only non-periodic timers.
  1557. // If the only remaining tasks are periodic(or requestAnimationFrame), finish flushing.
  1558. if (this._schedulerQueue.filter(task => !task.isPeriodic && !task.isRequestAnimationFrame)
  1559. .length === 0) {
  1560. break;
  1561. }
  1562. const current = this._schedulerQueue.shift();
  1563. lastCurrentTime = this._currentTickTime;
  1564. this._currentTickTime = current.endTime;
  1565. if (doTick) {
  1566. // Update any secondary schedulers like Jasmine mock Date.
  1567. doTick(this._currentTickTime - lastCurrentTime);
  1568. }
  1569. const retval = current.func.apply(global, current.args);
  1570. if (!retval) {
  1571. // Uncaught exception in the current scheduled function. Stop processing the queue.
  1572. break;
  1573. }
  1574. }
  1575. return this._currentTickTime - startTime;
  1576. }
  1577. }
  1578. class FakeAsyncTestZoneSpec {
  1579. static assertInZone() {
  1580. if (Zone.current.get('FakeAsyncTestZoneSpec') == null) {
  1581. throw new Error('The code should be running in the fakeAsync zone to call this function');
  1582. }
  1583. }
  1584. constructor(namePrefix, trackPendingRequestAnimationFrame = false, macroTaskOptions) {
  1585. this.trackPendingRequestAnimationFrame = trackPendingRequestAnimationFrame;
  1586. this.macroTaskOptions = macroTaskOptions;
  1587. this._scheduler = new Scheduler();
  1588. this._microtasks = [];
  1589. this._lastError = null;
  1590. this._uncaughtPromiseErrors = Promise[Zone.__symbol__('uncaughtPromiseErrors')];
  1591. this.pendingPeriodicTimers = [];
  1592. this.pendingTimers = [];
  1593. this.patchDateLocked = false;
  1594. this.properties = { 'FakeAsyncTestZoneSpec': this };
  1595. this.name = 'fakeAsyncTestZone for ' + namePrefix;
  1596. // in case user can't access the construction of FakeAsyncTestSpec
  1597. // user can also define macroTaskOptions by define a global variable.
  1598. if (!this.macroTaskOptions) {
  1599. this.macroTaskOptions = global[Zone.__symbol__('FakeAsyncTestMacroTask')];
  1600. }
  1601. }
  1602. _fnAndFlush(fn, completers) {
  1603. return (...args) => {
  1604. fn.apply(global, args);
  1605. if (this._lastError === null) { // Success
  1606. if (completers.onSuccess != null) {
  1607. completers.onSuccess.apply(global);
  1608. }
  1609. // Flush microtasks only on success.
  1610. this.flushMicrotasks();
  1611. }
  1612. else { // Failure
  1613. if (completers.onError != null) {
  1614. completers.onError.apply(global);
  1615. }
  1616. }
  1617. // Return true if there were no errors, false otherwise.
  1618. return this._lastError === null;
  1619. };
  1620. }
  1621. static _removeTimer(timers, id) {
  1622. let index = timers.indexOf(id);
  1623. if (index > -1) {
  1624. timers.splice(index, 1);
  1625. }
  1626. }
  1627. _dequeueTimer(id) {
  1628. return () => {
  1629. FakeAsyncTestZoneSpec._removeTimer(this.pendingTimers, id);
  1630. };
  1631. }
  1632. _requeuePeriodicTimer(fn, interval, args, id) {
  1633. return () => {
  1634. // Requeue the timer callback if it's not been canceled.
  1635. if (this.pendingPeriodicTimers.indexOf(id) !== -1) {
  1636. this._scheduler.scheduleFunction(fn, interval, { args, isPeriodic: true, id, isRequeuePeriodic: true });
  1637. }
  1638. };
  1639. }
  1640. _dequeuePeriodicTimer(id) {
  1641. return () => {
  1642. FakeAsyncTestZoneSpec._removeTimer(this.pendingPeriodicTimers, id);
  1643. };
  1644. }
  1645. _setTimeout(fn, delay, args, isTimer = true) {
  1646. let removeTimerFn = this._dequeueTimer(Scheduler.nextId);
  1647. // Queue the callback and dequeue the timer on success and error.
  1648. let cb = this._fnAndFlush(fn, { onSuccess: removeTimerFn, onError: removeTimerFn });
  1649. let id = this._scheduler.scheduleFunction(cb, delay, { args, isRequestAnimationFrame: !isTimer });
  1650. if (isTimer) {
  1651. this.pendingTimers.push(id);
  1652. }
  1653. return id;
  1654. }
  1655. _clearTimeout(id) {
  1656. FakeAsyncTestZoneSpec._removeTimer(this.pendingTimers, id);
  1657. this._scheduler.removeScheduledFunctionWithId(id);
  1658. }
  1659. _setInterval(fn, interval, args) {
  1660. let id = Scheduler.nextId;
  1661. let completers = { onSuccess: null, onError: this._dequeuePeriodicTimer(id) };
  1662. let cb = this._fnAndFlush(fn, completers);
  1663. // Use the callback created above to requeue on success.
  1664. completers.onSuccess = this._requeuePeriodicTimer(cb, interval, args, id);
  1665. // Queue the callback and dequeue the periodic timer only on error.
  1666. this._scheduler.scheduleFunction(cb, interval, { args, isPeriodic: true });
  1667. this.pendingPeriodicTimers.push(id);
  1668. return id;
  1669. }
  1670. _clearInterval(id) {
  1671. FakeAsyncTestZoneSpec._removeTimer(this.pendingPeriodicTimers, id);
  1672. this._scheduler.removeScheduledFunctionWithId(id);
  1673. }
  1674. _resetLastErrorAndThrow() {
  1675. let error = this._lastError || this._uncaughtPromiseErrors[0];
  1676. this._uncaughtPromiseErrors.length = 0;
  1677. this._lastError = null;
  1678. throw error;
  1679. }
  1680. getCurrentTickTime() {
  1681. return this._scheduler.getCurrentTickTime();
  1682. }
  1683. getFakeSystemTime() {
  1684. return this._scheduler.getFakeSystemTime();
  1685. }
  1686. setFakeBaseSystemTime(realTime) {
  1687. this._scheduler.setFakeBaseSystemTime(realTime);
  1688. }
  1689. getRealSystemTime() {
  1690. return this._scheduler.getRealSystemTime();
  1691. }
  1692. static patchDate() {
  1693. if (!!global[Zone.__symbol__('disableDatePatching')]) {
  1694. // we don't want to patch global Date
  1695. // because in some case, global Date
  1696. // is already being patched, we need to provide
  1697. // an option to let user still use their
  1698. // own version of Date.
  1699. return;
  1700. }
  1701. if (global['Date'] === FakeDate) {
  1702. // already patched
  1703. return;
  1704. }
  1705. global['Date'] = FakeDate;
  1706. FakeDate.prototype = OriginalDate.prototype;
  1707. // try check and reset timers
  1708. // because jasmine.clock().install() may
  1709. // have replaced the global timer
  1710. FakeAsyncTestZoneSpec.checkTimerPatch();
  1711. }
  1712. static resetDate() {
  1713. if (global['Date'] === FakeDate) {
  1714. global['Date'] = OriginalDate;
  1715. }
  1716. }
  1717. static checkTimerPatch() {
  1718. if (global.setTimeout !== timers.setTimeout) {
  1719. global.setTimeout = timers.setTimeout;
  1720. global.clearTimeout = timers.clearTimeout;
  1721. }
  1722. if (global.setInterval !== timers.setInterval) {
  1723. global.setInterval = timers.setInterval;
  1724. global.clearInterval = timers.clearInterval;
  1725. }
  1726. }
  1727. lockDatePatch() {
  1728. this.patchDateLocked = true;
  1729. FakeAsyncTestZoneSpec.patchDate();
  1730. }
  1731. unlockDatePatch() {
  1732. this.patchDateLocked = false;
  1733. FakeAsyncTestZoneSpec.resetDate();
  1734. }
  1735. tickToNext(steps = 1, doTick, tickOptions = { processNewMacroTasksSynchronously: true }) {
  1736. if (steps <= 0) {
  1737. return;
  1738. }
  1739. FakeAsyncTestZoneSpec.assertInZone();
  1740. this.flushMicrotasks();
  1741. this._scheduler.tickToNext(steps, doTick, tickOptions);
  1742. if (this._lastError !== null) {
  1743. this._resetLastErrorAndThrow();
  1744. }
  1745. }
  1746. tick(millis = 0, doTick, tickOptions = { processNewMacroTasksSynchronously: true }) {
  1747. FakeAsyncTestZoneSpec.assertInZone();
  1748. this.flushMicrotasks();
  1749. this._scheduler.tick(millis, doTick, tickOptions);
  1750. if (this._lastError !== null) {
  1751. this._resetLastErrorAndThrow();
  1752. }
  1753. }
  1754. flushMicrotasks() {
  1755. FakeAsyncTestZoneSpec.assertInZone();
  1756. const flushErrors = () => {
  1757. if (this._lastError !== null || this._uncaughtPromiseErrors.length) {
  1758. // If there is an error stop processing the microtask queue and rethrow the error.
  1759. this._resetLastErrorAndThrow();
  1760. }
  1761. };
  1762. while (this._microtasks.length > 0) {
  1763. let microtask = this._microtasks.shift();
  1764. microtask.func.apply(microtask.target, microtask.args);
  1765. }
  1766. flushErrors();
  1767. }
  1768. flush(limit, flushPeriodic, doTick) {
  1769. FakeAsyncTestZoneSpec.assertInZone();
  1770. this.flushMicrotasks();
  1771. const elapsed = this._scheduler.flush(limit, flushPeriodic, doTick);
  1772. if (this._lastError !== null) {
  1773. this._resetLastErrorAndThrow();
  1774. }
  1775. return elapsed;
  1776. }
  1777. flushOnlyPendingTimers(doTick) {
  1778. FakeAsyncTestZoneSpec.assertInZone();
  1779. this.flushMicrotasks();
  1780. const elapsed = this._scheduler.flushOnlyPendingTimers(doTick);
  1781. if (this._lastError !== null) {
  1782. this._resetLastErrorAndThrow();
  1783. }
  1784. return elapsed;
  1785. }
  1786. removeAllTimers() {
  1787. FakeAsyncTestZoneSpec.assertInZone();
  1788. this._scheduler.removeAll();
  1789. this.pendingPeriodicTimers = [];
  1790. this.pendingTimers = [];
  1791. }
  1792. getTimerCount() {
  1793. return this._scheduler.getTimerCount() + this._microtasks.length;
  1794. }
  1795. onScheduleTask(delegate, current, target, task) {
  1796. switch (task.type) {
  1797. case 'microTask':
  1798. let args = task.data && task.data.args;
  1799. // should pass additional arguments to callback if have any
  1800. // currently we know process.nextTick will have such additional
  1801. // arguments
  1802. let additionalArgs;
  1803. if (args) {
  1804. let callbackIndex = task.data.cbIdx;
  1805. if (typeof args.length === 'number' && args.length > callbackIndex + 1) {
  1806. additionalArgs = Array.prototype.slice.call(args, callbackIndex + 1);
  1807. }
  1808. }
  1809. this._microtasks.push({
  1810. func: task.invoke,
  1811. args: additionalArgs,
  1812. target: task.data && task.data.target
  1813. });
  1814. break;
  1815. case 'macroTask':
  1816. switch (task.source) {
  1817. case 'setTimeout':
  1818. task.data['handleId'] = this._setTimeout(task.invoke, task.data['delay'], Array.prototype.slice.call(task.data['args'], 2));
  1819. break;
  1820. case 'setImmediate':
  1821. task.data['handleId'] = this._setTimeout(task.invoke, 0, Array.prototype.slice.call(task.data['args'], 1));
  1822. break;
  1823. case 'setInterval':
  1824. task.data['handleId'] = this._setInterval(task.invoke, task.data['delay'], Array.prototype.slice.call(task.data['args'], 2));
  1825. break;
  1826. case 'XMLHttpRequest.send':
  1827. throw new Error('Cannot make XHRs from within a fake async test. Request URL: ' +
  1828. task.data['url']);
  1829. case 'requestAnimationFrame':
  1830. case 'webkitRequestAnimationFrame':
  1831. case 'mozRequestAnimationFrame':
  1832. // Simulate a requestAnimationFrame by using a setTimeout with 16 ms.
  1833. // (60 frames per second)
  1834. task.data['handleId'] = this._setTimeout(task.invoke, 16, task.data['args'], this.trackPendingRequestAnimationFrame);
  1835. break;
  1836. default:
  1837. // user can define which macroTask they want to support by passing
  1838. // macroTaskOptions
  1839. const macroTaskOption = this.findMacroTaskOption(task);
  1840. if (macroTaskOption) {
  1841. const args = task.data && task.data['args'];
  1842. const delay = args && args.length > 1 ? args[1] : 0;
  1843. let callbackArgs = macroTaskOption.callbackArgs ? macroTaskOption.callbackArgs : args;
  1844. if (!!macroTaskOption.isPeriodic) {
  1845. // periodic macroTask, use setInterval to simulate
  1846. task.data['handleId'] = this._setInterval(task.invoke, delay, callbackArgs);
  1847. task.data.isPeriodic = true;
  1848. }
  1849. else {
  1850. // not periodic, use setTimeout to simulate
  1851. task.data['handleId'] = this._setTimeout(task.invoke, delay, callbackArgs);
  1852. }
  1853. break;
  1854. }
  1855. throw new Error('Unknown macroTask scheduled in fake async test: ' + task.source);
  1856. }
  1857. break;
  1858. case 'eventTask':
  1859. task = delegate.scheduleTask(target, task);
  1860. break;
  1861. }
  1862. return task;
  1863. }
  1864. onCancelTask(delegate, current, target, task) {
  1865. switch (task.source) {
  1866. case 'setTimeout':
  1867. case 'requestAnimationFrame':
  1868. case 'webkitRequestAnimationFrame':
  1869. case 'mozRequestAnimationFrame':
  1870. return this._clearTimeout(task.data['handleId']);
  1871. case 'setInterval':
  1872. return this._clearInterval(task.data['handleId']);
  1873. default:
  1874. // user can define which macroTask they want to support by passing
  1875. // macroTaskOptions
  1876. const macroTaskOption = this.findMacroTaskOption(task);
  1877. if (macroTaskOption) {
  1878. const handleId = task.data['handleId'];
  1879. return macroTaskOption.isPeriodic ? this._clearInterval(handleId) :
  1880. this._clearTimeout(handleId);
  1881. }
  1882. return delegate.cancelTask(target, task);
  1883. }
  1884. }
  1885. onInvoke(delegate, current, target, callback, applyThis, applyArgs, source) {
  1886. try {
  1887. FakeAsyncTestZoneSpec.patchDate();
  1888. return delegate.invoke(target, callback, applyThis, applyArgs, source);
  1889. }
  1890. finally {
  1891. if (!this.patchDateLocked) {
  1892. FakeAsyncTestZoneSpec.resetDate();
  1893. }
  1894. }
  1895. }
  1896. findMacroTaskOption(task) {
  1897. if (!this.macroTaskOptions) {
  1898. return null;
  1899. }
  1900. for (let i = 0; i < this.macroTaskOptions.length; i++) {
  1901. const macroTaskOption = this.macroTaskOptions[i];
  1902. if (macroTaskOption.source === task.source) {
  1903. return macroTaskOption;
  1904. }
  1905. }
  1906. return null;
  1907. }
  1908. onHandleError(parentZoneDelegate, currentZone, targetZone, error) {
  1909. this._lastError = error;
  1910. return false; // Don't propagate error to parent zone.
  1911. }
  1912. }
  1913. // Export the class so that new instances can be created with proper
  1914. // constructor params.
  1915. Zone['FakeAsyncTestZoneSpec'] = FakeAsyncTestZoneSpec;
  1916. })(typeof window === 'object' && window || typeof self === 'object' && self || global);
  1917. Zone.__load_patch('fakeasync', (global, Zone, api) => {
  1918. const FakeAsyncTestZoneSpec = Zone && Zone['FakeAsyncTestZoneSpec'];
  1919. function getProxyZoneSpec() {
  1920. return Zone && Zone['ProxyZoneSpec'];
  1921. }
  1922. let _fakeAsyncTestZoneSpec = null;
  1923. /**
  1924. * Clears out the shared fake async zone for a test.
  1925. * To be called in a global `beforeEach`.
  1926. *
  1927. * @experimental
  1928. */
  1929. function resetFakeAsyncZone() {
  1930. if (_fakeAsyncTestZoneSpec) {
  1931. _fakeAsyncTestZoneSpec.unlockDatePatch();
  1932. }
  1933. _fakeAsyncTestZoneSpec = null;
  1934. // in node.js testing we may not have ProxyZoneSpec in which case there is nothing to reset.
  1935. getProxyZoneSpec() && getProxyZoneSpec().assertPresent().resetDelegate();
  1936. }
  1937. /**
  1938. * Wraps a function to be executed in the fakeAsync zone:
  1939. * - microtasks are manually executed by calling `flushMicrotasks()`,
  1940. * - timers are synchronous, `tick()` simulates the asynchronous passage of time.
  1941. *
  1942. * If there are any pending timers at the end of the function, an exception will be thrown.
  1943. *
  1944. * Can be used to wrap inject() calls.
  1945. *
  1946. * ## Example
  1947. *
  1948. * {@example core/testing/ts/fake_async.ts region='basic'}
  1949. *
  1950. * @param fn
  1951. * @returns The function wrapped to be executed in the fakeAsync zone
  1952. *
  1953. * @experimental
  1954. */
  1955. function fakeAsync(fn) {
  1956. // Not using an arrow function to preserve context passed from call site
  1957. const fakeAsyncFn = function (...args) {
  1958. const ProxyZoneSpec = getProxyZoneSpec();
  1959. if (!ProxyZoneSpec) {
  1960. throw new Error('ProxyZoneSpec is needed for the async() test helper but could not be found. ' +
  1961. 'Please make sure that your environment includes zone.js/plugins/proxy');
  1962. }
  1963. const proxyZoneSpec = ProxyZoneSpec.assertPresent();
  1964. if (Zone.current.get('FakeAsyncTestZoneSpec')) {
  1965. throw new Error('fakeAsync() calls can not be nested');
  1966. }
  1967. try {
  1968. // in case jasmine.clock init a fakeAsyncTestZoneSpec
  1969. if (!_fakeAsyncTestZoneSpec) {
  1970. if (proxyZoneSpec.getDelegate() instanceof FakeAsyncTestZoneSpec) {
  1971. throw new Error('fakeAsync() calls can not be nested');
  1972. }
  1973. _fakeAsyncTestZoneSpec = new FakeAsyncTestZoneSpec();
  1974. }
  1975. let res;
  1976. const lastProxyZoneSpec = proxyZoneSpec.getDelegate();
  1977. proxyZoneSpec.setDelegate(_fakeAsyncTestZoneSpec);
  1978. _fakeAsyncTestZoneSpec.lockDatePatch();
  1979. try {
  1980. res = fn.apply(this, args);
  1981. flushMicrotasks();
  1982. }
  1983. finally {
  1984. proxyZoneSpec.setDelegate(lastProxyZoneSpec);
  1985. }
  1986. if (_fakeAsyncTestZoneSpec.pendingPeriodicTimers.length > 0) {
  1987. throw new Error(`${_fakeAsyncTestZoneSpec.pendingPeriodicTimers.length} ` +
  1988. `periodic timer(s) still in the queue.`);
  1989. }
  1990. if (_fakeAsyncTestZoneSpec.pendingTimers.length > 0) {
  1991. throw new Error(`${_fakeAsyncTestZoneSpec.pendingTimers.length} timer(s) still in the queue.`);
  1992. }
  1993. return res;
  1994. }
  1995. finally {
  1996. resetFakeAsyncZone();
  1997. }
  1998. };
  1999. fakeAsyncFn.isFakeAsync = true;
  2000. return fakeAsyncFn;
  2001. }
  2002. function _getFakeAsyncZoneSpec() {
  2003. if (_fakeAsyncTestZoneSpec == null) {
  2004. _fakeAsyncTestZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec');
  2005. if (_fakeAsyncTestZoneSpec == null) {
  2006. throw new Error('The code should be running in the fakeAsync zone to call this function');
  2007. }
  2008. }
  2009. return _fakeAsyncTestZoneSpec;
  2010. }
  2011. /**
  2012. * Simulates the asynchronous passage of time for the timers in the fakeAsync zone.
  2013. *
  2014. * The microtasks queue is drained at the very start of this function and after any timer callback
  2015. * has been executed.
  2016. *
  2017. * ## Example
  2018. *
  2019. * {@example core/testing/ts/fake_async.ts region='basic'}
  2020. *
  2021. * @experimental
  2022. */
  2023. function tick(millis = 0, ignoreNestedTimeout = false) {
  2024. _getFakeAsyncZoneSpec().tick(millis, null, ignoreNestedTimeout);
  2025. }
  2026. /**
  2027. * Simulates the asynchronous passage of time for the timers in the fakeAsync zone by
  2028. * draining the macrotask queue until it is empty. The returned value is the milliseconds
  2029. * of time that would have been elapsed.
  2030. *
  2031. * @param maxTurns
  2032. * @returns The simulated time elapsed, in millis.
  2033. *
  2034. * @experimental
  2035. */
  2036. function flush(maxTurns) {
  2037. return _getFakeAsyncZoneSpec().flush(maxTurns);
  2038. }
  2039. /**
  2040. * Discard all remaining periodic tasks.
  2041. *
  2042. * @experimental
  2043. */
  2044. function discardPeriodicTasks() {
  2045. const zoneSpec = _getFakeAsyncZoneSpec();
  2046. zoneSpec.pendingPeriodicTimers;
  2047. zoneSpec.pendingPeriodicTimers.length = 0;
  2048. }
  2049. /**
  2050. * Flush any pending microtasks.
  2051. *
  2052. * @experimental
  2053. */
  2054. function flushMicrotasks() {
  2055. _getFakeAsyncZoneSpec().flushMicrotasks();
  2056. }
  2057. Zone[api.symbol('fakeAsyncTest')] =
  2058. { resetFakeAsyncZone, flushMicrotasks, discardPeriodicTasks, tick, flush, fakeAsync };
  2059. }, true);
  2060. /**
  2061. * Promise for async/fakeAsync zoneSpec test
  2062. * can support async operation which not supported by zone.js
  2063. * such as
  2064. * it ('test jsonp in AsyncZone', async() => {
  2065. * new Promise(res => {
  2066. * jsonp(url, (data) => {
  2067. * // success callback
  2068. * res(data);
  2069. * });
  2070. * }).then((jsonpResult) => {
  2071. * // get jsonp result.
  2072. *
  2073. * // user will expect AsyncZoneSpec wait for
  2074. * // then, but because jsonp is not zone aware
  2075. * // AsyncZone will finish before then is called.
  2076. * });
  2077. * });
  2078. */
  2079. Zone.__load_patch('promisefortest', (global, Zone, api) => {
  2080. const symbolState = api.symbol('state');
  2081. const UNRESOLVED = null;
  2082. const symbolParentUnresolved = api.symbol('parentUnresolved');
  2083. // patch Promise.prototype.then to keep an internal
  2084. // number for tracking unresolved chained promise
  2085. // we will decrease this number when the parent promise
  2086. // being resolved/rejected and chained promise was
  2087. // scheduled as a microTask.
  2088. // so we can know such kind of chained promise still
  2089. // not resolved in AsyncTestZone
  2090. Promise[api.symbol('patchPromiseForTest')] = function patchPromiseForTest() {
  2091. let oriThen = Promise[Zone.__symbol__('ZonePromiseThen')];
  2092. if (oriThen) {
  2093. return;
  2094. }
  2095. oriThen = Promise[Zone.__symbol__('ZonePromiseThen')] = Promise.prototype.then;
  2096. Promise.prototype.then = function () {
  2097. const chained = oriThen.apply(this, arguments);
  2098. if (this[symbolState] === UNRESOLVED) {
  2099. // parent promise is unresolved.
  2100. const asyncTestZoneSpec = Zone.current.get('AsyncTestZoneSpec');
  2101. if (asyncTestZoneSpec) {
  2102. asyncTestZoneSpec.unresolvedChainedPromiseCount++;
  2103. chained[symbolParentUnresolved] = true;
  2104. }
  2105. }
  2106. return chained;
  2107. };
  2108. };
  2109. Promise[api.symbol('unPatchPromiseForTest')] = function unpatchPromiseForTest() {
  2110. // restore origin then
  2111. const oriThen = Promise[Zone.__symbol__('ZonePromiseThen')];
  2112. if (oriThen) {
  2113. Promise.prototype.then = oriThen;
  2114. Promise[Zone.__symbol__('ZonePromiseThen')] = undefined;
  2115. }
  2116. };
  2117. });