promise_flow_test.js 68 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288
  1. // Licensed to the Software Freedom Conservancy (SFC) under one
  2. // or more contributor license agreements. See the NOTICE file
  3. // distributed with this work for additional information
  4. // regarding copyright ownership. The SFC licenses this file
  5. // to you under the Apache License, Version 2.0 (the
  6. // "License"); you may not use this file except in compliance
  7. // with the License. You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing,
  12. // software distributed under the License is distributed on an
  13. // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  14. // KIND, either express or implied. See the License for the
  15. // specific language governing permissions and limitations
  16. // under the License.
  17. 'use strict';
  18. const assert = require('assert');
  19. const fail = assert.fail;
  20. const sinon = require('sinon');
  21. const testutil = require('./testutil');
  22. const {TimeoutError} = require('../../lib/error');
  23. const promise = require('../../lib/promise');
  24. const {enablePromiseManager} = require('../../lib/test/promise');
  25. const NativePromise = Promise;
  26. // Aliases for readability.
  27. const StubError = testutil.StubError;
  28. const assertIsStubError = testutil.assertIsStubError;
  29. const callbackPair = testutil.callbackPair;
  30. const throwStubError = testutil.throwStubError;
  31. describe('promise control flow', function() {
  32. enablePromiseManager(() => {
  33. let flow, flowHistory, messages, uncaughtExceptions;
  34. beforeEach(function setUp() {
  35. promise.LONG_STACK_TRACES = false;
  36. flow = new promise.ControlFlow();
  37. promise.setDefaultFlow(flow);
  38. messages = [];
  39. flowHistory = [];
  40. uncaughtExceptions = [];
  41. flow.on(promise.ControlFlow.EventType.UNCAUGHT_EXCEPTION,
  42. onUncaughtException);
  43. });
  44. afterEach(function tearDown() {
  45. flow.removeAllListeners(
  46. promise.ControlFlow.EventType.UNCAUGHT_EXCEPTION);
  47. assert.deepEqual([], uncaughtExceptions,
  48. 'There were uncaught exceptions');
  49. flow.reset();
  50. promise.LONG_STACK_TRACES = false;
  51. });
  52. function onUncaughtException(e) {
  53. uncaughtExceptions.push(e);
  54. }
  55. function defer() {
  56. let d = {};
  57. let promise = new Promise((resolve, reject) => {
  58. Object.assign(d, {resolve, reject});
  59. });
  60. d.promise = promise;
  61. return d;
  62. }
  63. function waitForAbort(opt_flow) {
  64. var theFlow = opt_flow || flow;
  65. theFlow.removeAllListeners(
  66. promise.ControlFlow.EventType.UNCAUGHT_EXCEPTION);
  67. return new NativePromise(function(fulfill, reject) {
  68. theFlow.once(promise.ControlFlow.EventType.IDLE, function() {
  69. reject(Error('expected flow to report an unhandled error'));
  70. });
  71. theFlow.once(
  72. promise.ControlFlow.EventType.UNCAUGHT_EXCEPTION,
  73. fulfill);
  74. });
  75. }
  76. function waitForIdle(opt_flow) {
  77. var theFlow = opt_flow || flow;
  78. return new NativePromise(function(fulfill, reject) {
  79. theFlow.once(promise.ControlFlow.EventType.IDLE, fulfill);
  80. theFlow.once(
  81. promise.ControlFlow.EventType.UNCAUGHT_EXCEPTION, reject);
  82. });
  83. }
  84. function timeout(ms) {
  85. return new NativePromise(function(fulfill) {
  86. setTimeout(fulfill, ms);
  87. });
  88. }
  89. function schedule(msg, opt_return) {
  90. return scheduleAction(msg, function() {
  91. return opt_return;
  92. });
  93. }
  94. /**
  95. * @param {string} value The value to push.
  96. * @param {promise.Promise=} opt_taskPromise Promise to return from
  97. * the task.
  98. * @return {!promise.Promise} The result.
  99. */
  100. function schedulePush(value, opt_taskPromise) {
  101. return scheduleAction(value, function() {
  102. messages.push(value);
  103. return opt_taskPromise;
  104. });
  105. }
  106. /**
  107. * @param {string} msg Debug message.
  108. * @param {!Function} actionFn The function.
  109. * @return {!promise.Promise} The function result.
  110. */
  111. function scheduleAction(msg, actionFn) {
  112. return promise.controlFlow().execute(function() {
  113. flowHistory.push(msg);
  114. return actionFn();
  115. }, msg);
  116. }
  117. /**
  118. * @param {!Function} condition The condition function.
  119. * @param {number=} opt_timeout The timeout.
  120. * @param {string=} opt_message Optional message.
  121. * @return {!promise.Promise} The wait result.
  122. */
  123. function scheduleWait(condition, opt_timeout, opt_message) {
  124. var msg = opt_message || '';
  125. // It's not possible to hook into when the wait itself is scheduled, so
  126. // we record each iteration of the wait loop.
  127. var count = 0;
  128. return promise.controlFlow().wait(function() {
  129. flowHistory.push((count++) + ': ' + msg);
  130. return condition();
  131. }, opt_timeout, msg);
  132. }
  133. function asyncRun(fn, opt_self) {
  134. NativePromise.resolve().then(() => fn.call(opt_self));
  135. }
  136. function assertFlowHistory(var_args) {
  137. var expected = Array.prototype.slice.call(arguments, 0);
  138. assert.deepEqual(expected, flowHistory);
  139. }
  140. function assertMessages(var_args) {
  141. var expected = Array.prototype.slice.call(arguments, 0);
  142. assert.deepEqual(expected, messages);
  143. }
  144. function assertingMessages(var_args) {
  145. var args = Array.prototype.slice.call(arguments, 0);
  146. return () => assertMessages.apply(null, args);
  147. }
  148. function assertFlowIs(flow) {
  149. assert.equal(flow, promise.controlFlow());
  150. }
  151. describe('testScheduling', function() {
  152. it('aSimpleFunction', function() {
  153. schedule('go');
  154. return waitForIdle().then(function() {
  155. assertFlowHistory('go');
  156. });
  157. });
  158. it('aSimpleFunctionWithANonPromiseReturnValue', function() {
  159. schedule('go', 123).then(function(value) {
  160. assert.equal(123, value);
  161. });
  162. return waitForIdle().then(function() {
  163. assertFlowHistory('go');
  164. });
  165. });
  166. it('aSimpleSequence', function() {
  167. schedule('a');
  168. schedule('b');
  169. schedule('c');
  170. return waitForIdle().then(function() {
  171. assertFlowHistory('a', 'b', 'c');
  172. });
  173. });
  174. it('invokesCallbacksWhenTaskIsDone', function() {
  175. var d = new promise.Deferred();
  176. var called = false;
  177. var done = schedule('a', d.promise).then(function(value) {
  178. called = true;
  179. assert.equal(123, value);
  180. });
  181. return timeout(5).then(function() {
  182. assert.ok(!called);
  183. d.fulfill(123);
  184. return done;
  185. }).
  186. then(function() {
  187. assertFlowHistory('a');
  188. });
  189. });
  190. it('blocksUntilPromiseReturnedByTaskIsResolved', function() {
  191. var done = promise.defer();
  192. schedulePush('a', done.promise);
  193. schedulePush('b');
  194. setTimeout(function() {
  195. done.fulfill();
  196. messages.push('c');
  197. }, 25);
  198. return waitForIdle().then(assertingMessages('a', 'c', 'b'));
  199. });
  200. it('waitsForReturnedPromisesToResolve', function() {
  201. var d1 = new promise.Deferred();
  202. var d2 = new promise.Deferred();
  203. var callback = sinon.spy();
  204. schedule('a', d1.promise).then(callback);
  205. return timeout(5).then(function() {
  206. assert(!callback.called);
  207. d1.fulfill(d2.promise);
  208. return timeout(5);
  209. }).then(function() {
  210. assert(!callback.called);
  211. d2.fulfill('fluffy bunny');
  212. return waitForIdle();
  213. }).then(function() {
  214. assert(callback.called);
  215. assert.equal('fluffy bunny', callback.getCall(0).args[0]);
  216. assertFlowHistory('a');
  217. });
  218. });
  219. it('executesTasksInAFutureTurnAfterTheyAreScheduled', function() {
  220. var count = 0;
  221. function incr() { count++; }
  222. scheduleAction('', incr);
  223. assert.equal(0, count);
  224. return waitForIdle().then(function() {
  225. assert.equal(1, count);
  226. });
  227. });
  228. it('executesOneTaskPerTurnOfTheEventLoop', function() {
  229. var order = [];
  230. function go() {
  231. order.push(order.length / 2);
  232. asyncRun(function() {
  233. order.push('-');
  234. });
  235. }
  236. scheduleAction('', go);
  237. scheduleAction('', go);
  238. return waitForIdle().then(function() {
  239. assert.deepEqual([0, '-', 1, '-'], order);
  240. })
  241. });
  242. it('firstScheduledTaskIsWithinACallback', function() {
  243. promise.fulfilled().then(function() {
  244. schedule('a');
  245. schedule('b');
  246. schedule('c');
  247. }).then(function() {
  248. assertFlowHistory('a', 'b', 'c');
  249. });
  250. return waitForIdle();
  251. });
  252. it('newTasksAddedWhileWaitingOnTaskReturnedPromise1', function() {
  253. scheduleAction('a', function() {
  254. var d = promise.defer();
  255. setTimeout(function() {
  256. schedule('c');
  257. d.fulfill();
  258. }, 10);
  259. return d.promise;
  260. });
  261. schedule('b');
  262. return waitForIdle().then(function() {
  263. assertFlowHistory('a', 'b', 'c');
  264. });
  265. });
  266. it('newTasksAddedWhileWaitingOnTaskReturnedPromise2', function() {
  267. scheduleAction('a', function() {
  268. var d = promise.defer();
  269. setTimeout(function() {
  270. schedule('c');
  271. asyncRun(d.fulfill);
  272. }, 10);
  273. return d.promise;
  274. });
  275. schedule('b');
  276. return waitForIdle().then(function() {
  277. assertFlowHistory('a', 'c', 'b');
  278. });
  279. });
  280. });
  281. describe('testFraming', function() {
  282. it('callbacksRunInANewFrame', function() {
  283. schedule('a').then(function() {
  284. schedule('c');
  285. });
  286. schedule('b');
  287. return waitForIdle().then(function() {
  288. assertFlowHistory('a', 'c', 'b');
  289. });
  290. });
  291. it('lotsOfNesting', function() {
  292. schedule('a').then(function() {
  293. schedule('c').then(function() {
  294. schedule('e').then(function() {
  295. schedule('g');
  296. });
  297. schedule('f');
  298. });
  299. schedule('d');
  300. });
  301. schedule('b');
  302. return waitForIdle().then(function() {
  303. assertFlowHistory('a', 'c', 'e', 'g', 'f', 'd', 'b');
  304. });
  305. });
  306. it('callbackReturnsPromiseThatDependsOnATask_1', function() {
  307. schedule('a').then(function() {
  308. schedule('b');
  309. return promise.delayed(5).then(function() {
  310. return schedule('c');
  311. });
  312. });
  313. schedule('d');
  314. return waitForIdle().then(function() {
  315. assertFlowHistory('a', 'b', 'c', 'd');
  316. });
  317. });
  318. it('callbackReturnsPromiseThatDependsOnATask_2', function() {
  319. schedule('a').then(function() {
  320. schedule('b');
  321. return promise.delayed(5).
  322. then(function() { return promise.delayed(5) }).
  323. then(function() { return promise.delayed(5) }).
  324. then(function() { return promise.delayed(5) }).
  325. then(function() { return schedule('c'); });
  326. });
  327. schedule('d');
  328. return waitForIdle().then(function() {
  329. assertFlowHistory('a', 'b', 'c', 'd');
  330. });
  331. });
  332. it('eachCallbackWaitsForAllScheduledTasksToComplete', function() {
  333. schedule('a').
  334. then(function() {
  335. schedule('b');
  336. schedule('c');
  337. }).
  338. then(function() {
  339. schedule('d');
  340. });
  341. schedule('e');
  342. return waitForIdle().then(function() {
  343. assertFlowHistory('a', 'b', 'c', 'd', 'e');
  344. });
  345. });
  346. it('eachCallbackWaitsForReturnTasksToComplete', function() {
  347. schedule('a').
  348. then(function() {
  349. schedule('b');
  350. return schedule('c');
  351. }).
  352. then(function() {
  353. schedule('d');
  354. });
  355. schedule('e');
  356. return waitForIdle().then(function() {
  357. assertFlowHistory('a', 'b', 'c', 'd', 'e');
  358. });
  359. });
  360. it('callbacksOnAResolvedPromiseInsertIntoTheCurrentFlow', function() {
  361. promise.fulfilled().then(function() {
  362. schedule('b');
  363. });
  364. schedule('a');
  365. return waitForIdle().then(function() {
  366. assertFlowHistory('b', 'a');
  367. });
  368. });
  369. it('callbacksInterruptTheFlowWhenPromiseIsResolved', function() {
  370. schedule('a').then(function() {
  371. schedule('c');
  372. });
  373. schedule('b');
  374. return waitForIdle().then(function() {
  375. assertFlowHistory('a', 'c', 'b');
  376. });
  377. });
  378. it('allCallbacksInAFrameAreScheduledWhenPromiseIsResolved', function() {
  379. var a = schedule('a');
  380. a.then(function() { schedule('b'); });
  381. schedule('c');
  382. a.then(function() { schedule('d'); });
  383. schedule('e');
  384. return waitForIdle().then(function() {
  385. assertFlowHistory('a', 'b', 'c', 'd', 'e');
  386. });
  387. });
  388. it('tasksScheduledInInActiveFrameDoNotGetPrecedence', function() {
  389. var d = promise.fulfilled();
  390. schedule('a');
  391. schedule('b');
  392. d.then(function() { schedule('c'); });
  393. return waitForIdle().then(function() {
  394. assertFlowHistory('a', 'b', 'c');
  395. });
  396. });
  397. it('tasksScheduledInAFrameGetPrecedence_1', function() {
  398. var a = schedule('a');
  399. schedule('b').then(function() {
  400. a.then(function() {
  401. schedule('c');
  402. schedule('d');
  403. });
  404. var e = schedule('e');
  405. a.then(function() {
  406. schedule('f');
  407. e.then(function() {
  408. schedule('g');
  409. });
  410. schedule('h');
  411. });
  412. schedule('i');
  413. });
  414. schedule('j');
  415. return waitForIdle().then(function() {
  416. assertFlowHistory('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j');
  417. });
  418. });
  419. });
  420. describe('testErrorHandling', function() {
  421. it('thrownErrorsArePassedToTaskErrback', function() {
  422. scheduleAction('function that throws', throwStubError).
  423. then(fail, assertIsStubError);
  424. return waitForIdle();
  425. });
  426. it('thrownErrorsPropagateThroughPromiseChain', function() {
  427. scheduleAction('function that throws', throwStubError).
  428. then(fail).
  429. then(fail, assertIsStubError);
  430. return waitForIdle();
  431. });
  432. it('catchesErrorsFromFailedTasksInAFrame', function() {
  433. schedule('a').then(function() {
  434. schedule('b');
  435. scheduleAction('function that throws', throwStubError);
  436. }).
  437. then(fail, assertIsStubError);
  438. return waitForIdle();
  439. });
  440. it('abortsIfOnlyTaskReturnsAnUnhandledRejection', function() {
  441. scheduleAction('function that returns rejected promise', function() {
  442. return promise.rejected(new StubError);
  443. });
  444. return waitForAbort().then(assertIsStubError);
  445. });
  446. it('abortsIfThereIsAnUnhandledRejection', function() {
  447. promise.rejected(new StubError);
  448. schedule('this should not run');
  449. return waitForAbort().
  450. then(assertIsStubError).
  451. then(function() {
  452. assertFlowHistory(/* none */);
  453. });
  454. });
  455. it('abortsSequenceIfATaskFails', function() {
  456. schedule('a');
  457. schedule('b');
  458. scheduleAction('c', throwStubError);
  459. schedule('d'); // Should never execute.
  460. return waitForAbort().
  461. then(assertIsStubError).
  462. then(function() {
  463. assertFlowHistory('a', 'b', 'c');
  464. });
  465. });
  466. it('abortsFromUnhandledFramedTaskFailures_1', function() {
  467. schedule('outer task').then(function() {
  468. scheduleAction('inner task', throwStubError);
  469. });
  470. schedule('this should not run');
  471. return waitForAbort().
  472. then(assertIsStubError).
  473. then(function() {
  474. assertFlowHistory('outer task', 'inner task');
  475. });
  476. });
  477. it('abortsFromUnhandledFramedTaskFailures_2', function() {
  478. schedule('a').then(function() {
  479. schedule('b').then(function() {
  480. scheduleAction('c', throwStubError);
  481. // This should not execute.
  482. schedule('d');
  483. });
  484. });
  485. return waitForAbort().
  486. then(assertIsStubError).
  487. then(function() {
  488. assertFlowHistory('a', 'b', 'c');
  489. });
  490. });
  491. it('abortsWhenErrorBubblesUpFromFullyResolvingAnObject', function() {
  492. var callback = sinon.spy();
  493. scheduleAction('', function() {
  494. var obj = {'foo': promise.rejected(new StubError)};
  495. return promise.fullyResolved(obj).then(callback);
  496. });
  497. return waitForAbort().
  498. then(assertIsStubError).
  499. then(() => assert(!callback.called));
  500. });
  501. it('abortsWhenErrorBubblesUpFromFullyResolvingAnObject_withCallback', function() {
  502. var callback1 = sinon.spy();
  503. var callback2 = sinon.spy();
  504. scheduleAction('', function() {
  505. var obj = {'foo': promise.rejected(new StubError)};
  506. return promise.fullyResolved(obj).then(callback1);
  507. }).then(callback2);
  508. return waitForAbort().
  509. then(assertIsStubError).
  510. then(() => assert(!callback1.called)).
  511. then(() => assert(!callback2.called));
  512. });
  513. it('canCatchErrorsFromNestedTasks', function() {
  514. var errback = sinon.spy();
  515. schedule('a').
  516. then(function() {
  517. return scheduleAction('b', throwStubError);
  518. }).
  519. catch(errback);
  520. return waitForIdle().then(function() {
  521. assert(errback.called);
  522. assertIsStubError(errback.getCall(0).args[0]);
  523. });
  524. });
  525. it('nestedCommandFailuresCanBeCaughtAndSuppressed', function() {
  526. var errback = sinon.spy();
  527. schedule('a').then(function() {
  528. return schedule('b').then(function() {
  529. return schedule('c').then(function() {
  530. throw new StubError;
  531. });
  532. });
  533. }).catch(errback);
  534. schedule('d');
  535. return waitForIdle().
  536. then(function() {
  537. assert(errback.called);
  538. assertIsStubError(errback.getCall(0).args[0]);
  539. assertFlowHistory('a', 'b', 'c', 'd');
  540. });
  541. });
  542. it('aTaskWithAnUnhandledPromiseRejection', function() {
  543. schedule('a');
  544. scheduleAction('sub-tasks', function() {
  545. promise.rejected(new StubError);
  546. });
  547. schedule('should never run');
  548. return waitForAbort().
  549. then(assertIsStubError).
  550. then(function() {
  551. assertFlowHistory('a', 'sub-tasks');
  552. });
  553. });
  554. it('aTaskThatReutrnsARejectedPromise', function() {
  555. schedule('a');
  556. scheduleAction('sub-tasks', function() {
  557. return promise.rejected(new StubError);
  558. });
  559. schedule('should never run');
  560. return waitForAbort().
  561. then(assertIsStubError).
  562. then(function() {
  563. assertFlowHistory('a', 'sub-tasks');
  564. });
  565. });
  566. it('discardsSubtasksIfTaskThrows', function() {
  567. var pair = callbackPair(null, assertIsStubError);
  568. scheduleAction('a', function() {
  569. schedule('b');
  570. schedule('c');
  571. throwStubError();
  572. }).then(pair.callback, pair.errback);
  573. schedule('d');
  574. return waitForIdle().
  575. then(pair.assertErrback).
  576. then(function() {
  577. assertFlowHistory('a', 'd');
  578. });
  579. });
  580. it('discardsRemainingSubtasksIfASubtaskFails', function() {
  581. var pair = callbackPair(null, assertIsStubError);
  582. scheduleAction('a', function() {
  583. schedule('b');
  584. scheduleAction('c', throwStubError);
  585. schedule('d');
  586. }).then(pair.callback, pair.errback);
  587. schedule('e');
  588. return waitForIdle().
  589. then(pair.assertErrback).
  590. then(function() {
  591. assertFlowHistory('a', 'b', 'c', 'e');
  592. });
  593. });
  594. });
  595. describe('testTryModelingFinally', function() {
  596. it('happyPath', function() {
  597. /* Model:
  598. try {
  599. doFoo();
  600. doBar();
  601. } finally {
  602. doBaz();
  603. }
  604. */
  605. schedulePush('foo').
  606. then(() => schedulePush('bar')).
  607. finally(() => schedulePush('baz'));
  608. return waitForIdle().then(assertingMessages('foo', 'bar', 'baz'));
  609. });
  610. it('firstTryFails', function() {
  611. /* Model:
  612. try {
  613. doFoo();
  614. doBar();
  615. } finally {
  616. doBaz();
  617. }
  618. */
  619. scheduleAction('doFoo and throw', function() {
  620. messages.push('foo');
  621. throw new StubError;
  622. }).
  623. then(function() { schedulePush('bar'); }).
  624. finally(function() { schedulePush('baz'); });
  625. return waitForAbort().
  626. then(assertIsStubError).
  627. then(assertingMessages('foo', 'baz'));
  628. });
  629. it('secondTryFails', function() {
  630. /* Model:
  631. try {
  632. doFoo();
  633. doBar();
  634. } finally {
  635. doBaz();
  636. }
  637. */
  638. schedulePush('foo').
  639. then(function() {
  640. return scheduleAction('doBar and throw', function() {
  641. messages.push('bar');
  642. throw new StubError;
  643. });
  644. }).
  645. finally(function() {
  646. return schedulePush('baz');
  647. });
  648. return waitForAbort().
  649. then(assertIsStubError).
  650. then(assertingMessages('foo', 'bar', 'baz'));
  651. });
  652. });
  653. describe('testTaskCallbacksInterruptFlow', function() {
  654. it('(base case)', function() {
  655. schedule('a').then(function() {
  656. schedule('b');
  657. });
  658. schedule('c');
  659. return waitForIdle().then(function() {
  660. assertFlowHistory('a', 'b', 'c');
  661. });
  662. });
  663. it('taskDependsOnImmediatelyFulfilledPromise', function() {
  664. scheduleAction('a', function() {
  665. return promise.fulfilled();
  666. }).then(function() {
  667. schedule('b');
  668. });
  669. schedule('c');
  670. return waitForIdle().then(function() {
  671. assertFlowHistory('a', 'b', 'c');
  672. });
  673. });
  674. it('taskDependsOnPreviouslyFulfilledPromise', function() {
  675. var aPromise = promise.fulfilled(123);
  676. scheduleAction('a', function() {
  677. return aPromise;
  678. }).then(function(value) {
  679. assert.equal(123, value);
  680. schedule('b');
  681. });
  682. schedule('c');
  683. return waitForIdle().then(function() {
  684. assertFlowHistory('a', 'b', 'c');
  685. });
  686. });
  687. it('taskDependsOnAsyncPromise', function() {
  688. scheduleAction('a', function() {
  689. return promise.delayed(25);
  690. }).then(function() {
  691. schedule('b');
  692. });
  693. schedule('c');
  694. return waitForIdle().then(function() {
  695. assertFlowHistory('a', 'b', 'c');
  696. });
  697. });
  698. it('promiseChainedToTaskInterruptFlow', function() {
  699. schedule('a').then(function() {
  700. return promise.fulfilled();
  701. }).then(function() {
  702. return promise.fulfilled();
  703. }).then(function() {
  704. schedule('b');
  705. });
  706. schedule('c');
  707. return waitForIdle().then(function() {
  708. assertFlowHistory('a', 'b', 'c');
  709. });
  710. });
  711. it('nestedTaskCallbacksInterruptFlowWhenResolved', function() {
  712. schedule('a').then(function() {
  713. schedule('b').then(function() {
  714. schedule('c');
  715. });
  716. });
  717. schedule('d');
  718. return waitForIdle().then(function() {
  719. assertFlowHistory('a', 'b', 'c', 'd');
  720. });
  721. });
  722. });
  723. describe('testDelayedNesting', function() {
  724. it('1', function() {
  725. var a = schedule('a');
  726. schedule('b').then(function() {
  727. a.then(function() { schedule('c'); });
  728. schedule('d');
  729. });
  730. schedule('e');
  731. return waitForIdle().then(function() {
  732. assertFlowHistory('a', 'b', 'c', 'd', 'e');
  733. });
  734. });
  735. it('2', function() {
  736. var a = schedule('a');
  737. schedule('b').then(function() {
  738. a.then(function() { schedule('c'); });
  739. schedule('d');
  740. a.then(function() { schedule('e'); });
  741. });
  742. schedule('f');
  743. return waitForIdle().then(function() {
  744. assertFlowHistory('a', 'b', 'c', 'd', 'e', 'f');
  745. });
  746. });
  747. it('3', function() {
  748. var a = schedule('a');
  749. schedule('b').then(function() {
  750. a.then(function() { schedule('c'); });
  751. a.then(function() { schedule('d'); });
  752. });
  753. schedule('e');
  754. return waitForIdle().then(function() {
  755. assertFlowHistory('a', 'b', 'c', 'd', 'e');
  756. });
  757. });
  758. it('4', function() {
  759. var a = schedule('a');
  760. schedule('b').then(function() {
  761. a.then(function() { schedule('c'); }).then(function() {
  762. schedule('d');
  763. });
  764. a.then(function() { schedule('e'); });
  765. });
  766. schedule('f');
  767. return waitForIdle().then(function() {
  768. assertFlowHistory('a', 'b', 'c', 'd', 'e', 'f');
  769. });
  770. });
  771. it('5', function() {
  772. var a = schedule('a');
  773. schedule('b').then(function() {
  774. var c;
  775. a.then(function() { c = schedule('c'); }).then(function() {
  776. schedule('d');
  777. a.then(function() { schedule('e'); });
  778. c.then(function() { schedule('f'); });
  779. schedule('g');
  780. });
  781. a.then(function() { schedule('h'); });
  782. });
  783. schedule('i');
  784. return waitForIdle().then(function() {
  785. assertFlowHistory('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i');
  786. });
  787. });
  788. });
  789. describe('testWaiting', function() {
  790. it('onAConditionThatIsAlwaysTrue', function() {
  791. scheduleWait(function() { return true;}, 0, 'waiting on true');
  792. return waitForIdle().then(function() {
  793. assertFlowHistory('0: waiting on true');
  794. });
  795. });
  796. it('aSimpleCountingCondition', function() {
  797. var count = 0;
  798. scheduleWait(function() {
  799. return ++count == 3;
  800. }, 100, 'counting to 3');
  801. return waitForIdle().then(function() {
  802. assert.equal(3, count);
  803. });
  804. });
  805. it('aConditionThatReturnsAPromise', function() {
  806. var d = new promise.Deferred();
  807. var count = 0;
  808. scheduleWait(function() {
  809. count += 1;
  810. return d.promise;
  811. }, 0, 'waiting for promise');
  812. return timeout(50).then(function() {
  813. assert.equal(1, count);
  814. d.fulfill(123);
  815. return waitForIdle();
  816. });
  817. });
  818. it('aConditionThatReturnsAPromise_2', function() {
  819. var count = 0;
  820. scheduleWait(function() {
  821. return promise.fulfilled(++count == 3);
  822. }, 100, 'waiting for promise');
  823. return waitForIdle().then(function() {
  824. assert.equal(3, count);
  825. });
  826. });
  827. it('aConditionThatReturnsATaskResult', function() {
  828. var count = 0;
  829. scheduleWait(function() {
  830. return scheduleAction('increment count', function() {
  831. return ++count == 3;
  832. });
  833. }, 100, 'counting to 3');
  834. schedule('post wait');
  835. return waitForIdle().then(function() {
  836. assert.equal(3, count);
  837. assertFlowHistory(
  838. '0: counting to 3', 'increment count',
  839. '1: counting to 3', 'increment count',
  840. '2: counting to 3', 'increment count',
  841. 'post wait');
  842. });
  843. });
  844. it('conditionContainsASubtask', function() {
  845. var count = 0;
  846. scheduleWait(function() {
  847. schedule('sub task');
  848. return ++count == 3;
  849. }, 100, 'counting to 3');
  850. schedule('post wait');
  851. return waitForIdle().then(function() {
  852. assert.equal(3, count);
  853. assertFlowHistory(
  854. '0: counting to 3', 'sub task',
  855. '1: counting to 3', 'sub task',
  856. '2: counting to 3', 'sub task',
  857. 'post wait');
  858. });
  859. });
  860. it('cancelsWaitIfScheduledTaskFails', function() {
  861. var pair = callbackPair(null, assertIsStubError);
  862. scheduleWait(function() {
  863. scheduleAction('boom', throwStubError);
  864. schedule('this should not run');
  865. return true;
  866. }, 100, 'waiting to go boom').then(pair.callback, pair.errback);
  867. schedule('post wait');
  868. return waitForIdle().
  869. then(pair.assertErrback).
  870. then(function() {
  871. assertFlowHistory(
  872. '0: waiting to go boom', 'boom',
  873. 'post wait');
  874. });
  875. });
  876. it('failsIfConditionThrows', function() {
  877. var callbacks = callbackPair(null, assertIsStubError);
  878. scheduleWait(throwStubError, 0, 'goes boom').
  879. then(callbacks.callback, callbacks.errback);
  880. schedule('post wait');
  881. return waitForIdle().
  882. then(callbacks.assertErrback).
  883. then(function() {
  884. assertFlowHistory('0: goes boom', 'post wait');
  885. });
  886. });
  887. it('failsIfConditionReturnsARejectedPromise', function() {
  888. var callbacks = callbackPair(null, assertIsStubError);
  889. scheduleWait(function() {
  890. return promise.rejected(new StubError);
  891. }, 0, 'goes boom').then(callbacks.callback, callbacks.errback);
  892. schedule('post wait');
  893. return waitForIdle().
  894. then(callbacks.assertErrback).
  895. then(function() {
  896. assertFlowHistory('0: goes boom', 'post wait');
  897. });
  898. });
  899. it('failsIfConditionHasUnhandledRejection', function() {
  900. var callbacks = callbackPair(null, assertIsStubError);
  901. scheduleWait(function() {
  902. promise.controlFlow().execute(throwStubError);
  903. }, 0, 'goes boom').then(callbacks.callback, callbacks.errback);
  904. schedule('post wait');
  905. return waitForIdle().
  906. then(callbacks.assertErrback).
  907. then(function() {
  908. assertFlowHistory('0: goes boom', 'post wait');
  909. });
  910. });
  911. it('failsIfConditionHasAFailedSubtask', function() {
  912. var callbacks = callbackPair(null, assertIsStubError);
  913. var count = 0;
  914. scheduleWait(function() {
  915. scheduleAction('maybe throw', function() {
  916. if (++count == 2) {
  917. throw new StubError;
  918. }
  919. });
  920. }, 100, 'waiting').then(callbacks.callback, callbacks.errback);
  921. schedule('post wait');
  922. return waitForIdle().then(function() {
  923. assert.equal(2, count);
  924. assertFlowHistory(
  925. '0: waiting', 'maybe throw',
  926. '1: waiting', 'maybe throw',
  927. 'post wait');
  928. });
  929. });
  930. it('pollingLoopWaitsForAllScheduledTasksInCondition', function() {
  931. var count = 0;
  932. scheduleWait(function() {
  933. scheduleAction('increment count', function() { ++count; });
  934. return count >= 3;
  935. }, 100, 'counting to 3');
  936. schedule('post wait');
  937. return waitForIdle().then(function() {
  938. assert.equal(4, count);
  939. assertFlowHistory(
  940. '0: counting to 3', 'increment count',
  941. '1: counting to 3', 'increment count',
  942. '2: counting to 3', 'increment count',
  943. '3: counting to 3', 'increment count',
  944. 'post wait');
  945. });
  946. });
  947. it('waitsForeverOnAZeroTimeout', function() {
  948. var done = false;
  949. setTimeout(function() {
  950. done = true;
  951. }, 150);
  952. var waitResult = scheduleWait(function() {
  953. return done;
  954. }, 0);
  955. return timeout(75).then(function() {
  956. assert.ok(!done);
  957. return timeout(100);
  958. }).then(function() {
  959. assert.ok(done);
  960. return waitResult;
  961. });
  962. });
  963. it('waitsForeverIfTimeoutOmitted', function() {
  964. var done = false;
  965. setTimeout(function() {
  966. done = true;
  967. }, 150);
  968. var waitResult = scheduleWait(function() {
  969. return done;
  970. });
  971. return timeout(75).then(function() {
  972. assert.ok(!done);
  973. return timeout(100);
  974. }).then(function() {
  975. assert.ok(done);
  976. return waitResult;
  977. });
  978. });
  979. it('timesOut_nonZeroTimeout', function() {
  980. var count = 0;
  981. scheduleWait(function() {
  982. count += 1;
  983. var ms = count === 2 ? 65 : 5;
  984. return promise.delayed(ms).then(function() {
  985. return false;
  986. });
  987. }, 60, 'counting to 3');
  988. return waitForAbort().then(function(e) {
  989. switch (count) {
  990. case 1:
  991. assertFlowHistory('0: counting to 3');
  992. break;
  993. case 2:
  994. assertFlowHistory('0: counting to 3', '1: counting to 3');
  995. break;
  996. default:
  997. fail('unexpected polling count: ' + count);
  998. }
  999. assert.ok(e instanceof TimeoutError, 'Unexpected error: ' + e);
  1000. assert.ok(
  1001. /^counting to 3\nWait timed out after \d+ms$/.test(e.message));
  1002. });
  1003. });
  1004. it('shouldFailIfConditionReturnsARejectedPromise', function() {
  1005. scheduleWait(function() {
  1006. return promise.rejected(new StubError);
  1007. }, 100, 'returns rejected promise on first pass');
  1008. return waitForAbort().then(assertIsStubError);
  1009. });
  1010. it('scheduleWithIntermittentWaits', function() {
  1011. schedule('a');
  1012. scheduleWait(function() { return true; }, 0, 'wait 1');
  1013. schedule('b');
  1014. scheduleWait(function() { return true; }, 0, 'wait 2');
  1015. schedule('c');
  1016. scheduleWait(function() { return true; }, 0, 'wait 3');
  1017. return waitForIdle().then(function() {
  1018. assertFlowHistory('a', '0: wait 1', 'b', '0: wait 2', 'c', '0: wait 3');
  1019. });
  1020. });
  1021. it('scheduleWithIntermittentAndNestedWaits', function() {
  1022. schedule('a');
  1023. scheduleWait(function() { return true; }, 0, 'wait 1').
  1024. then(function() {
  1025. schedule('d');
  1026. scheduleWait(function() { return true; }, 0, 'wait 2');
  1027. schedule('e');
  1028. });
  1029. schedule('b');
  1030. scheduleWait(function() { return true; }, 0, 'wait 3');
  1031. schedule('c');
  1032. scheduleWait(function() { return true; }, 0, 'wait 4');
  1033. return waitForIdle().then(function() {
  1034. assertFlowHistory(
  1035. 'a', '0: wait 1', 'd', '0: wait 2', 'e', 'b', '0: wait 3', 'c',
  1036. '0: wait 4');
  1037. });
  1038. });
  1039. it('requiresConditionToBeAPromiseOrFunction', function() {
  1040. assert.throws(function() {
  1041. flow.wait(1234, 0);
  1042. });
  1043. flow.wait(function() { return true;}, 0);
  1044. flow.wait(promise.fulfilled(), 0);
  1045. return waitForIdle();
  1046. });
  1047. it('promiseThatDoesNotResolveBeforeTimeout', function() {
  1048. var d = promise.defer();
  1049. flow.wait(d.promise, 5).then(fail, function(e) {
  1050. assert.ok(e instanceof TimeoutError, 'Unexpected error: ' + e);
  1051. assert.ok(
  1052. /Timed out waiting for promise to resolve after \d+ms/
  1053. .test(e.message),
  1054. 'unexpected error message: ' + e.message);
  1055. });
  1056. return waitForIdle();
  1057. });
  1058. it('unboundedWaitOnPromiseResolution', function() {
  1059. var messages = [];
  1060. var d = promise.defer();
  1061. var waitResult = flow.wait(d.promise).then(function(value) {
  1062. messages.push('b');
  1063. assert.equal(1234, value);
  1064. });
  1065. setTimeout(function() {
  1066. messages.push('a');
  1067. }, 5);
  1068. timeout(10).then(function() {
  1069. assert.deepEqual(['a'], messages);
  1070. d.fulfill(1234);
  1071. return waitResult;
  1072. }).then(function() {
  1073. assert.deepEqual(['a', 'b'], messages);
  1074. });
  1075. return waitForIdle();
  1076. });
  1077. });
  1078. describe('testSubtasks', function() {
  1079. it('(base case)', function() {
  1080. schedule('a');
  1081. scheduleAction('sub-tasks', function() {
  1082. schedule('c');
  1083. schedule('d');
  1084. });
  1085. schedule('b');
  1086. return waitForIdle().then(function() {
  1087. assertFlowHistory('a', 'sub-tasks', 'c', 'd', 'b');
  1088. });
  1089. });
  1090. it('nesting', function() {
  1091. schedule('a');
  1092. scheduleAction('sub-tasks', function() {
  1093. schedule('b');
  1094. scheduleAction('sub-sub-tasks', function() {
  1095. schedule('c');
  1096. schedule('d');
  1097. });
  1098. schedule('e');
  1099. });
  1100. schedule('f');
  1101. return waitForIdle().then(function() {
  1102. assertFlowHistory(
  1103. 'a', 'sub-tasks', 'b', 'sub-sub-tasks', 'c', 'd', 'e', 'f');
  1104. });
  1105. });
  1106. it('taskReturnsSubTaskResult_1', function() {
  1107. schedule('a');
  1108. scheduleAction('sub-tasks', function() {
  1109. return schedule('c');
  1110. });
  1111. schedule('b');
  1112. return waitForIdle().then(function() {
  1113. assertFlowHistory('a', 'sub-tasks', 'c', 'b');
  1114. });
  1115. });
  1116. it('taskReturnsSubTaskResult_2', function() {
  1117. let pair = callbackPair((value) => assert.equal(123, value));
  1118. schedule('a');
  1119. schedule('sub-tasks', promise.fulfilled(123)).then(pair.callback);
  1120. schedule('b');
  1121. return waitForIdle().then(function() {
  1122. assertFlowHistory('a', 'sub-tasks','b');
  1123. pair.assertCallback();
  1124. });
  1125. });
  1126. it('taskReturnsPromiseThatDependsOnSubtask_1', function() {
  1127. scheduleAction('a', function() {
  1128. return promise.delayed(10).then(function() {
  1129. schedule('b');
  1130. });
  1131. });
  1132. schedule('c');
  1133. return waitForIdle().then(function() {
  1134. assertFlowHistory('a', 'b', 'c');
  1135. });
  1136. });
  1137. it('taskReturnsPromiseThatDependsOnSubtask_2', function() {
  1138. scheduleAction('a', function() {
  1139. return promise.fulfilled().then(function() {
  1140. schedule('b');
  1141. });
  1142. });
  1143. schedule('c');
  1144. return waitForIdle().then(function() {
  1145. assertFlowHistory('a', 'b', 'c');
  1146. });
  1147. });
  1148. it('taskReturnsPromiseThatDependsOnSubtask_3', function() {
  1149. scheduleAction('a', function() {
  1150. return promise.delayed(10).then(function() {
  1151. return schedule('b');
  1152. });
  1153. });
  1154. schedule('c');
  1155. return waitForIdle().then(function() {
  1156. assertFlowHistory('a', 'b', 'c');
  1157. });
  1158. });
  1159. it('taskReturnsPromiseThatDependsOnSubtask_4', function() {
  1160. scheduleAction('a', function() {
  1161. return promise.delayed(5).then(function() {
  1162. return promise.delayed(5).then(function() {
  1163. return schedule('b');
  1164. });
  1165. });
  1166. });
  1167. schedule('c');
  1168. return waitForIdle().then(function() {
  1169. assertFlowHistory('a', 'b', 'c');
  1170. });
  1171. });
  1172. it('taskReturnsPromiseThatDependsOnSubtask_5', function() {
  1173. scheduleAction('a', function() {
  1174. return promise.delayed(5).then(function() {
  1175. return promise.delayed(5).then(function() {
  1176. return promise.delayed(5).then(function() {
  1177. return promise.delayed(5).then(function() {
  1178. return schedule('b');
  1179. });
  1180. });
  1181. });
  1182. });
  1183. });
  1184. schedule('c');
  1185. return waitForIdle().then(function() {
  1186. assertFlowHistory('a', 'b', 'c');
  1187. });
  1188. });
  1189. it('taskReturnsPromiseThatDependsOnSubtask_6', function() {
  1190. scheduleAction('a', function() {
  1191. return promise.delayed(5).
  1192. then(function() { return promise.delayed(5) }).
  1193. then(function() { return promise.delayed(5) }).
  1194. then(function() { return promise.delayed(5) }).
  1195. then(function() { return schedule('b'); });
  1196. });
  1197. schedule('c');
  1198. return waitForIdle().then(function() {
  1199. assertFlowHistory('a', 'b', 'c');
  1200. });
  1201. });
  1202. it('subTaskFails_1', function() {
  1203. schedule('a');
  1204. scheduleAction('sub-tasks', function() {
  1205. scheduleAction('sub-task that fails', throwStubError);
  1206. });
  1207. schedule('should never execute');
  1208. return waitForAbort().
  1209. then(assertIsStubError).
  1210. then(function() {
  1211. assertFlowHistory('a', 'sub-tasks', 'sub-task that fails');
  1212. });
  1213. });
  1214. it('subTaskFails_2', function() {
  1215. schedule('a');
  1216. scheduleAction('sub-tasks', function() {
  1217. return promise.rejected(new StubError);
  1218. });
  1219. schedule('should never execute');
  1220. return waitForAbort().
  1221. then(assertIsStubError).
  1222. then(function() {
  1223. assertFlowHistory('a', 'sub-tasks');
  1224. });
  1225. });
  1226. it('subTaskFails_3', function() {
  1227. var callbacks = callbackPair(null, assertIsStubError);
  1228. schedule('a');
  1229. scheduleAction('sub-tasks', function() {
  1230. return promise.rejected(new StubError);
  1231. }).then(callbacks.callback, callbacks.errback);
  1232. schedule('b');
  1233. return waitForIdle().
  1234. then(function() {
  1235. assertFlowHistory('a', 'sub-tasks', 'b');
  1236. callbacks.assertErrback();
  1237. });
  1238. });
  1239. });
  1240. describe('testEventLoopWaitsOnPendingPromiseRejections', function() {
  1241. it('oneRejection', function() {
  1242. var d = new promise.Deferred;
  1243. scheduleAction('one', function() {
  1244. return d.promise;
  1245. });
  1246. scheduleAction('two', function() {});
  1247. return timeout(50).then(function() {
  1248. assertFlowHistory('one');
  1249. d.reject(new StubError);
  1250. return waitForAbort();
  1251. }).
  1252. then(assertIsStubError).
  1253. then(function() {
  1254. assertFlowHistory('one');
  1255. });
  1256. });
  1257. it('multipleRejections', function() {
  1258. var once = Error('once');
  1259. var twice = Error('twice');
  1260. scheduleAction('one', function() {
  1261. promise.rejected(once);
  1262. promise.rejected(twice);
  1263. });
  1264. var twoResult = scheduleAction('two', function() {});
  1265. flow.removeAllListeners(
  1266. promise.ControlFlow.EventType.UNCAUGHT_EXCEPTION);
  1267. return new NativePromise(function(fulfill, reject) {
  1268. setTimeout(function() {
  1269. reject(Error('Should have reported the two errors by now'));
  1270. }, 50);
  1271. flow.on(
  1272. promise.ControlFlow.EventType.UNCAUGHT_EXCEPTION,
  1273. fulfill);
  1274. }).then(function(e) {
  1275. assert.ok(e instanceof promise.MultipleUnhandledRejectionError,
  1276. 'Not a MultipleUnhandledRejectionError');
  1277. let errors = Array.from(e.errors);
  1278. assert.deepEqual([once, twice], errors);
  1279. assertFlowHistory('one');
  1280. });
  1281. });
  1282. });
  1283. describe('testCancelsPromiseReturnedByCallbackIfFrameFails', function() {
  1284. it('promiseCallback', function() {
  1285. var chainPair = callbackPair(null, assertIsStubError);
  1286. var deferredPair = callbackPair(null, function(e) {
  1287. assert.equal('CancellationError: StubError', e.toString(),
  1288. 'callback result should be cancelled');
  1289. });
  1290. var d = new promise.Deferred();
  1291. d.promise.then(deferredPair.callback, deferredPair.errback);
  1292. promise.fulfilled().
  1293. then(function() {
  1294. scheduleAction('boom', throwStubError);
  1295. schedule('this should not run');
  1296. return d.promise;
  1297. }).
  1298. then(chainPair.callback, chainPair.errback);
  1299. return waitForIdle().then(function() {
  1300. assertFlowHistory('boom');
  1301. chainPair.assertErrback('chain errback not invoked');
  1302. deferredPair.assertErrback('deferred errback not invoked');
  1303. });
  1304. });
  1305. it('taskCallback', function() {
  1306. var chainPair = callbackPair(null, assertIsStubError);
  1307. var deferredPair = callbackPair(null, function(e) {
  1308. assert.equal('CancellationError: StubError', e.toString(),
  1309. 'callback result should be cancelled');
  1310. });
  1311. var d = new promise.Deferred();
  1312. d.promise.then(deferredPair.callback, deferredPair.errback);
  1313. schedule('a').
  1314. then(function() {
  1315. scheduleAction('boom', throwStubError);
  1316. schedule('this should not run');
  1317. return d.promise;
  1318. }).
  1319. then(chainPair.callback, chainPair.errback);
  1320. return waitForIdle().then(function() {
  1321. assertFlowHistory('a', 'boom');
  1322. chainPair.assertErrback('chain errback not invoked');
  1323. deferredPair.assertErrback('deferred errback not invoked');
  1324. });
  1325. });
  1326. });
  1327. it('testMaintainsOrderInCallbacksWhenATaskReturnsAPromise', function() {
  1328. schedule('__start__', promise.fulfilled()).
  1329. then(function() {
  1330. messages.push('a');
  1331. schedulePush('b');
  1332. messages.push('c');
  1333. }).
  1334. then(function() {
  1335. messages.push('d');
  1336. });
  1337. schedulePush('e');
  1338. return waitForIdle().then(function() {
  1339. assertFlowHistory('__start__', 'b', 'e');
  1340. assertMessages('a', 'c', 'b', 'd', 'e');
  1341. });
  1342. });
  1343. it('testOwningFlowIsActivatedForExecutingTasks', function() {
  1344. var defaultFlow = promise.controlFlow();
  1345. var order = [];
  1346. promise.createFlow(function(flow) {
  1347. assertFlowIs(flow);
  1348. order.push(0);
  1349. defaultFlow.execute(function() {
  1350. assertFlowIs(defaultFlow);
  1351. order.push(1);
  1352. });
  1353. });
  1354. return waitForIdle().then(function() {
  1355. assertFlowIs(defaultFlow);
  1356. assert.deepEqual([0, 1], order);
  1357. });
  1358. });
  1359. it('testCreateFlowReturnsPromisePairedWithCreatedFlow', function() {
  1360. return new NativePromise(function(fulfill, reject) {
  1361. var newFlow;
  1362. promise.createFlow(function(flow) {
  1363. newFlow = flow;
  1364. assertFlowIs(newFlow);
  1365. }).then(function() {
  1366. assertFlowIs(newFlow);
  1367. waitForIdle(newFlow).then(fulfill, reject);
  1368. });
  1369. });
  1370. });
  1371. it('testDeferredFactoriesCreateForActiveFlow_defaultFlow', function() {
  1372. var e = Error();
  1373. var defaultFlow = promise.controlFlow();
  1374. promise.fulfilled().then(function() {
  1375. assertFlowIs(defaultFlow);
  1376. });
  1377. promise.rejected(e).then(null, function(err) {
  1378. assert.equal(e, err);
  1379. assertFlowIs(defaultFlow);
  1380. });
  1381. promise.defer().promise.then(function() {
  1382. assertFlowIs(defaultFlow);
  1383. });
  1384. return waitForIdle();
  1385. });
  1386. it('testDeferredFactoriesCreateForActiveFlow_newFlow', function() {
  1387. var e = Error();
  1388. var newFlow = new promise.ControlFlow;
  1389. newFlow.execute(function() {
  1390. promise.fulfilled().then(function() {
  1391. assertFlowIs(newFlow);
  1392. });
  1393. promise.rejected(e).then(null, function(err) {
  1394. assert.equal(e, err);
  1395. assertFlowIs(newFlow);
  1396. });
  1397. let d = promise.defer();
  1398. d.promise.then(function() {
  1399. assertFlowIs(newFlow);
  1400. });
  1401. d.fulfill();
  1402. }).then(function() {
  1403. assertFlowIs(newFlow);
  1404. });
  1405. return waitForIdle(newFlow);
  1406. });
  1407. it('testFlowsSynchronizeWithThemselvesNotEachOther', function() {
  1408. var defaultFlow = promise.controlFlow();
  1409. schedulePush('a', 'a');
  1410. promise.controlFlow().timeout(500);
  1411. schedulePush('b', 'b');
  1412. promise.createFlow(function(flow2) {
  1413. assertFlowIs(flow2);
  1414. schedulePush('c', 'c');
  1415. schedulePush('d', 'd');
  1416. });
  1417. return waitForIdle().then(function() {
  1418. assertMessages('a', 'c', 'd', 'b');
  1419. });
  1420. });
  1421. it('testUnhandledErrorsAreReportedToTheOwningFlow', function() {
  1422. var error1 = Error('e1');
  1423. var error2 = Error('e2');
  1424. var defaultFlow = promise.controlFlow();
  1425. defaultFlow.removeAllListeners('uncaughtException');
  1426. var flow1Error = defer();
  1427. flow1Error.promise.then(function(value) {
  1428. assert.equal(error2, value);
  1429. });
  1430. var flow2Error = defer();
  1431. flow2Error.promise.then(function(value) {
  1432. assert.equal(error1, value);
  1433. });
  1434. promise.createFlow(function(flow) {
  1435. flow.once('uncaughtException', flow2Error.resolve);
  1436. promise.rejected(error1);
  1437. defaultFlow.once('uncaughtException', flow1Error.resolve);
  1438. defaultFlow.execute(function() {
  1439. promise.rejected(error2);
  1440. });
  1441. });
  1442. return NativePromise.all([flow1Error.promise, flow2Error.promise]);
  1443. });
  1444. it('testCanSynchronizeFlowsByReturningPromiseFromOneToAnother', function() {
  1445. var flow1 = new promise.ControlFlow;
  1446. var flow1Done = defer();
  1447. flow1.once('idle', flow1Done.resolve);
  1448. flow1.once('uncaughtException', flow1Done.reject);
  1449. var flow2 = new promise.ControlFlow;
  1450. var flow2Done = defer();
  1451. flow2.once('idle', flow2Done.resolve);
  1452. flow2.once('uncaughtException', flow2Done.reject);
  1453. flow1.execute(function() {
  1454. schedulePush('a', 'a');
  1455. return promise.delayed(25);
  1456. }, 'start flow 1');
  1457. flow2.execute(function() {
  1458. schedulePush('b', 'b');
  1459. schedulePush('c', 'c');
  1460. flow2.execute(function() {
  1461. return flow1.execute(function() {
  1462. schedulePush('d', 'd');
  1463. }, 'flow 1 task');
  1464. }, 'inject flow1 result into flow2');
  1465. schedulePush('e', 'e');
  1466. }, 'start flow 2');
  1467. return NativePromise.all([flow1Done.promise, flow2Done.promise]).
  1468. then(function() {
  1469. assertMessages('a', 'b', 'c', 'd', 'e');
  1470. });
  1471. });
  1472. it('testFramesWaitToCompleteForPendingRejections', function() {
  1473. return new NativePromise(function(fulfill, reject) {
  1474. promise.controlFlow().execute(function() {
  1475. promise.rejected(new StubError);
  1476. }).then(fulfill, reject);
  1477. }).
  1478. then(() => fail('expected to fail'), assertIsStubError);
  1479. });
  1480. it('testSynchronizeErrorsPropagateToOuterFlow', function() {
  1481. var outerFlow = new promise.ControlFlow;
  1482. var innerFlow = new promise.ControlFlow;
  1483. var block = defer();
  1484. innerFlow.execute(function() {
  1485. return block.promise;
  1486. }, 'block inner flow');
  1487. outerFlow.execute(function() {
  1488. block.resolve();
  1489. return innerFlow.execute(function() {
  1490. promise.rejected(new StubError);
  1491. }, 'trigger unhandled rejection error');
  1492. }, 'run test');
  1493. return NativePromise.all([
  1494. waitForIdle(innerFlow),
  1495. waitForAbort(outerFlow).then(assertIsStubError)
  1496. ]);
  1497. });
  1498. it('testFailsIfErrbackThrows', function() {
  1499. promise.rejected('').then(null, throwStubError);
  1500. return waitForAbort().then(assertIsStubError);
  1501. });
  1502. it('testFailsIfCallbackReturnsRejectedPromise', function() {
  1503. promise.fulfilled().then(function() {
  1504. return promise.rejected(new StubError);
  1505. });
  1506. return waitForAbort().then(assertIsStubError);
  1507. });
  1508. it('testAbortsFrameIfTaskFails', function() {
  1509. promise.fulfilled().then(function() {
  1510. promise.controlFlow().execute(throwStubError);
  1511. });
  1512. return waitForAbort().then(assertIsStubError);
  1513. });
  1514. it('testAbortsFramePromisedChainedFromTaskIsNotHandled', function() {
  1515. promise.fulfilled().then(function() {
  1516. promise.controlFlow().execute(function() {}).
  1517. then(throwStubError);
  1518. });
  1519. return waitForAbort().then(assertIsStubError);
  1520. });
  1521. it('testTrapsChainedUnhandledRejectionsWithinAFrame', function() {
  1522. var pair = callbackPair(null, assertIsStubError);
  1523. promise.fulfilled().then(function() {
  1524. promise.controlFlow().execute(function() {}).
  1525. then(throwStubError);
  1526. }).then(pair.callback, pair.errback);
  1527. return waitForIdle().then(pair.assertErrback);
  1528. });
  1529. it('testCancelsRemainingTasksIfFrameThrowsDuringScheduling', function() {
  1530. var task1, task2;
  1531. var pair = callbackPair(null, assertIsStubError);
  1532. var flow = promise.controlFlow();
  1533. flow.execute(function() {
  1534. task1 = flow.execute(function() {});
  1535. task2 = flow.execute(function() {});
  1536. throw new StubError;
  1537. }).then(pair.callback, pair.errback);
  1538. return waitForIdle().
  1539. then(pair.assertErrback).
  1540. then(function() {
  1541. pair = callbackPair();
  1542. return task1.then(pair.callback, pair.errback);
  1543. }).
  1544. then(function() {
  1545. pair.assertErrback();
  1546. pair = callbackPair();
  1547. return task2.then(pair.callback, pair.errback);
  1548. }).
  1549. then(function() {
  1550. pair.assertErrback();
  1551. });
  1552. });
  1553. it('testCancelsRemainingTasksInFrameIfATaskFails', function() {
  1554. var task;
  1555. var pair = callbackPair(null, assertIsStubError);
  1556. var flow = promise.controlFlow();
  1557. flow.execute(function() {
  1558. flow.execute(throwStubError);
  1559. task = flow.execute(function() {});
  1560. }).then(pair.callback, pair.errback);
  1561. return waitForIdle().then(pair.assertErrback).then(function() {
  1562. pair = callbackPair();
  1563. task.then(pair.callback, pair.errback);
  1564. }).then(function() {
  1565. pair.assertErrback();
  1566. });
  1567. });
  1568. it('testDoesNotModifyRejectionErrorIfPromiseNotInsideAFlow', function() {
  1569. var error = Error('original message');
  1570. var originalStack = error.stack;
  1571. var originalStr = error.toString();
  1572. var pair = callbackPair(null, function(e) {
  1573. assert.equal(error, e);
  1574. assert.equal('original message', e.message);
  1575. assert.equal(originalStack, e.stack);
  1576. assert.equal(originalStr, e.toString());
  1577. });
  1578. promise.rejected(error).then(pair.callback, pair.errback);
  1579. return waitForIdle().then(pair.assertErrback);
  1580. });
  1581. /** See https://github.com/SeleniumHQ/selenium/issues/444 */
  1582. it('testMaintainsOrderWithPromiseChainsCreatedWithinAForeach_1', function() {
  1583. var messages = [];
  1584. flow.execute(function() {
  1585. return promise.fulfilled(['a', 'b', 'c', 'd']);
  1586. }, 'start').then(function(steps) {
  1587. steps.forEach(function(step) {
  1588. promise.fulfilled(step)
  1589. .then(function() {
  1590. messages.push(step + '.1');
  1591. }).then(function() {
  1592. messages.push(step + '.2');
  1593. });
  1594. })
  1595. });
  1596. return waitForIdle().then(function() {
  1597. assert.deepEqual(
  1598. ['a.1', 'a.2', 'b.1', 'b.2', 'c.1', 'c.2', 'd.1', 'd.2'],
  1599. messages);
  1600. });
  1601. });
  1602. /** See https://github.com/SeleniumHQ/selenium/issues/444 */
  1603. it('testMaintainsOrderWithPromiseChainsCreatedWithinAForeach_2', function() {
  1604. var messages = [];
  1605. flow.execute(function() {
  1606. return promise.fulfilled(['a', 'b', 'c', 'd']);
  1607. }, 'start').then(function(steps) {
  1608. steps.forEach(function(step) {
  1609. promise.fulfilled(step)
  1610. .then(function() {
  1611. messages.push(step + '.1');
  1612. }).then(function() {
  1613. flow.execute(function() {}, step + '.2').then(function() {
  1614. messages.push(step + '.2');
  1615. });
  1616. });
  1617. })
  1618. });
  1619. return waitForIdle().then(function() {
  1620. assert.deepEqual(
  1621. ['a.1', 'a.2', 'b.1', 'b.2', 'c.1', 'c.2', 'd.1', 'd.2'],
  1622. messages);
  1623. });
  1624. });
  1625. /** See https://github.com/SeleniumHQ/selenium/issues/444 */
  1626. it('testMaintainsOrderWithPromiseChainsCreatedWithinAForeach_3', function() {
  1627. var messages = [];
  1628. flow.execute(function() {
  1629. return promise.fulfilled(['a', 'b', 'c', 'd']);
  1630. }, 'start').then(function(steps) {
  1631. steps.forEach(function(step) {
  1632. promise.fulfilled(step)
  1633. .then(function(){})
  1634. .then(function() {
  1635. messages.push(step + '.1');
  1636. return flow.execute(function() {}, step + '.1');
  1637. }).then(function() {
  1638. flow.execute(function() {}, step + '.2').then(function(text) {
  1639. messages.push(step + '.2');
  1640. });
  1641. });
  1642. })
  1643. });
  1644. return waitForIdle().then(function() {
  1645. assert.deepEqual(
  1646. ['a.1', 'a.2', 'b.1', 'b.2', 'c.1', 'c.2', 'd.1', 'd.2'],
  1647. messages);
  1648. });
  1649. });
  1650. /** See https://github.com/SeleniumHQ/selenium/issues/363 */
  1651. it('testTasksScheduledInASeparateTurnOfTheEventLoopGetASeparateTaskQueue_2', function() {
  1652. scheduleAction('a', () => promise.delayed(10));
  1653. schedule('b');
  1654. setTimeout(() => schedule('c'), 0);
  1655. return waitForIdle().then(function() {
  1656. assertFlowHistory('a', 'c', 'b');
  1657. });
  1658. });
  1659. /** See https://github.com/SeleniumHQ/selenium/issues/363 */
  1660. it('testTasksScheduledInASeparateTurnOfTheEventLoopGetASeparateTaskQueue_2', function() {
  1661. scheduleAction('a', () => promise.delayed(10));
  1662. schedule('b');
  1663. schedule('c');
  1664. setTimeout(function() {
  1665. schedule('d');
  1666. scheduleAction('e', () => promise.delayed(10));
  1667. schedule('f');
  1668. }, 0);
  1669. return waitForIdle().then(function() {
  1670. assertFlowHistory('a', 'd', 'e', 'b', 'c', 'f');
  1671. });
  1672. });
  1673. /** See https://github.com/SeleniumHQ/selenium/issues/363 */
  1674. it('testCanSynchronizeTasksFromAdjacentTaskQueues', function() {
  1675. var task1 = scheduleAction('a', () => promise.delayed(10));
  1676. schedule('b');
  1677. setTimeout(function() {
  1678. scheduleAction('c', () => task1);
  1679. schedule('d');
  1680. }, 0);
  1681. return waitForIdle().then(function() {
  1682. assertFlowHistory('a', 'c', 'd', 'b');
  1683. });
  1684. });
  1685. describe('testCancellingAScheduledTask', function() {
  1686. it('1', function() {
  1687. var called = false;
  1688. var task1 = scheduleAction('a', () => called = true);
  1689. task1.cancel('no soup for you');
  1690. return waitForIdle().then(function() {
  1691. assert.ok(!called);
  1692. assertFlowHistory();
  1693. return task1.catch(function(e) {
  1694. assert.ok(e instanceof promise.CancellationError);
  1695. assert.equal('no soup for you', e.message);
  1696. });
  1697. });
  1698. });
  1699. it('2', function() {
  1700. schedule('a');
  1701. var called = false;
  1702. var task2 = scheduleAction('b', () => called = true);
  1703. schedule('c');
  1704. task2.cancel('no soup for you');
  1705. return waitForIdle().then(function() {
  1706. assert.ok(!called);
  1707. assertFlowHistory('a', 'c');
  1708. return task2.catch(function(e) {
  1709. assert.ok(e instanceof promise.CancellationError);
  1710. assert.equal('no soup for you', e.message);
  1711. });
  1712. });
  1713. });
  1714. it('3', function() {
  1715. var called = false;
  1716. var task = scheduleAction('a', () => called = true);
  1717. task.cancel(new StubError);
  1718. return waitForIdle().then(function() {
  1719. assert.ok(!called);
  1720. assertFlowHistory();
  1721. return task.catch(function(e) {
  1722. assert.ok(e instanceof promise.CancellationError);
  1723. });
  1724. });
  1725. });
  1726. it('4', function() {
  1727. var seen = [];
  1728. var task = scheduleAction('a', () => seen.push(1))
  1729. .then(() => seen.push(2))
  1730. .then(() => seen.push(3))
  1731. .then(() => seen.push(4))
  1732. .then(() => seen.push(5));
  1733. task.cancel(new StubError);
  1734. return waitForIdle().then(function() {
  1735. assert.deepEqual([], seen);
  1736. assertFlowHistory();
  1737. return task.catch(function(e) {
  1738. assert.ok(e instanceof promise.CancellationError);
  1739. });
  1740. });
  1741. });
  1742. it('fromWithinAnExecutingTask', function() {
  1743. var called = false;
  1744. var task;
  1745. scheduleAction('a', function() {
  1746. task.cancel('no soup for you');
  1747. });
  1748. task = scheduleAction('b', () => called = true);
  1749. schedule('c');
  1750. return waitForIdle().then(function() {
  1751. assert.ok(!called);
  1752. assertFlowHistory('a', 'c');
  1753. return task.catch(function(e) {
  1754. assert.ok(e instanceof promise.CancellationError);
  1755. assert.equal('no soup for you', e.message);
  1756. });
  1757. });
  1758. });
  1759. });
  1760. it('testCancellingAPendingTask', function() {
  1761. var order = [];
  1762. var unresolved = promise.defer();
  1763. var innerTask;
  1764. var outerTask = scheduleAction('a', function() {
  1765. order.push(1);
  1766. // Schedule a task that will never finish.
  1767. innerTask = scheduleAction('a.1', function() {
  1768. return unresolved.promise;
  1769. });
  1770. // Since the outerTask is cancelled below, innerTask should be cancelled
  1771. // with a DiscardedTaskError, which means its callbacks are silently
  1772. // dropped - so this should never execute.
  1773. innerTask.catch(function(e) {
  1774. order.push(2);
  1775. });
  1776. });
  1777. schedule('b');
  1778. outerTask.catch(function(e) {
  1779. order.push(3);
  1780. assert.ok(e instanceof promise.CancellationError);
  1781. assert.equal('no soup for you', e.message);
  1782. });
  1783. unresolved.promise.catch(function(e) {
  1784. order.push(4);
  1785. assert.ok(e instanceof promise.CancellationError);
  1786. });
  1787. return timeout(10).then(function() {
  1788. assert.deepEqual([1], order);
  1789. outerTask.cancel('no soup for you');
  1790. return waitForIdle();
  1791. }).then(function() {
  1792. assertFlowHistory('a', 'a.1', 'b');
  1793. assert.deepEqual([1, 3, 4], order);
  1794. });
  1795. });
  1796. it('testCancellingAPendingPromiseCallback', function() {
  1797. var called = false;
  1798. var root = promise.fulfilled();
  1799. root.then(function() {
  1800. cb2.cancel('no soup for you');
  1801. });
  1802. var cb2 = root.then(fail, fail); // These callbacks should never be called.
  1803. cb2.then(fail, function(e) {
  1804. called = true;
  1805. assert.ok(e instanceof promise.CancellationError);
  1806. assert.equal('no soup for you', e.message);
  1807. });
  1808. return waitForIdle().then(function() {
  1809. assert.ok(called);
  1810. });
  1811. });
  1812. describe('testResetFlow', function() {
  1813. it('1', function() {
  1814. var called = 0;
  1815. var task = flow.execute(() => called++);
  1816. task.finally(() => called++);
  1817. return new Promise(function(fulfill) {
  1818. flow.once('reset', fulfill);
  1819. flow.reset();
  1820. }).then(function() {
  1821. assert.equal(0, called);
  1822. return task;
  1823. }).then(fail, function(e) {
  1824. assert.ok(e instanceof promise.CancellationError);
  1825. assert.equal('ControlFlow was reset', e.message);
  1826. });
  1827. });
  1828. it('2', function() {
  1829. var called = 0;
  1830. var task1 = flow.execute(() => called++);
  1831. task1.finally(() => called++);
  1832. var task2 = flow.execute(() => called++);
  1833. task2.finally(() => called++);
  1834. var task3 = flow.execute(() => called++);
  1835. task3.finally(() => called++);
  1836. return new Promise(function(fulfill) {
  1837. flow.once('reset', fulfill);
  1838. flow.reset();
  1839. }).then(function() {
  1840. assert.equal(0, called);
  1841. });
  1842. });
  1843. });
  1844. describe('testPromiseFulfilledInsideTask', function() {
  1845. it('1', function() {
  1846. var order = [];
  1847. flow.execute(function() {
  1848. var d = promise.defer();
  1849. d.promise.then(() => order.push('a'));
  1850. d.promise.then(() => order.push('b'));
  1851. d.promise.then(() => order.push('c'));
  1852. d.fulfill();
  1853. flow.execute(() => order.push('d'));
  1854. }).then(() => order.push('fin'));
  1855. return waitForIdle().then(function() {
  1856. assert.deepEqual(['a', 'b', 'c', 'd', 'fin'], order);
  1857. });
  1858. });
  1859. it('2', function() {
  1860. var order = [];
  1861. flow.execute(function() {
  1862. flow.execute(() => order.push('a'));
  1863. flow.execute(() => order.push('b'));
  1864. var d = promise.defer();
  1865. d.promise.then(() => order.push('c'));
  1866. d.promise.then(() => order.push('d'));
  1867. d.fulfill();
  1868. flow.execute(() => order.push('e'));
  1869. }).then(() => order.push('fin'));
  1870. return waitForIdle().then(function() {
  1871. assert.deepEqual(['a', 'b', 'c', 'd', 'e', 'fin'], order);
  1872. });
  1873. });
  1874. it('3', function() {
  1875. var order = [];
  1876. var d = promise.defer();
  1877. d.promise.then(() => order.push('c'));
  1878. d.promise.then(() => order.push('d'));
  1879. flow.execute(function() {
  1880. flow.execute(() => order.push('a'));
  1881. flow.execute(() => order.push('b'));
  1882. d.promise.then(() => order.push('e'));
  1883. d.fulfill();
  1884. flow.execute(() => order.push('f'));
  1885. }).then(() => order.push('fin'));
  1886. return waitForIdle().then(function() {
  1887. assert.deepEqual(['c', 'd', 'a', 'b', 'e', 'f', 'fin'], order);
  1888. });
  1889. });
  1890. it('4', function() {
  1891. var order = [];
  1892. var d = promise.defer();
  1893. d.promise.then(() => order.push('a'));
  1894. d.promise.then(() => order.push('b'));
  1895. flow.execute(function() {
  1896. flow.execute(function() {
  1897. order.push('c');
  1898. flow.execute(() => order.push('d'));
  1899. d.promise.then(() => order.push('e'));
  1900. });
  1901. flow.execute(() => order.push('f'));
  1902. d.promise.then(() => order.push('g'));
  1903. d.fulfill();
  1904. flow.execute(() => order.push('h'));
  1905. }).then(() => order.push('fin'));
  1906. return waitForIdle().then(function() {
  1907. assert.deepEqual(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'fin'], order);
  1908. });
  1909. });
  1910. });
  1911. describe('testSettledPromiseCallbacksInsideATask', function() {
  1912. it('1', function() {
  1913. var order = [];
  1914. var p = promise.fulfilled();
  1915. flow.execute(function() {
  1916. flow.execute(() => order.push('a'));
  1917. p.then(() => order.push('b'));
  1918. flow.execute(() => order.push('c'));
  1919. p.then(() => order.push('d'));
  1920. }).then(() => order.push('fin'));
  1921. return waitForIdle().then(function() {
  1922. assert.deepEqual(['a', 'b', 'c', 'd', 'fin'], order);
  1923. });
  1924. });
  1925. it('2', function() {
  1926. var order = [];
  1927. flow.execute(function() {
  1928. flow.execute(() => order.push('a'))
  1929. .then( () => order.push('c'));
  1930. flow.execute(() => order.push('b'));
  1931. }).then(() => order.push('fin'));
  1932. return waitForIdle().then(function() {
  1933. assert.deepEqual(['a', 'c', 'b', 'fin'], order);
  1934. });
  1935. });
  1936. });
  1937. it('testTasksDoNotWaitForNewlyCreatedPromises', function() {
  1938. var order = [];
  1939. flow.execute(function() {
  1940. var d = promise.defer();
  1941. // This is a normal promise, not a task, so the task for this callback is
  1942. // considered volatile. Volatile tasks should be skipped when they reach
  1943. // the front of the task queue.
  1944. d.promise.then(() => order.push('a'));
  1945. flow.execute(() => order.push('b'));
  1946. flow.execute(function() {
  1947. flow.execute(() => order.push('c'));
  1948. d.promise.then(() => order.push('d'));
  1949. d.fulfill();
  1950. });
  1951. flow.execute(() => order.push('e'));
  1952. }).then(() => order.push('fin'));
  1953. return waitForIdle().then(function() {
  1954. assert.deepEqual(['b', 'a', 'c', 'd', 'e', 'fin'], order);
  1955. });
  1956. });
  1957. it('testCallbackDependenciesDoNotDeadlock', function() {
  1958. var order = [];
  1959. var root = promise.defer();
  1960. var dep = promise.fulfilled().then(function() {
  1961. order.push('a');
  1962. return root.promise.then(function() {
  1963. order.push('b');
  1964. });
  1965. });
  1966. // This callback depends on |dep|, which depends on another callback
  1967. // attached to |root| via a chain.
  1968. root.promise.then(function() {
  1969. order.push('c');
  1970. return dep.then(() => order.push('d'));
  1971. }).then(() => order.push('fin'));
  1972. setTimeout(() => root.fulfill(), 20);
  1973. return waitForIdle().then(function() {
  1974. assert.deepEqual(['a', 'b', 'c', 'd', 'fin'], order);
  1975. });
  1976. });
  1977. });
  1978. });