promise_test.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. // Copyright 2015 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. goog.module('goog.labs.promiseTest');
  15. goog.setTestOnly('goog.labs.promiseTest');
  16. goog.require('goog.testing.jsunit');
  17. var Promise = goog.require('goog.Promise');
  18. var Timer = goog.require('goog.Timer');
  19. var promise = goog.require('goog.labs.promise');
  20. var MockClock = goog.require('goog.testing.MockClock');
  21. var testSuite = goog.require('goog.testing.testSuite');
  22. // Workaround roughly equivalent to the following ES6 code:
  23. //
  24. // function*() {
  25. // while (cond()) {
  26. // yield body();
  27. // }
  28. // }
  29. function whileLoopIterator(cond, body) {
  30. return function() {
  31. var done = false;
  32. return {
  33. next: function(opt_arg) {
  34. done = done || !cond();
  35. if (done) {
  36. return {done: true};
  37. } else {
  38. return {done: false, value: body()};
  39. }
  40. },
  41. 'throw': function(error) { throw error; }
  42. };
  43. };
  44. }
  45. /**
  46. * Dummy onfulfilled or onrejected function that should not be called.
  47. *
  48. * @param {*} result The result passed into the callback.
  49. */
  50. function shouldNotCall(result) {
  51. fail('This should not have been called (result: ' + String(result) + ')');
  52. }
  53. var mockClock;
  54. var sentinel = {};
  55. testSuite({
  56. setUp: function() { mockClock = new MockClock(); },
  57. tearDown: function() { mockClock.uninstall(); },
  58. testWhileLoopIterator: function() {
  59. var counter = 3;
  60. var it = whileLoopIterator(
  61. function() { return counter > 0; }, function() { --counter; })();
  62. assertEquals(3, counter);
  63. assertFalse(it.next().done);
  64. assertEquals(2, counter);
  65. assertFalse(it.next().done);
  66. assertEquals(1, counter);
  67. assertFalse(it.next().done);
  68. assertEquals(0, counter);
  69. assertTrue(it.next().done);
  70. assertEquals(0, counter);
  71. },
  72. testRun: function() {
  73. var counter = 5;
  74. var resolved = 0;
  75. return promise
  76. .run(
  77. whileLoopIterator(
  78. function() { return counter > 0; },
  79. function() {
  80. --counter;
  81. return Promise.resolve().then(function() { ++resolved; });
  82. }))
  83. .then(function(result) {
  84. assertFalse(goog.isDef(result));
  85. assertEquals(0, counter);
  86. assertEquals(5, resolved);
  87. });
  88. },
  89. testRunWithNonPromise: function() {
  90. var counter = 5;
  91. return promise
  92. .run(
  93. whileLoopIterator(
  94. function() { return counter > 0; }, function() { --counter; }))
  95. .then(function(result) {
  96. assertFalse(goog.isDef(result));
  97. assertEquals(0, counter);
  98. });
  99. },
  100. testRunWithMockClock: function() {
  101. mockClock.install();
  102. var counter = 3;
  103. var innerResolved = 0;
  104. var outerResolved = false;
  105. promise
  106. .run(
  107. whileLoopIterator(
  108. function() { return counter > 0; },
  109. function() {
  110. --counter;
  111. return Timer.promise(10).then(function() {
  112. ++innerResolved;
  113. });
  114. }))
  115. .then(function() { outerResolved = true; });
  116. assertEquals(3, counter);
  117. assertEquals(0, innerResolved);
  118. assertFalse(outerResolved);
  119. mockClock.tick();
  120. assertEquals(2, counter);
  121. assertEquals(0, innerResolved);
  122. assertFalse(outerResolved);
  123. mockClock.tick(10);
  124. assertEquals(1, counter);
  125. assertEquals(1, innerResolved);
  126. assertFalse(outerResolved);
  127. mockClock.tick(10);
  128. assertEquals(0, counter);
  129. assertEquals(2, innerResolved);
  130. assertFalse(outerResolved);
  131. mockClock.tick(10);
  132. assertEquals(0, counter);
  133. assertEquals(3, innerResolved);
  134. assertTrue(outerResolved);
  135. },
  136. testRunWithRejection: function() {
  137. var counter = 5;
  138. return promise
  139. .run(
  140. whileLoopIterator(
  141. function() { return counter > 0; },
  142. function() {
  143. --counter;
  144. if (counter == 2) {
  145. return Promise.reject(sentinel);
  146. }
  147. return Promise.resolve();
  148. }))
  149. .then(shouldNotCall, function(error) {
  150. assertEquals(2, counter);
  151. assertEquals(sentinel, error);
  152. });
  153. },
  154. testRunWithException: function() {
  155. var counter = 5;
  156. return promise
  157. .run(
  158. whileLoopIterator(
  159. function() { return counter > 0; },
  160. function() {
  161. --counter;
  162. if (counter == 2) {
  163. throw sentinel;
  164. }
  165. return Promise.resolve();
  166. }))
  167. .then(shouldNotCall, function(error) {
  168. assertEquals(2, counter);
  169. assertEquals(sentinel, error);
  170. });
  171. },
  172. testRunWithImmediateException: function() {
  173. return promise
  174. .run(whileLoopIterator(function() { throw sentinel; }, function() {}))
  175. .then(
  176. shouldNotCall, function(error) { assertEquals(sentinel, error); });
  177. },
  178. testRunWithImmediateRejection: function() {
  179. return promise
  180. .run(
  181. whileLoopIterator(
  182. function() { return true; },
  183. function() { return Promise.reject(sentinel); }))
  184. .then(
  185. shouldNotCall, function(error) { assertEquals(sentinel, error); });
  186. },
  187. testRunWithoutYield: function() {
  188. return promise
  189. .run(whileLoopIterator(function() { return false; }, goog.nullFunction))
  190. .then(function(result) { assertFalse(goog.isDef(result)); });
  191. },
  192. testRunYieldWithValue: function() {
  193. // ES6 version:
  194. // return promise.run(function*() {
  195. // var x = yield Promise.resolve(1);
  196. // var y = yield Promise.resolve(2);
  197. // return x + y;
  198. // }).then(result => assertEquals(3, result));
  199. return promise
  200. .run(function() {
  201. var step = 0;
  202. var x, y;
  203. return {
  204. next: function(nextArg) {
  205. switch (++step) {
  206. case 1:
  207. return {done: false, value: Promise.resolve(1)};
  208. case 2:
  209. x = nextArg;
  210. return {done: false, value: Promise.resolve(2)};
  211. case 3:
  212. y = nextArg;
  213. return {done: true, value: x + y};
  214. default:
  215. return {done: true};
  216. }
  217. }
  218. };
  219. })
  220. .then(function(result) { assertEquals(3, result); });
  221. },
  222. testRunYieldWithThrow: function() {
  223. // ES6 version:
  224. // return promise.run(function*() {
  225. // var x = 0;
  226. // try {
  227. // x = yield Promise.reject('error');
  228. // catch (e) {
  229. // x = yield Promise.resolve(1);
  230. // }
  231. // var y = yield Promise.resolve(2);
  232. // return x + y;
  233. // }).then(result => assertEquals(3, result));
  234. return promise
  235. .run(function() {
  236. var step = 0;
  237. var x, y;
  238. return {
  239. next: function(nextArg) {
  240. switch (++step) {
  241. case 1:
  242. return {done: false, value: Promise.reject('error')};
  243. case 2:
  244. x = nextArg;
  245. return {done: false, value: Promise.resolve(2)};
  246. case 3:
  247. y = nextArg;
  248. return {done: true, value: x + y};
  249. default:
  250. return {done: true};
  251. }
  252. },
  253. 'throw': function(error) {
  254. return {done: false, value: Promise.resolve(1)};
  255. }
  256. };
  257. })
  258. .then(function(result) { assertEquals(3, result); });
  259. }
  260. });