deferred_test.html 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140
  1. <!DOCTYPE html>
  2. <html>
  3. <!--
  4. Copyright 2009 The Closure Library Authors. All Rights Reserved.
  5. Author: arv@google.com (Erik Arvidsson)
  6. -->
  7. <head>
  8. <title>Closure Unit Tests - goog.async.Deferred</title>
  9. <script src="../../../../../closure/goog/base.js"></script>
  10. <script>
  11. goog.require('goog.Promise');
  12. goog.require('goog.Thenable');
  13. goog.require('goog.array');
  14. goog.require('goog.async.Deferred');
  15. goog.require('goog.string');
  16. goog.require('goog.testing.MockClock');
  17. goog.require('goog.testing.PropertyReplacer');
  18. goog.require('goog.testing.jsunit');
  19. goog.require('goog.testing.recordFunction');
  20. </script>
  21. </head>
  22. <body>
  23. <script>
  24. var Deferred = goog.async.Deferred;
  25. var AlreadyCalledError = Deferred.AlreadyCalledError;
  26. var CanceledError = Deferred.CanceledError;
  27. // Unhandled errors may be sent to the browser on a timeout.
  28. var mockClock = new goog.testing.MockClock();
  29. var stubs = new goog.testing.PropertyReplacer();
  30. function setUp() {
  31. mockClock.install();
  32. }
  33. function tearDown() {
  34. // Advance the mockClock to fire any unhandled exception timeouts.
  35. mockClock.tick();
  36. mockClock.uninstall();
  37. stubs.reset();
  38. }
  39. function assertEqualsCallback(msg, expected) {
  40. return function(res) {
  41. assertEquals(msg, expected, res);
  42. // Since the assertion is an exception that will be caught inside the
  43. // Deferred object, we must advance the clock to see if it has failed.
  44. mockClock.tick();
  45. return res;
  46. };
  47. }
  48. function increment(res) {
  49. return res + 1;
  50. }
  51. function throwStuff(res) {
  52. throw res;
  53. }
  54. function catchStuff(res) {
  55. return res;
  56. }
  57. function returnError(res) {
  58. return Error(res);
  59. }
  60. function neverHappen(res) {
  61. fail('This should not happen');
  62. }
  63. function testNormal() {
  64. var d = new Deferred();
  65. d.addCallback(assertEqualsCallback('pre-deferred callback', 1));
  66. d.callback(1);
  67. d.addCallback(increment);
  68. d.addCallback(assertEqualsCallback('post-deferred callback', 2));
  69. d.addCallback(throwStuff);
  70. d.addCallback(neverHappen);
  71. d.addErrback(catchStuff);
  72. d.addCallback(assertEqualsCallback('throw -> err, catch -> success', 2));
  73. d.addCallback(returnError);
  74. d.addCallback(neverHappen);
  75. d.addErrback(catchStuff);
  76. d.addCallback(assertEqualsCallback('return -> err, catch -> succcess', 2));
  77. }
  78. function testCancel() {
  79. var count = 0;
  80. function canceled(d) {
  81. count++;
  82. }
  83. function canceledError(res) {
  84. assertTrue(res instanceof CanceledError);
  85. }
  86. var d = new Deferred(canceled);
  87. d.addCallback(neverHappen);
  88. d.addErrback(canceledError);
  89. d.cancel();
  90. assertEquals(1, count);
  91. }
  92. function testSucceedFail() {
  93. var count = 0;
  94. var d = Deferred.succeed(1).addCallback(assertEqualsCallback('succeed', 1));
  95. // default error
  96. d = Deferred.fail().addCallback(neverHappen);
  97. d = d.addErrback(function(res) {
  98. count++;
  99. return res;
  100. });
  101. // default wrapped error
  102. d = Deferred.fail('web taco').addCallback(neverHappen).addErrback(catchStuff);
  103. d = d.addCallback(assertEqualsCallback('wrapped fail', 'web taco'));
  104. // default unwrapped error
  105. d = Deferred.fail(Error('ugh')).addCallback(neverHappen).addErrback(
  106. catchStuff);
  107. d = d.addCallback(assertEqualsCallback('unwrapped fail', 'ugh'));
  108. assertEquals(1, count);
  109. }
  110. function testDeferredDependencies() {
  111. function deferredIncrement(res) {
  112. var rval = Deferred.succeed(res);
  113. rval.addCallback(increment);
  114. return rval;
  115. }
  116. var d = Deferred.succeed(1).addCallback(deferredIncrement);
  117. d = d.addCallback(assertEqualsCallback('dependent deferred succeed', 2));
  118. function deferredFailure(res) {
  119. return Deferred.fail(res);
  120. }
  121. d = Deferred.succeed('ugh').addCallback(deferredFailure).addErrback(
  122. catchStuff);
  123. d = d.addCallback(assertEqualsCallback('dependent deferred fail', 'ugh'));
  124. }
  125. // Test double-calling, double-failing, etc.
  126. function testDoubleCalling() {
  127. var ex = assertThrows(function() {
  128. Deferred.succeed(1).callback(2);
  129. neverHappen();
  130. });
  131. assertTrue('double call', ex instanceof AlreadyCalledError);
  132. }
  133. function testDoubleCalling2() {
  134. var ex = assertThrows(function() {
  135. Deferred.fail(1).errback(2);
  136. neverHappen();
  137. });
  138. assertTrue('double-fail', ex instanceof AlreadyCalledError);
  139. }
  140. function testDoubleCalling3() {
  141. var ex = assertThrows(function() {
  142. var d = Deferred.succeed(1);
  143. d.cancel();
  144. d = d.callback(2);
  145. assertTrue('swallowed one callback, no canceler', true);
  146. d.callback(3);
  147. neverHappen();
  148. });
  149. assertTrue('swallow cancel', ex instanceof AlreadyCalledError);
  150. }
  151. function testDoubleCalling4() {
  152. var count = 0;
  153. function canceled(d) {
  154. count++;
  155. }
  156. var ex = assertThrows(function() {
  157. var d = new Deferred(canceled);
  158. d.cancel();
  159. d = d.callback(1);
  160. });
  161. assertTrue('non-swallowed cancel', ex instanceof AlreadyCalledError);
  162. assertEquals(1, count);
  163. }
  164. // Test incorrect Deferred usage
  165. function testIncorrectUsage() {
  166. var d = new Deferred();
  167. var ex = assertThrows(function() {
  168. d.callback(new Deferred());
  169. neverHappen();
  170. });
  171. assertTrue('deferred not allowed for callback', ex instanceof Error);
  172. }
  173. function testIncorrectUsage2() {
  174. var d = new Deferred();
  175. var ex = assertThrows(function() {
  176. d.errback(new Deferred());
  177. neverHappen();
  178. });
  179. assertTrue('deferred not allowed for errback', ex instanceof Error);
  180. }
  181. function testIncorrectUsage3() {
  182. var d = new Deferred();
  183. (new Deferred()).addCallback(function() {return d;}).callback(1);
  184. var ex = assertThrows(function() {
  185. d.addCallback(function() {});
  186. neverHappen();
  187. });
  188. assertTrue('chained deferred not allowed to be re-used', ex instanceof Error);
  189. }
  190. function testCallbackScope1() {
  191. var c1 = {}, c2 = {};
  192. var callbackScope = null;
  193. var errbackScope = null;
  194. var d = new Deferred();
  195. d.addCallback(function() {
  196. callbackScope = this;
  197. throw Error('Foo');
  198. }, c1);
  199. d.addErrback(function() {
  200. errbackScope = this;
  201. }, c2);
  202. d.callback();
  203. assertEquals('Incorrect callback scope', c1, callbackScope);
  204. assertEquals('Incorrect errback scope', c2, errbackScope);
  205. }
  206. function testCallbackScope2() {
  207. var callbackScope = null;
  208. var errbackScope = null;
  209. var d = new Deferred();
  210. d.addCallback(function() {
  211. callbackScope = this;
  212. throw Error('Foo');
  213. });
  214. d.addErrback(function() {
  215. errbackScope = this;
  216. });
  217. d.callback();
  218. assertEquals('Incorrect callback scope', window, callbackScope);
  219. assertEquals('Incorrect errback scope', window, errbackScope);
  220. }
  221. function testCallbackScope3() {
  222. var c = {};
  223. var callbackScope = null;
  224. var errbackScope = null;
  225. var d = new Deferred(null, c);
  226. d.addCallback(function() {
  227. callbackScope = this;
  228. throw Error('Foo');
  229. });
  230. d.addErrback(function() {
  231. errbackScope = this;
  232. });
  233. d.callback();
  234. assertEquals('Incorrect callback scope', c, callbackScope);
  235. assertEquals('Incorrect errback scope', c, errbackScope);
  236. }
  237. function testChainedDeferred1() {
  238. var calls = [];
  239. var d2 = new Deferred();
  240. d2.addCallback(function() {calls.push('B1');});
  241. d2.addCallback(function() {calls.push('B2');});
  242. var d1 = new Deferred();
  243. d1.addCallback(function() {calls.push('A1');});
  244. d1.addCallback(function() {calls.push('A2');});
  245. d1.chainDeferred(d2);
  246. d1.addCallback(function() {calls.push('A3');});
  247. d1.callback();
  248. assertEquals('A1,A2,B1,B2,A3', calls.join(','));
  249. }
  250. function testChainedDeferred2() {
  251. var calls = [];
  252. var d2 = new Deferred();
  253. d2.addCallback(function() {calls.push('B1');});
  254. d2.addErrback(function(err) {calls.push('B2'); throw Error('x');});
  255. var d1 = new Deferred();
  256. d1.addCallback(function(err) {throw Error('foo');});
  257. d1.chainDeferred(d2);
  258. d1.addCallback(function() {calls.push('A1');});
  259. d1.addErrback(function() {calls.push('A2');});
  260. d1.callback();
  261. assertEquals('B2,A2', calls.join(','));
  262. var ex = assertThrows(function() {
  263. mockClock.tick();
  264. neverHappen();
  265. });
  266. assertTrue('Should catch unhandled throw from d2.', ex.message == 'x');
  267. }
  268. function testUndefinedResultAndCallbackSequence() {
  269. var results = [];
  270. var d = new Deferred();
  271. d.addCallback(function(res) {return 'foo';});
  272. d.addCallback(function(res) {results.push(res); return 'bar';});
  273. d.addCallback(function(res) {results.push(res);});
  274. d.addCallback(function(res) {results.push(res);});
  275. d.callback();
  276. assertEquals('foo,bar,bar', results.join(','));
  277. }
  278. function testUndefinedResultAndErrbackSequence() {
  279. var results = [];
  280. var d = new Deferred();
  281. d.addCallback(function(res) {throw Error('uh oh');});
  282. d.addErrback(function(res) {results.push('A');});
  283. d.addCallback(function(res) {results.push('B');});
  284. d.addErrback(function(res) {results.push('C');});
  285. d.callback();
  286. assertEquals('A,C', results.join(','));
  287. }
  288. function testHasFired() {
  289. var d1 = new Deferred();
  290. var d2 = new Deferred();
  291. assertFalse(d1.hasFired());
  292. assertFalse(d2.hasFired());
  293. d1.callback();
  294. d2.errback();
  295. assertTrue(d1.hasFired());
  296. assertTrue(d2.hasFired());
  297. }
  298. function testUnhandledErrors() {
  299. var d = new Deferred();
  300. d.addCallback(throwStuff);
  301. var ex = assertThrows(function() {
  302. d.callback(123);
  303. mockClock.tick();
  304. neverHappen();
  305. });
  306. assertEquals('Unhandled throws should hit the browser.', 123, ex);
  307. assertNotThrows(
  308. 'Errbacks added after a failure should resume.',
  309. function() {
  310. d.addErrback(catchStuff);
  311. mockClock.tick();
  312. });
  313. d.addCallback(assertEqualsCallback('Should recover after throw.', 1));
  314. mockClock.tick();
  315. }
  316. function testStrictUnhandledErrors() {
  317. stubs.replace(Deferred, 'STRICT_ERRORS', true);
  318. var err = Error('never handled');
  319. // The registered errback exists, but doesn't modify the error value.
  320. var d = Deferred.succeed();
  321. d.addCallback(function(res) { throw err; });
  322. d.addErrback(function(unhandledErr) {});
  323. var caught = assertThrows(
  324. 'The error should be rethrown at the next clock tick.',
  325. function() { mockClock.tick(); });
  326. assertEquals(err, caught);
  327. }
  328. function testStrictHandledErrors() {
  329. stubs.replace(Deferred, 'STRICT_ERRORS', true);
  330. // The registered errback returns a non-error value.
  331. var d = Deferred.succeed();
  332. d.addCallback(function(res) { throw Error('eventually handled'); });
  333. d.addErrback(function(unhandledErr) { return true; });
  334. assertNotThrows(
  335. 'The error was handled and should not be rethrown',
  336. function() { mockClock.tick(); });
  337. d.addCallback(function(res) { assertTrue(res); });
  338. }
  339. function testStrictBlockedErrors() {
  340. stubs.replace(Deferred, 'STRICT_ERRORS', true);
  341. var d1 = Deferred.fail(Error('blocked failure'));
  342. var d2 = new Deferred();
  343. d1.addBoth(function() { return d2; });
  344. assertNotThrows(
  345. 'd1 should be blocked until d2 fires.',
  346. function() { mockClock.tick(); });
  347. d2.callback('unblocked');
  348. d1.addCallback(assertEqualsCallback(
  349. 'd1 should receive the fired result from d2.', 'unblocked'));
  350. }
  351. function testStrictCanceledErrors() {
  352. stubs.replace(Deferred, 'STRICT_ERRORS', true);
  353. var d = Deferred.canceled();
  354. assertNotThrows(
  355. 'CanceledErrors should not be rethrown to the global scope.',
  356. function() { mockClock.tick(); });
  357. }
  358. function testSynchronousErrorCanceling() {
  359. var d = new Deferred();
  360. d.addCallback(throwStuff);
  361. assertNotThrows(
  362. 'Adding an errback to the end of a failing Deferred should cancel the ' +
  363. 'unhandled error timeout.',
  364. function() {
  365. d.callback(1);
  366. d.addErrback(catchStuff);
  367. mockClock.tick();
  368. });
  369. d.addCallback(assertEqualsCallback('Callback should fire', 1));
  370. }
  371. function testThrowNonError() {
  372. var results = [];
  373. var d = new Deferred();
  374. d.addCallback(function(res) {
  375. throw res;
  376. });
  377. d.addErrback(function(res) {
  378. results.push(res);
  379. return 6;
  380. });
  381. d.addCallback(function(res) {
  382. results.push(res);
  383. });
  384. d.callback(7);
  385. assertArrayEquals(
  386. 'Errback should have been called with 7, followed by callback with 6.',
  387. [7, 6], results);
  388. }
  389. function testThrownErrorWithNoErrbacks() {
  390. var d = new Deferred();
  391. d.addCallback(function() {
  392. throw Error('foo');
  393. });
  394. d.addCallback(goog.nullFunction);
  395. function assertCallback() {
  396. d.callback(1);
  397. mockClock.tick(); // Should cause error because throwing is delayed.
  398. }
  399. assertThrows('A thrown error should be rethrown if there is no ' +
  400. 'errback to catch it.', assertCallback);
  401. }
  402. function testThrownErrorCallbacksDoNotCancel() {
  403. var d = new Deferred();
  404. d.addCallback(function() {
  405. throw Error('foo');
  406. });
  407. function assertCallback() {
  408. d.callback(1);
  409. // Add another callback after the fact. Note this is not an errback!
  410. d.addCallback(neverHappen);
  411. mockClock.tick(); // Should cause error because throwing is delayed.
  412. }
  413. assertThrows('A thrown error should be rethrown if there is no ' +
  414. 'errback to catch it.', assertCallback);
  415. }
  416. function testAwaitDeferred() {
  417. var results = [];
  418. function fn(x) {
  419. return function() {
  420. results.push(x);
  421. };
  422. }
  423. var d2 = new Deferred();
  424. d2.addCallback(fn('b'));
  425. // d1 -> a -> (wait for d2) -> c
  426. var d1 = new Deferred();
  427. d1.addCallback(fn('a'));
  428. d1.awaitDeferred(d2);
  429. d1.addCallback(fn('c'));
  430. // calls 'a' then yields for d2.
  431. d1.callback(null);
  432. // will get called after d2.
  433. d1.addCallback(fn('d'));
  434. assertEquals('a', results.join(''));
  435. // d3 -> w -> (wait for d2) -> x
  436. var d3 = new Deferred();
  437. d3.addCallback(fn('w'));
  438. d3.awaitDeferred(d2);
  439. d3.addCallback(fn('x'));
  440. // calls 'w', then yields for d2.
  441. d3.callback();
  442. // will get called after d2.
  443. d3.addCallback(fn('y'));
  444. assertEquals('aw', results.join(''));
  445. // d1 calls 'd', d3 calls 'y'
  446. d2.callback(null);
  447. assertEquals('awbcdxy', results.join(''));
  448. // d3 and d2 already called, so 'z' called immediately.
  449. d3.addCallback(fn('z'));
  450. assertEquals('awbcdxyz', results.join(''));
  451. }
  452. function testAwaitDeferred_withPromise() {
  453. var results = [];
  454. function fn(x) {
  455. return function() {
  456. results.push(x);
  457. };
  458. }
  459. var resolver = new goog.Promise.withResolver();
  460. resolver.promise.then(fn('b'));
  461. // d1 -> a -> (wait for promise) -> c
  462. var d1 = new Deferred();
  463. d1.addCallback(fn('a'));
  464. d1.awaitDeferred(resolver.promise);
  465. d1.addCallback(fn('c'));
  466. // calls 'a' then yields for promise.
  467. d1.callback(1);
  468. // will get called after promise.
  469. d1.addCallback(fn('d'));
  470. assertEquals('a', results.join(''));
  471. // d3 -> w -> (wait for promise) -> x
  472. var d3 = new Deferred();
  473. d3.addCallback(fn('w'));
  474. d3.awaitDeferred(resolver.promise);
  475. d3.addCallback(fn('x'));
  476. // calls 'w', then yields for promise.
  477. d3.callback(2);
  478. // will get called after promise.
  479. d3.addCallback(fn('y'));
  480. assertEquals('aw', results.join(''));
  481. // d1 calls 'd', d3 calls 'y'
  482. resolver.resolve();
  483. mockClock.tick();
  484. assertEquals('awbcdxy', results.join(''));
  485. // d3 and promise already called, so 'z' called immediately.
  486. d3.addCallback(fn('z'));
  487. assertEquals('awbcdxyz', results.join(''));
  488. }
  489. function testAwaitDeferredWithErrors() {
  490. var results = [];
  491. function fn(x) {
  492. return function(e) {
  493. results.push(x);
  494. };
  495. }
  496. var d2 = new Deferred();
  497. d2.addErrback(fn('a'));
  498. var d1 = new Deferred();
  499. d1.awaitDeferred(d2);
  500. d1.addCallback(fn('x'));
  501. d1.addErrback(fn('b'));
  502. d1.callback(null);
  503. assertEquals('', results.join(''));
  504. d2.addCallback(fn('z'));
  505. d2.addErrback(fn('c'));
  506. d2.errback(null);
  507. // First errback added to d2 prints 'a'.
  508. // Next 'd' was chained, so execute its err backs, printing 'b'.
  509. // Finally 'c' was added last by d2's errback.
  510. assertEquals('abc', results.join(''));
  511. }
  512. function testNonErrorErrback() {
  513. var results = [];
  514. function fn(x) {
  515. return function(e) {
  516. results.push(x);
  517. };
  518. }
  519. var d = new Deferred();
  520. d.addCallback(fn('a'));
  521. d.addErrback(fn('b'));
  522. d.addCallback(fn('c'));
  523. d.addErrback(fn('d'));
  524. d.errback('foo');
  525. assertEquals('bd', results.join(''));
  526. }
  527. function testUnequalReturnValueForErrback() {
  528. var results = [];
  529. function fn(x) {
  530. return function(e) {
  531. results.push(x);
  532. };
  533. }
  534. var d = new Deferred();
  535. d.addCallback(fn('a'));
  536. d.addErrback(function() {
  537. results.push('b');
  538. return 'bar';
  539. });
  540. d.addCallback(fn('c'));
  541. d.addErrback(fn('d'));
  542. d.errback('foo');
  543. assertEquals('bc', results.join(''));
  544. }
  545. function testBranch() {
  546. function fn(x) {
  547. return function(arr) {
  548. return arr.concat(x);
  549. };
  550. }
  551. var d = new Deferred();
  552. d.addCallback(fn(1));
  553. d.addCallback(fn(2));
  554. var d2 = d.branch();
  555. d.addCallback(fn(3));
  556. d2.addCallback(fn(4));
  557. d.callback([]);
  558. assertTrue('both deferreds should have fired', d.hasFired());
  559. assertTrue('both deferreds should have fired', d2.hasFired());
  560. d.addCallback(function(arr) { assertArrayEquals([1, 2, 3], arr); });
  561. d2.addCallback(function(arr) { assertArrayEquals([1, 2, 4], arr); });
  562. }
  563. function testDiamondBranch() {
  564. function fn(x) {
  565. return function(arr) {
  566. return arr.concat(x);
  567. };
  568. }
  569. var d = new Deferred();
  570. d.addCallback(fn(1));
  571. var d2 = d.branch();
  572. d2.addCallback(fn(2));
  573. // Chain the branch back to the original. There is no good reason to do this
  574. // cever.
  575. d.addCallback(function(ret) {return d2;});
  576. d.callback([]);
  577. // But no reason it shouldn't work!
  578. d.addCallback(function(arr) { assertArrayEquals([1, 2], arr); });
  579. }
  580. function testRepeatedBranch() {
  581. var d = new Deferred().addCallback(increment);
  582. d.branch().
  583. addCallback(assertEqualsCallback('branch should be after increment', 2)).
  584. addCallback(function(res) {return d.branch();}).
  585. addCallback(assertEqualsCallback('second branch should be the same', 2));
  586. d.callback(1);
  587. }
  588. function testCancelThroughBranch() {
  589. var wasCanceled = false;
  590. var d = new Deferred(function() { wasCanceled = true; });
  591. var branch1 = d.branch(true);
  592. var branch2 = d.branch(true);
  593. branch1.cancel();
  594. assertFalse(wasCanceled);
  595. branch2.cancel();
  596. assertTrue(wasCanceled);
  597. }
  598. function testCancelThroughSeveralBranches() {
  599. var wasCanceled = false;
  600. var d = new Deferred(function() { wasCanceled = true; });
  601. var branch = d.branch(true).branch(true).branch(true);
  602. branch.cancel();
  603. assertTrue(wasCanceled);
  604. }
  605. function testBranchCancelThenCallback() {
  606. var wasCanceled = false;
  607. var d = new Deferred(function() { wasCanceled = true; });
  608. var wasCalled = false;
  609. d.addCallback(function() { wasCalled = true; });
  610. var branch1 = d.branch();
  611. var branch2 = d.branch();
  612. var branch1WasCalled = false;
  613. var branch2WasCalled = false;
  614. branch1.addCallback(function() { branch1WasCalled = true; });
  615. branch2.addCallback(function() { branch2WasCalled = true; });
  616. var branch1HadErrback = false;
  617. var branch2HadErrback = false;
  618. branch1.addErrback(function() { branch1HadErrback = true; });
  619. branch2.addErrback(function() { branch2HadErrback = true; });
  620. branch1.cancel();
  621. assertFalse(wasCanceled);
  622. assertTrue(branch1HadErrback);
  623. assertFalse(branch2HadErrback);
  624. d.callback();
  625. assertTrue(wasCalled);
  626. assertFalse(branch1WasCalled);
  627. assertTrue(branch2WasCalled);
  628. }
  629. function testDeepCancelOnBranch() {
  630. var wasCanceled = false;
  631. var d = new Deferred(function() { wasCanceled = true; });
  632. var branch1 = d.branch(true);
  633. var branch2 = d.branch(true).branch(true).branch(true);
  634. var branch1HadErrback = false;
  635. var branch2HadErrback = false;
  636. branch1.addErrback(function() { branch1HadErrback = true; });
  637. branch2.addErrback(function() { branch2HadErrback = true; });
  638. branch2.cancel(true /* opt_deepCancel */);
  639. assertTrue(wasCanceled);
  640. assertTrue(branch1HadErrback);
  641. assertTrue(branch2HadErrback);
  642. }
  643. function testCancelOnRoot() {
  644. var wasCanceled = false;
  645. var d = new Deferred(function() { wasCanceled = true; });
  646. var branch = d.branch(true).branch(true).branch(true);
  647. d.cancel();
  648. assertTrue(wasCanceled);
  649. }
  650. function testCancelOnLeafBranch() {
  651. var wasCanceled = false;
  652. var branchWasCanceled = false;
  653. var d = new Deferred(function() { wasCanceled = true; });
  654. var branch = d.branch(true).branch(true).branch(true);
  655. branch.addErrback(function() { branchWasCanceled = true; });
  656. branch.cancel();
  657. assertTrue(wasCanceled);
  658. assertTrue(branchWasCanceled);
  659. }
  660. function testCancelOnIntermediateBranch() {
  661. var rootWasCanceled = false;
  662. var d = new Deferred(function() { rootWasCanceled = true; });
  663. var branch = d.branch(true).branch(true).branch(true);
  664. var deepBranch1 = branch.branch(true);
  665. var deepBranch2 = branch.branch(true);
  666. branch.cancel();
  667. assertTrue(rootWasCanceled);
  668. assertTrue(deepBranch1.hasFired());
  669. assertTrue(deepBranch2.hasFired());
  670. }
  671. function testCancelWithSomeCompletedBranches() {
  672. var d = new Deferred();
  673. var branch1 = d.branch(true);
  674. var branch1HadCallback = false;
  675. var branch1HadErrback = false;
  676. branch1.
  677. addCallback(function() { branch1HadCallback = true; }).
  678. addErrback(function() { branch1HadErrback = true; });
  679. d.callback(true);
  680. assertTrue(branch1HadCallback);
  681. assertFalse(branch1HadErrback);
  682. var rootHadCallback = false;
  683. var rootHadErrback = false;
  684. // Block the root on a new Deferred indefinitely.
  685. d.
  686. addCallback(function() { rootHadCallback = true; }).
  687. addCallback(function() { return new Deferred(); }).
  688. addErrback(function() { rootHadErrback = true; });
  689. var branch2 = d.branch(true);
  690. assertTrue(rootHadCallback);
  691. assertFalse(rootHadErrback);
  692. branch2.cancel();
  693. assertFalse(branch1HadErrback);
  694. assertTrue('Canceling the last active branch should cancel the parent.',
  695. rootHadErrback);
  696. }
  697. function testStaticCanceled() {
  698. var callbackCalled = false;
  699. var errbackResult = null;
  700. var d = goog.async.Deferred.canceled();
  701. d.addCallback(function() { callbackCalled = true;} );
  702. d.addErrback(function(err) { errbackResult = err;} );
  703. assertTrue('Errback should have been called with a canceled error',
  704. errbackResult instanceof goog.async.Deferred.CanceledError);
  705. assertFalse('Callback should not have been called', callbackCalled);
  706. }
  707. function testWhenWithValues() {
  708. var called = false;
  709. Deferred.when(4, function(obj) {
  710. called = true;
  711. assertEquals(4, obj);
  712. });
  713. assertTrue('Fn should have been called', called);
  714. }
  715. function testWhenWithDeferred() {
  716. var called = false;
  717. var d = new Deferred();
  718. Deferred.when(d, function(obj) {
  719. called = true;
  720. assertEquals(6, obj);
  721. });
  722. assertFalse('Fn should not have been called yet', called);
  723. d.callback(6);
  724. assertTrue('Fn should have been called', called);
  725. }
  726. function testWhenDoesntAlterOriginalChain() {
  727. var calls = 0;
  728. var d1 = new Deferred();
  729. var d2 = Deferred.when(d1, function(obj) {
  730. calls++;
  731. return obj * 2;
  732. });
  733. d1.addCallback(function(obj) {
  734. assertEquals('Original chain should get original value', 5, obj);
  735. calls++;
  736. });
  737. d2.addCallback(function(obj) {
  738. assertEquals('Branched chain should get modified value', 10, obj);
  739. calls++;
  740. });
  741. d1.callback(5);
  742. assertEquals('There should have been 3 callbacks', 3, calls);
  743. }
  744. function testAssertNoErrors() {
  745. var d = new Deferred();
  746. d.addCallback(function() {
  747. throw new Error('Foo');
  748. });
  749. d.callback(1);
  750. var ex = assertThrows(function() {
  751. Deferred.assertNoErrors();
  752. neverHappen();
  753. });
  754. assertEquals('Expected to get thrown error', 'Foo', ex.message);
  755. assertNotThrows(
  756. 'Calling Deferred.assertNoErrors() a second time with only one ' +
  757. 'scheduled error should pass.',
  758. function() {
  759. Deferred.assertNoErrors();
  760. });
  761. }
  762. function testThen() {
  763. var result;
  764. var result2;
  765. var d = new Deferred();
  766. assertEquals(d.then, d['then']);
  767. d.then(function(r) {
  768. return result = r;
  769. }).then(function (r2) {
  770. result2 = r2;
  771. });
  772. d.callback('done');
  773. assertUndefined(result);
  774. mockClock.tick();
  775. assertEquals('done', result);
  776. assertEquals('done', result2);
  777. }
  778. function testThen_reject() {
  779. var result, error, error2;
  780. var d = new Deferred();
  781. assertEquals(d.then, d['then']);
  782. d.then(function(r) {
  783. result = r;
  784. }, function(e) {
  785. error = e;
  786. });
  787. d.errback(new Error('boom'));
  788. assertUndefined(result);
  789. mockClock.tick();
  790. assertUndefined(result);
  791. assertEquals('boom', error.message);
  792. }
  793. function testPromiseAll() {
  794. var d = new Deferred();
  795. var p = new goog.Promise(function(resolve) {
  796. resolve('promise');
  797. });
  798. goog.Promise.all([d, p]).then(function(values) {
  799. assertEquals(2, values.length);
  800. assertEquals('deferred', values[0]);
  801. assertEquals('promise', values[1]);
  802. });
  803. d.callback('deferred');
  804. mockClock.tick();
  805. }
  806. function testGoogPromiseBlocksDeferred() {
  807. var result;
  808. var d = new Deferred();
  809. var p = new goog.Promise(function(resolve) {
  810. resolve('promise');
  811. });
  812. d.callback();
  813. d.addCallback(function() {
  814. return p;
  815. });
  816. d.addCallback(function(r) {
  817. result = r;
  818. });
  819. assertUndefined(result);
  820. mockClock.tick();
  821. assertEquals('promise', result);
  822. }
  823. function testNativePromiseBlocksDeferred() {
  824. // Early-out for browsers that don't support native Promises.
  825. if (typeof Promise !== 'function') {
  826. return;
  827. }
  828. // Disable mock clock for this test. Native promises don't abide by it, so
  829. // it just complicates things in this case.
  830. mockClock.uninstall();
  831. var blockedOnPromise = true;
  832. var resolver;
  833. var d = Deferred.succeed();
  834. d.addCallback(function() {
  835. return new Promise(function(resolve) {
  836. resolver = resolve;
  837. });
  838. });
  839. d.addCallback(function(r) {
  840. blockedOnPromise = false;
  841. assertEquals('Native promise value', 'result', r);
  842. });
  843. // Verify that the callback chain executes up to, but not beyond, the callback
  844. // that returns a Promise.
  845. assertTrue(!!resolver);
  846. assertTrue('Deferred chain not blocked on Promise resolution',
  847. blockedOnPromise);
  848. // Resolve the promise, which should unblock the rest of the callback chain.
  849. resolver('result');
  850. return d;
  851. }
  852. function testFromPromise() {
  853. var result;
  854. var p = new goog.Promise(function(resolve) {
  855. resolve('promise');
  856. });
  857. var d = Deferred.fromPromise(p);
  858. d.addCallback(function(value) {
  859. result = value;
  860. });
  861. assertUndefined(result);
  862. mockClock.tick();
  863. assertEquals('promise', result);
  864. }
  865. function testPromiseBlocksDeferredAndRejects() {
  866. var result;
  867. var d = new Deferred();
  868. var p = new goog.Promise(function(resolve, reject) {
  869. reject(new Error('error'));
  870. });
  871. d.callback();
  872. d.addCallback(function(r) {
  873. return p;
  874. });
  875. d.addErrback(function(r) {
  876. result = r;
  877. });
  878. assertUndefined(result);
  879. mockClock.tick();
  880. assertEquals('error', result.message);
  881. }
  882. function testPromiseFromCanceledDeferred() {
  883. var result;
  884. var d = new Deferred();
  885. d.cancel();
  886. var p = d.then(neverHappen, function(reason) {
  887. result = reason;
  888. });
  889. mockClock.tick();
  890. assertTrue(result instanceof goog.Promise.CancellationError);
  891. }
  892. function testThenableInterface() {
  893. var d = new Deferred();
  894. assertTrue(goog.Thenable.isImplementedBy(d));
  895. }
  896. function testAddBothPropagatesToErrback() {
  897. var log = [];
  898. var deferred = new goog.async.Deferred();
  899. deferred.addBoth(goog.nullFunction);
  900. deferred.addErrback(function () {
  901. log.push('errback');
  902. });
  903. deferred.errback(new Error('my error'));
  904. mockClock.tick(1);
  905. assertArrayEquals(['errback'], log);
  906. }
  907. function testAddBothDoesNotPropagateUncaughtExceptions() {
  908. var deferred = new goog.async.Deferred();
  909. deferred.addBoth(goog.nullFunction);
  910. deferred.errback(new Error('my error'));
  911. mockClock.tick(1);
  912. }
  913. function testAddFinally() {
  914. var deferred = new goog.async.Deferred();
  915. var callback = goog.testing.recordFunction();
  916. var thisArg = {};
  917. deferred.addFinally(callback, thisArg);
  918. deferred.errback(new Error('my error'));
  919. try {
  920. mockClock.tick(1);
  921. } catch (e) {
  922. assertEquals('my error', e.message);
  923. }
  924. assertEquals(thisArg, callback.getCalls()[0].getThis());
  925. }
  926. </script>
  927. </body>
  928. </html>