async-test.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /**
  2. * @license
  3. * Copyright Google Inc. All Rights Reserved.
  4. *
  5. * Use of this source code is governed by an MIT-style license that can be
  6. * found in the LICENSE file at https://angular.io/license
  7. */
  8. (function (global, factory) {
  9. typeof exports === 'object' && typeof module !== 'undefined' ? factory() :
  10. typeof define === 'function' && define.amd ? define(factory) :
  11. (factory());
  12. }(this, (function () { 'use strict';
  13. /**
  14. * @license
  15. * Copyright Google Inc. All Rights Reserved.
  16. *
  17. * Use of this source code is governed by an MIT-style license that can be
  18. * found in the LICENSE file at https://angular.io/license
  19. */
  20. var _global = typeof window !== 'undefined' && window || typeof self !== 'undefined' && self || global;
  21. var AsyncTestZoneSpec = /** @class */ (function () {
  22. function AsyncTestZoneSpec(finishCallback, failCallback, namePrefix) {
  23. this.finishCallback = finishCallback;
  24. this.failCallback = failCallback;
  25. this._pendingMicroTasks = false;
  26. this._pendingMacroTasks = false;
  27. this._alreadyErrored = false;
  28. this._isSync = false;
  29. this.runZone = Zone.current;
  30. this.unresolvedChainedPromiseCount = 0;
  31. this.supportWaitUnresolvedChainedPromise = false;
  32. this.name = 'asyncTestZone for ' + namePrefix;
  33. this.properties = { 'AsyncTestZoneSpec': this };
  34. this.supportWaitUnresolvedChainedPromise =
  35. _global[Zone.__symbol__('supportWaitUnResolvedChainedPromise')] === true;
  36. }
  37. AsyncTestZoneSpec.prototype.isUnresolvedChainedPromisePending = function () {
  38. return this.unresolvedChainedPromiseCount > 0;
  39. };
  40. AsyncTestZoneSpec.prototype._finishCallbackIfDone = function () {
  41. var _this = this;
  42. if (!(this._pendingMicroTasks || this._pendingMacroTasks ||
  43. (this.supportWaitUnresolvedChainedPromise && this.isUnresolvedChainedPromisePending()))) {
  44. // We do this because we would like to catch unhandled rejected promises.
  45. this.runZone.run(function () {
  46. setTimeout(function () {
  47. if (!_this._alreadyErrored && !(_this._pendingMicroTasks || _this._pendingMacroTasks)) {
  48. _this.finishCallback();
  49. }
  50. }, 0);
  51. });
  52. }
  53. };
  54. AsyncTestZoneSpec.prototype.patchPromiseForTest = function () {
  55. if (!this.supportWaitUnresolvedChainedPromise) {
  56. return;
  57. }
  58. var patchPromiseForTest = Promise[Zone.__symbol__('patchPromiseForTest')];
  59. if (patchPromiseForTest) {
  60. patchPromiseForTest();
  61. }
  62. };
  63. AsyncTestZoneSpec.prototype.unPatchPromiseForTest = function () {
  64. if (!this.supportWaitUnresolvedChainedPromise) {
  65. return;
  66. }
  67. var unPatchPromiseForTest = Promise[Zone.__symbol__('unPatchPromiseForTest')];
  68. if (unPatchPromiseForTest) {
  69. unPatchPromiseForTest();
  70. }
  71. };
  72. AsyncTestZoneSpec.prototype.onScheduleTask = function (delegate, current, target, task) {
  73. if (task.type !== 'eventTask') {
  74. this._isSync = false;
  75. }
  76. if (task.type === 'microTask' && task.data && task.data instanceof Promise) {
  77. // check whether the promise is a chained promise
  78. if (task.data[AsyncTestZoneSpec.symbolParentUnresolved] === true) {
  79. // chained promise is being scheduled
  80. this.unresolvedChainedPromiseCount--;
  81. }
  82. }
  83. return delegate.scheduleTask(target, task);
  84. };
  85. AsyncTestZoneSpec.prototype.onInvokeTask = function (delegate, current, target, task, applyThis, applyArgs) {
  86. if (task.type !== 'eventTask') {
  87. this._isSync = false;
  88. }
  89. return delegate.invokeTask(target, task, applyThis, applyArgs);
  90. };
  91. AsyncTestZoneSpec.prototype.onCancelTask = function (delegate, current, target, task) {
  92. if (task.type !== 'eventTask') {
  93. this._isSync = false;
  94. }
  95. return delegate.cancelTask(target, task);
  96. };
  97. // Note - we need to use onInvoke at the moment to call finish when a test is
  98. // fully synchronous. TODO(juliemr): remove this when the logic for
  99. // onHasTask changes and it calls whenever the task queues are dirty.
  100. // updated by(JiaLiPassion), only call finish callback when no task
  101. // was scheduled/invoked/canceled.
  102. AsyncTestZoneSpec.prototype.onInvoke = function (parentZoneDelegate, currentZone, targetZone, delegate, applyThis, applyArgs, source) {
  103. try {
  104. this._isSync = true;
  105. return parentZoneDelegate.invoke(targetZone, delegate, applyThis, applyArgs, source);
  106. }
  107. finally {
  108. var afterTaskCounts = parentZoneDelegate._taskCounts;
  109. if (this._isSync) {
  110. this._finishCallbackIfDone();
  111. }
  112. }
  113. };
  114. AsyncTestZoneSpec.prototype.onHandleError = function (parentZoneDelegate, currentZone, targetZone, error) {
  115. // Let the parent try to handle the error.
  116. var result = parentZoneDelegate.handleError(targetZone, error);
  117. if (result) {
  118. this.failCallback(error);
  119. this._alreadyErrored = true;
  120. }
  121. return false;
  122. };
  123. AsyncTestZoneSpec.prototype.onHasTask = function (delegate, current, target, hasTaskState) {
  124. delegate.hasTask(target, hasTaskState);
  125. if (hasTaskState.change == 'microTask') {
  126. this._pendingMicroTasks = hasTaskState.microTask;
  127. this._finishCallbackIfDone();
  128. }
  129. else if (hasTaskState.change == 'macroTask') {
  130. this._pendingMacroTasks = hasTaskState.macroTask;
  131. this._finishCallbackIfDone();
  132. }
  133. };
  134. AsyncTestZoneSpec.symbolParentUnresolved = Zone.__symbol__('parentUnresolved');
  135. return AsyncTestZoneSpec;
  136. }());
  137. // Export the class so that new instances can be created with proper
  138. // constructor params.
  139. Zone['AsyncTestZoneSpec'] = AsyncTestZoneSpec;
  140. /**
  141. * @license
  142. * Copyright Google Inc. All Rights Reserved.
  143. *
  144. * Use of this source code is governed by an MIT-style license that can be
  145. * found in the LICENSE file at https://angular.io/license
  146. */
  147. Zone.__load_patch('asynctest', function (global, Zone, api) {
  148. /**
  149. * Wraps a test function in an asynchronous test zone. The test will automatically
  150. * complete when all asynchronous calls within this zone are done.
  151. */
  152. Zone[api.symbol('asyncTest')] = function asyncTest(fn) {
  153. // If we're running using the Jasmine test framework, adapt to call the 'done'
  154. // function when asynchronous activity is finished.
  155. if (global.jasmine) {
  156. // Not using an arrow function to preserve context passed from call site
  157. return function (done) {
  158. if (!done) {
  159. // if we run beforeEach in @angular/core/testing/testing_internal then we get no done
  160. // fake it here and assume sync.
  161. done = function () { };
  162. done.fail = function (e) {
  163. throw e;
  164. };
  165. }
  166. runInTestZone(fn, this, done, function (err) {
  167. if (typeof err === 'string') {
  168. return done.fail(new Error(err));
  169. }
  170. else {
  171. done.fail(err);
  172. }
  173. });
  174. };
  175. }
  176. // Otherwise, return a promise which will resolve when asynchronous activity
  177. // is finished. This will be correctly consumed by the Mocha framework with
  178. // it('...', async(myFn)); or can be used in a custom framework.
  179. // Not using an arrow function to preserve context passed from call site
  180. return function () {
  181. var _this = this;
  182. return new Promise(function (finishCallback, failCallback) {
  183. runInTestZone(fn, _this, finishCallback, failCallback);
  184. });
  185. };
  186. };
  187. function runInTestZone(fn, context, finishCallback, failCallback) {
  188. var currentZone = Zone.current;
  189. var AsyncTestZoneSpec = Zone['AsyncTestZoneSpec'];
  190. if (AsyncTestZoneSpec === undefined) {
  191. throw new Error('AsyncTestZoneSpec is needed for the async() test helper but could not be found. ' +
  192. 'Please make sure that your environment includes zone.js/dist/async-test.js');
  193. }
  194. var ProxyZoneSpec = Zone['ProxyZoneSpec'];
  195. if (ProxyZoneSpec === undefined) {
  196. throw new Error('ProxyZoneSpec is needed for the async() test helper but could not be found. ' +
  197. 'Please make sure that your environment includes zone.js/dist/proxy.js');
  198. }
  199. var proxyZoneSpec = ProxyZoneSpec.get();
  200. ProxyZoneSpec.assertPresent();
  201. // We need to create the AsyncTestZoneSpec outside the ProxyZone.
  202. // If we do it in ProxyZone then we will get to infinite recursion.
  203. var proxyZone = Zone.current.getZoneWith('ProxyZoneSpec');
  204. var previousDelegate = proxyZoneSpec.getDelegate();
  205. proxyZone.parent.run(function () {
  206. var testZoneSpec = new AsyncTestZoneSpec(function () {
  207. // Need to restore the original zone.
  208. if (proxyZoneSpec.getDelegate() == testZoneSpec) {
  209. // Only reset the zone spec if it's
  210. // sill this one. Otherwise, assume
  211. // it's OK.
  212. proxyZoneSpec.setDelegate(previousDelegate);
  213. }
  214. testZoneSpec.unPatchPromiseForTest();
  215. currentZone.run(function () {
  216. finishCallback();
  217. });
  218. }, function (error) {
  219. // Need to restore the original zone.
  220. if (proxyZoneSpec.getDelegate() == testZoneSpec) {
  221. // Only reset the zone spec if it's sill this one. Otherwise, assume it's OK.
  222. proxyZoneSpec.setDelegate(previousDelegate);
  223. }
  224. testZoneSpec.unPatchPromiseForTest();
  225. currentZone.run(function () {
  226. failCallback(error);
  227. });
  228. }, 'test');
  229. proxyZoneSpec.setDelegate(testZoneSpec);
  230. testZoneSpec.patchPromiseForTest();
  231. });
  232. return Zone.current.runGuarded(fn, context);
  233. }
  234. });
  235. })));