selenium-webdriver 3.0.0-beta-1 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/CHANGES.md +109 -0
  2. package/LICENSE +1 -1
  3. package/README.md +7 -6
  4. package/chrome.js +31 -128
  5. package/edge.js +13 -91
  6. package/example/chrome_android.js +18 -13
  7. package/example/chrome_mobile_emulation.js +19 -15
  8. package/example/google_search.js +11 -11
  9. package/example/google_search_generator.js +23 -18
  10. package/example/google_search_test.js +31 -17
  11. package/example/logging.js +9 -17
  12. package/example/parallel_flows.js +3 -0
  13. package/firefox/binary.js +17 -0
  14. package/firefox/index.js +198 -101
  15. package/firefox/profile.js +24 -3
  16. package/http/util.js +95 -59
  17. package/ie.js +6 -10
  18. package/index.js +636 -2
  19. package/lib/actions.js +18 -10
  20. package/lib/atoms/getAttribute.js +11 -0
  21. package/lib/atoms/isDisplayed.js +106 -0
  22. package/lib/firefox/amd64/libnoblur64.so +0 -0
  23. package/lib/firefox/i386/libnoblur.so +0 -0
  24. package/lib/firefox/webdriver.xpi +0 -0
  25. package/lib/http.js +159 -46
  26. package/lib/logging.js +7 -1
  27. package/lib/promise.js +602 -358
  28. package/lib/proxy.js +28 -0
  29. package/lib/session.js +1 -1
  30. package/lib/test/build.js +26 -28
  31. package/lib/test/data/formPage.html +1 -0
  32. package/lib/test/fileserver.js +12 -10
  33. package/lib/test/httpserver.js +4 -6
  34. package/lib/test/index.js +18 -11
  35. package/lib/test/promise.js +79 -0
  36. package/lib/webdriver.js +587 -479
  37. package/opera.js +12 -88
  38. package/package.json +13 -14
  39. package/phantomjs.js +7 -14
  40. package/remote/index.js +201 -30
  41. package/safari.js +62 -416
  42. package/test/actions_test.js +9 -11
  43. package/test/chrome/options_test.js +8 -8
  44. package/test/chrome/service_test.js +2 -2
  45. package/test/cookie_test.js +57 -57
  46. package/test/element_finding_test.js +201 -185
  47. package/test/execute_script_test.js +108 -111
  48. package/test/fingerprint_test.js +16 -11
  49. package/test/firefox/firefox_test.js +75 -49
  50. package/test/firefox/profile_test.js +1 -3
  51. package/test/http/util_test.js +21 -27
  52. package/test/io_test.js +2 -5
  53. package/test/lib/http_test.js +8 -6
  54. package/test/lib/promise_aplus_test.js +48 -44
  55. package/test/lib/promise_error_test.js +687 -611
  56. package/test/lib/promise_flow_test.js +1810 -1806
  57. package/test/lib/promise_generator_test.js +227 -225
  58. package/test/lib/promise_test.js +864 -835
  59. package/test/lib/until_test.js +1 -1
  60. package/test/lib/webdriver_test.js +520 -424
  61. package/test/logging_test.js +43 -45
  62. package/test/net/portprober_test.js +23 -24
  63. package/test/page_loading_test.js +84 -78
  64. package/test/phantomjs/execute_phantomjs_test.js +11 -25
  65. package/test/proxy_test.js +23 -23
  66. package/test/remote_test.js +22 -22
  67. package/test/safari_test.js +108 -0
  68. package/test/session_test.js +11 -10
  69. package/test/stale_element_test.js +18 -16
  70. package/test/tag_name_test.js +7 -5
  71. package/test/testing/assert_test.js +2 -3
  72. package/test/testing/index_test.js +163 -117
  73. package/test/upload_test.js +13 -13
  74. package/test/window_test.js +94 -70
  75. package/testing/index.js +176 -37
  76. package/builder.js +0 -553
  77. package/lib/safari/client.js +0 -56
@@ -27,6 +27,7 @@ const testutil = require('./testutil');
27
27
 
28
28
  const assert = require('assert');
29
29
  const promise = require('../../lib/promise');
30
+ const {enablePromiseManager} = require('../../lib/test/promise');
30
31
 
31
32
  const NativePromise = Promise;
32
33
  const StubError = testutil.StubError;
@@ -34,244 +35,178 @@ const throwStubError = testutil.throwStubError;
34
35
  const assertIsStubError = testutil.assertIsStubError;
35
36
 
36
37
  describe('promise error handling', function() {
37
- var flow, uncaughtExceptions;
38
-
39
- beforeEach(function setUp() {
40
- flow = promise.controlFlow();
41
- uncaughtExceptions = [];
42
- flow.on('uncaughtException', onUncaughtException);
43
- });
44
-
45
- afterEach(function tearDown() {
46
- return waitForIdle(flow).then(function() {
47
- assert.deepEqual(
48
- [], uncaughtExceptions, 'There were uncaught exceptions');
49
- flow.reset();
50
- });
51
- });
52
-
53
- function onUncaughtException(e) {
54
- uncaughtExceptions.push(e);
55
- }
56
-
57
- function waitForAbort(opt_flow, opt_n) {
58
- var n = opt_n || 1;
59
- var theFlow = opt_flow || flow;
60
- theFlow.removeAllListeners(
61
- promise.ControlFlow.EventType.UNCAUGHT_EXCEPTION);
62
- return new NativePromise(function(fulfill, reject) {
63
- theFlow.once('idle', function() {
64
- reject(Error('expected flow to report an unhandled error'));
65
- });
66
-
67
- var errors = [];
68
- theFlow.on('uncaughtException', onError);
69
- function onError(e) {
70
- errors.push(e);
71
- if (errors.length === n) {
72
- theFlow.removeListener('uncaughtException', onError);
73
- fulfill(n === 1 ? errors[0] : errors);
74
- }
75
- }
76
- });
77
- }
78
-
79
- function waitForIdle(opt_flow) {
80
- var theFlow = opt_flow || flow;
81
- return new NativePromise(function(fulfill, reject) {
82
- if (theFlow.isIdle()) {
83
- fulfill();
84
- return;
38
+ enablePromiseManager(() => {
39
+ var flow, uncaughtExceptions;
40
+
41
+ beforeEach(function setUp() {
42
+ if (promise.USE_PROMISE_MANAGER) {
43
+ flow = promise.controlFlow();
44
+ uncaughtExceptions = [];
45
+ flow.on('uncaughtException', onUncaughtException);
85
46
  }
86
- theFlow.once('idle', fulfill);
87
- theFlow.once('uncaughtException', reject);
88
- });
89
- }
90
-
91
- it('testRejectedPromiseTriggersErrorCallback', function() {
92
- return promise.rejected(new StubError).
93
- then(assert.fail, assertIsStubError);
94
- });
95
-
96
- describe('callback throws trigger subsequent error callback', function() {
97
- it('fulfilled promise', function() {
98
- return promise.fulfilled().
99
- then(throwStubError).
100
- then(assert.fail, assertIsStubError);
101
- });
102
-
103
- it('rejected promise', function() {
104
- var e = Error('not the droids you are looking for');
105
- return promise.rejected(e).
106
- then(assert.fail, throwStubError).
107
- then(assert.fail, assertIsStubError);
108
- });
109
- });
110
-
111
- describe('callback returns rejected promise triggers subsequent errback', function() {
112
- it('from fulfilled callback', function() {
113
- return promise.fulfilled().then(function() {
114
- return promise.rejected(new StubError);
115
- }).then(assert.fail, assertIsStubError);
116
47
  });
117
48
 
118
- it('from rejected callback', function() {
119
- var e = Error('not the droids you are looking for');
120
- return promise.rejected(e).
121
- then(assert.fail, function() {
122
- return promise.rejected(new StubError);
123
- }).
124
- then(assert.fail, assertIsStubError);
49
+ afterEach(function tearDown() {
50
+ if (promise.USE_PROMISE_MANAGER) {
51
+ return waitForIdle(flow).then(function() {
52
+ assert.deepEqual(
53
+ [], uncaughtExceptions, 'There were uncaught exceptions');
54
+ flow.reset();
55
+ });
56
+ }
125
57
  });
126
- });
127
58
 
128
- it('testReportsUnhandledRejectionsThroughTheControlFlow', function() {
129
- promise.rejected(new StubError);
130
- return waitForAbort().then(assertIsStubError);
131
- });
132
-
133
- describe('multiple unhandled rejections outside a task', function() {
134
- it('are reported in order they occurred', function() {
135
- var e1 = Error('error 1');
136
- var e2 = Error('error 2');
59
+ function onUncaughtException(e) {
60
+ uncaughtExceptions.push(e);
61
+ }
137
62
 
138
- promise.rejected(e1);
139
- promise.rejected(e2);
63
+ function waitForAbort(opt_flow, opt_n) {
64
+ var n = opt_n || 1;
65
+ var theFlow = opt_flow || flow;
66
+ theFlow.removeAllListeners(
67
+ promise.ControlFlow.EventType.UNCAUGHT_EXCEPTION);
68
+ return new NativePromise(function(fulfill, reject) {
69
+ theFlow.once('idle', function() {
70
+ reject(Error('expected flow to report an unhandled error'));
71
+ });
140
72
 
141
- return waitForAbort(flow).then(function(error) {
142
- assert.ok(
143
- error instanceof promise.MultipleUnhandledRejectionError);
144
- // TODO: switch to Array.from when we drop node 0.12.x
145
73
  var errors = [];
146
- for (var e of error.errors) {
74
+ theFlow.on('uncaughtException', onError);
75
+ function onError(e) {
147
76
  errors.push(e);
77
+ if (errors.length === n) {
78
+ theFlow.removeListener('uncaughtException', onError);
79
+ fulfill(n === 1 ? errors[0] : errors);
80
+ }
148
81
  }
149
- assert.deepEqual([e1, e2], errors);
150
82
  });
151
- });
152
- });
153
-
154
- describe('does not report unhandled rejection when', function() {
155
- it('handler added before next tick', function() {
156
- promise.rejected(new StubError).then(assert.fail, assertIsStubError);
157
- return waitForIdle();
158
- });
83
+ }
159
84
 
160
- it('added async but before next tick', function() {
161
- var called = false;
85
+ function waitForIdle(opt_flow) {
86
+ var theFlow = opt_flow || flow;
162
87
  return new NativePromise(function(fulfill, reject) {
163
- var aPromise;
164
- NativePromise.resolve().then(function() {
165
- aPromise.then(assert.fail, function(e) {
166
- called = true;
167
- assertIsStubError(e);
168
- });
169
- waitForIdle().then(fulfill, reject);
170
- });
171
- aPromise = promise.rejected(new StubError);
172
- }).then(function() {
173
- assert.ok(called);
174
- })
88
+ if (theFlow.isIdle()) {
89
+ fulfill();
90
+ return;
91
+ }
92
+ theFlow.once('idle', fulfill);
93
+ theFlow.once('uncaughtException', reject);
94
+ });
95
+ }
96
+
97
+ it('testRejectedPromiseTriggersErrorCallback', function() {
98
+ return promise.rejected(new StubError).
99
+ then(assert.fail, assertIsStubError);
175
100
  });
176
- });
177
101
 
178
- it('testTaskThrows', function() {
179
- return flow.execute(throwStubError).then(assert.fail, assertIsStubError);
180
- });
102
+ describe('callback throws trigger subsequent error callback', function() {
103
+ it('fulfilled promise', function() {
104
+ return promise.fulfilled().
105
+ then(throwStubError).
106
+ then(assert.fail, assertIsStubError);
107
+ });
181
108
 
182
- it('testTaskReturnsRejectedPromise', function() {
183
- return flow.execute(function() {
184
- return promise.rejected(new StubError)
185
- }).then(assert.fail, assertIsStubError);
186
- });
109
+ it('rejected promise', function() {
110
+ var e = Error('not the droids you are looking for');
111
+ return promise.rejected(e).
112
+ then(assert.fail, throwStubError).
113
+ then(assert.fail, assertIsStubError);
114
+ });
115
+ });
187
116
 
188
- it('testTaskHasUnhandledRejection', function() {
189
- return flow.execute(function() {
190
- promise.rejected(new StubError)
191
- }).then(assert.fail, assertIsStubError);
192
- });
117
+ describe('callback returns rejected promise triggers subsequent errback', function() {
118
+ it('from fulfilled callback', function() {
119
+ return promise.fulfilled().then(function() {
120
+ return promise.rejected(new StubError);
121
+ }).then(assert.fail, assertIsStubError);
122
+ });
193
123
 
194
- it('testTaskfails_returnedPromiseIsUnhandled', function() {
195
- flow.execute(throwStubError);
196
- return waitForAbort().then(assertIsStubError);
197
- });
124
+ it('from rejected callback', function() {
125
+ var e = Error('not the droids you are looking for');
126
+ return promise.rejected(e).
127
+ then(assert.fail, function() {
128
+ return promise.rejected(new StubError);
129
+ }).
130
+ then(assert.fail, assertIsStubError);
131
+ });
132
+ });
198
133
 
199
- it('testTaskHasUnhandledRejection_cancelsRemainingSubTasks', function() {
200
- var seen = [];
201
- flow.execute(function() {
134
+ it('testReportsUnhandledRejectionsThroughTheControlFlow', function() {
202
135
  promise.rejected(new StubError);
203
-
204
- flow.execute(() => seen.push('a'))
205
- .then(() => seen.push('b'), (e) => seen.push(e));
206
- flow.execute(() => seen.push('c'))
207
- .then(() => seen.push('b'), (e) => seen.push(e));
136
+ return waitForAbort().then(assertIsStubError);
208
137
  });
209
138
 
210
- return waitForAbort()
211
- .then(assertIsStubError)
212
- .then(() => assert.deepEqual([], seen));
213
- });
139
+ describe('multiple unhandled rejections outside a task', function() {
140
+ it('are reported in order they occurred', function() {
141
+ var e1 = Error('error 1');
142
+ var e2 = Error('error 2');
214
143
 
215
- describe('nested task failures', function() {
216
- it('returns up to paren', function() {
217
- return flow.execute(function() {
218
- return flow.execute(function() {
219
- return flow.execute(throwStubError);
220
- });
221
- }).then(assert.fail, assertIsStubError);
222
- });
144
+ promise.rejected(e1);
145
+ promise.rejected(e2);
223
146
 
224
- it('task throws; uncaught error bubbles up', function() {
225
- flow.execute(function() {
226
- flow.execute(function() {
227
- flow.execute(throwStubError);
147
+ return waitForAbort(flow).then(function(error) {
148
+ assert.ok(
149
+ error instanceof promise.MultipleUnhandledRejectionError);
150
+ // TODO: switch to Array.from when we drop node 0.12.x
151
+ var errors = [];
152
+ for (var e of error.errors) {
153
+ errors.push(e);
154
+ }
155
+ assert.deepEqual([e1, e2], errors);
228
156
  });
229
157
  });
230
- return waitForAbort().then(assertIsStubError);
231
158
  });
232
159
 
233
- it('task throws; uncaught error bubbles up; is caught at root', function() {
234
- flow.execute(function() {
235
- flow.execute(function() {
236
- flow.execute(throwStubError);
237
- });
238
- }).then(assert.fail, assertIsStubError);
239
- return waitForIdle();
240
- });
160
+ describe('does not report unhandled rejection when', function() {
161
+ it('handler added before next tick', function() {
162
+ promise.rejected(new StubError).then(assert.fail, assertIsStubError);
163
+ return waitForIdle();
164
+ });
241
165
 
242
- it('unhandled rejection bubbles up', function() {
243
- flow.execute(function() {
244
- flow.execute(function() {
245
- flow.execute(function() {
246
- promise.rejected(new StubError);
166
+ it('added async but before next tick', function() {
167
+ var called = false;
168
+ return new NativePromise(function(fulfill, reject) {
169
+ var aPromise;
170
+ NativePromise.resolve().then(function() {
171
+ aPromise.then(assert.fail, function(e) {
172
+ called = true;
173
+ assertIsStubError(e);
174
+ });
175
+ waitForIdle().then(fulfill, reject);
247
176
  });
248
- });
177
+ aPromise = promise.rejected(new StubError);
178
+ }).then(function() {
179
+ assert.ok(called);
180
+ })
249
181
  });
250
- return waitForAbort().then(assertIsStubError);
251
182
  });
252
183
 
253
- it('unhandled rejection bubbles up; caught at root', function() {
254
- flow.execute(function() {
255
- flow.execute(function() {
256
- promise.rejected(new StubError);
257
- });
184
+ it('testTaskThrows', function() {
185
+ return flow.execute(throwStubError).then(assert.fail, assertIsStubError);
186
+ });
187
+
188
+ it('testTaskReturnsRejectedPromise', function() {
189
+ return flow.execute(function() {
190
+ return promise.rejected(new StubError)
258
191
  }).then(assert.fail, assertIsStubError);
259
- return waitForIdle();
260
192
  });
261
193
 
262
- it('mixtureof hanging and free subtasks', function() {
263
- flow.execute(function() {
264
- return flow.execute(function() {
265
- flow.execute(throwStubError);
266
- });
267
- });
194
+ it('testTaskHasUnhandledRejection', function() {
195
+ return flow.execute(function() {
196
+ promise.rejected(new StubError)
197
+ }).then(assert.fail, assertIsStubError);
198
+ });
199
+
200
+ it('testTaskfails_returnedPromiseIsUnhandled', function() {
201
+ flow.execute(throwStubError);
268
202
  return waitForAbort().then(assertIsStubError);
269
203
  });
270
204
 
271
- it('cancels remaining tasks', function() {
205
+ it('testTaskHasUnhandledRejection_cancelsRemainingSubTasks', function() {
272
206
  var seen = [];
273
207
  flow.execute(function() {
274
- flow.execute(() => promise.rejected(new StubError));
208
+ promise.rejected(new StubError);
209
+
275
210
  flow.execute(() => seen.push('a'))
276
211
  .then(() => seen.push('b'), (e) => seen.push(e));
277
212
  flow.execute(() => seen.push('c'))
@@ -282,526 +217,667 @@ describe('promise error handling', function() {
282
217
  .then(assertIsStubError)
283
218
  .then(() => assert.deepEqual([], seen));
284
219
  });
285
- });
286
-
287
- it('testTaskReturnsPromiseLikeObjectThatInvokesErrback', function() {
288
- return flow.execute(function() {
289
- return {
290
- 'then': function(_, errback) {
291
- errback('abc123');
292
- }
293
- };
294
- }).then(assert.fail, function(value) {
295
- assert.equal('abc123', value);
296
- });
297
- });
298
220
 
299
- describe('ControlFlow#wait();', function() {
300
- describe('condition throws;', function() {
301
- it('failure is caught', function() {
302
- return flow.wait(throwStubError, 50).then(assert.fail, assertIsStubError);
303
- });
304
-
305
- it('failure is not caught', function() {
306
- flow.wait(throwStubError, 50);
307
- return waitForAbort().then(assertIsStubError);
308
- });
309
- });
310
-
311
- describe('condition returns promise', function() {
312
- it('failure is caught', function() {
313
- return flow.wait(function() {
314
- return promise.rejected(new StubError);
315
- }, 50).then(assert.fail, assertIsStubError);
221
+ describe('nested task failures', function() {
222
+ it('returns up to paren', function() {
223
+ return flow.execute(function() {
224
+ return flow.execute(function() {
225
+ return flow.execute(throwStubError);
226
+ });
227
+ }).then(assert.fail, assertIsStubError);
316
228
  });
317
229
 
318
- it('failure is not caught', function() {
319
- flow.wait(function() {
320
- return promise.rejected(new StubError);
321
- }, 50);
230
+ it('task throws; uncaught error bubbles up', function() {
231
+ flow.execute(function() {
232
+ flow.execute(function() {
233
+ flow.execute(throwStubError);
234
+ });
235
+ });
322
236
  return waitForAbort().then(assertIsStubError);
323
237
  });
324
- });
325
238
 
326
- describe('condition has unhandled promise rejection', function() {
327
- it('failure is caught', function() {
328
- return flow.wait(function() {
329
- promise.rejected(new StubError);
330
- }, 50).then(assert.fail, assertIsStubError);
239
+ it('task throws; uncaught error bubbles up; is caught at root', function() {
240
+ flow.execute(function() {
241
+ flow.execute(function() {
242
+ flow.execute(throwStubError);
243
+ });
244
+ }).then(assert.fail, assertIsStubError);
245
+ return waitForIdle();
331
246
  });
332
247
 
333
- it('failure is not caught', function() {
334
- flow.wait(function() {
335
- promise.rejected(new StubError);
336
- }, 50);
248
+ it('unhandled rejection bubbles up', function() {
249
+ flow.execute(function() {
250
+ flow.execute(function() {
251
+ flow.execute(function() {
252
+ promise.rejected(new StubError);
253
+ });
254
+ });
255
+ });
337
256
  return waitForAbort().then(assertIsStubError);
338
257
  });
339
- });
340
258
 
341
- describe('condition has subtask failure', function() {
342
- it('failure is caught', function() {
343
- return flow.wait(function() {
259
+ it('unhandled rejection bubbles up; caught at root', function() {
260
+ flow.execute(function() {
344
261
  flow.execute(function() {
345
- flow.execute(throwStubError);
262
+ promise.rejected(new StubError);
346
263
  });
347
- }, 50).then(assert.fail, assertIsStubError);
264
+ }).then(assert.fail, assertIsStubError);
265
+ return waitForIdle();
348
266
  });
349
267
 
350
- it('failure is not caught', function() {
351
- flow.wait(function() {
352
- flow.execute(function() {
268
+ it('mixtureof hanging and free subtasks', function() {
269
+ flow.execute(function() {
270
+ return flow.execute(function() {
353
271
  flow.execute(throwStubError);
354
272
  });
355
- }, 50);
273
+ });
356
274
  return waitForAbort().then(assertIsStubError);
357
275
  });
358
- });
359
- });
360
276
 
361
- describe('errback throws a new error', function() {
362
- it('start with normal promise', function() {
363
- var error = Error('an error');
364
- return promise.rejected(error).
365
- catch(function(e) {
366
- assert.equal(e, error);
367
- throw new StubError;
368
- }).
369
- catch(assertIsStubError);
277
+ it('cancels remaining tasks', function() {
278
+ var seen = [];
279
+ flow.execute(function() {
280
+ flow.execute(() => promise.rejected(new StubError));
281
+ flow.execute(() => seen.push('a'))
282
+ .then(() => seen.push('b'), (e) => seen.push(e));
283
+ flow.execute(() => seen.push('c'))
284
+ .then(() => seen.push('b'), (e) => seen.push(e));
285
+ });
286
+
287
+ return waitForAbort()
288
+ .then(assertIsStubError)
289
+ .then(() => assert.deepEqual([], seen));
290
+ });
370
291
  });
371
292
 
372
- it('start with task result', function() {
373
- var error = Error('an error');
293
+ it('testTaskReturnsPromiseLikeObjectThatInvokesErrback', function() {
374
294
  return flow.execute(function() {
375
- throw error;
376
- }).
377
- catch(function(e) {
378
- assert.equal(e, error);
379
- throw new StubError;
380
- }).
381
- catch(assertIsStubError);
295
+ return {
296
+ 'then': function(_, errback) {
297
+ errback('abc123');
298
+ }
299
+ };
300
+ }).then(assert.fail, function(value) {
301
+ assert.equal('abc123', value);
302
+ });
382
303
  });
383
304
 
384
- it('start with normal promise; uncaught error', function() {
385
- var error = Error('an error');
386
- promise.rejected(error).
387
- catch(function(e) {
388
- assert.equal(e, error);
389
- throw new StubError;
390
- });
391
- return waitForAbort().then(assertIsStubError);
392
- });
305
+ describe('ControlFlow#wait();', function() {
306
+ describe('condition throws;', function() {
307
+ it('failure is caught', function() {
308
+ return flow.wait(throwStubError, 50).then(assert.fail, assertIsStubError);
309
+ });
393
310
 
394
- it('start with task result; uncaught error', function() {
395
- var error = Error('an error');
396
- flow.execute(function() {
397
- throw error;
398
- }).
399
- catch(function(e) {
400
- assert.equal(e, error);
401
- throw new StubError;
311
+ it('failure is not caught', function() {
312
+ flow.wait(throwStubError, 50);
313
+ return waitForAbort().then(assertIsStubError);
314
+ });
315
+ });
316
+
317
+ describe('condition returns promise', function() {
318
+ it('failure is caught', function() {
319
+ return flow.wait(function() {
320
+ return promise.rejected(new StubError);
321
+ }, 50).then(assert.fail, assertIsStubError);
322
+ });
323
+
324
+ it('failure is not caught', function() {
325
+ flow.wait(function() {
326
+ return promise.rejected(new StubError);
327
+ }, 50);
328
+ return waitForAbort().then(assertIsStubError);
329
+ });
330
+ });
331
+
332
+ describe('condition has unhandled promise rejection', function() {
333
+ it('failure is caught', function() {
334
+ return flow.wait(function() {
335
+ promise.rejected(new StubError);
336
+ }, 50).then(assert.fail, assertIsStubError);
337
+ });
338
+
339
+ it('failure is not caught', function() {
340
+ flow.wait(function() {
341
+ promise.rejected(new StubError);
342
+ }, 50);
343
+ return waitForAbort().then(assertIsStubError);
344
+ });
345
+ });
346
+
347
+ describe('condition has subtask failure', function() {
348
+ it('failure is caught', function() {
349
+ return flow.wait(function() {
350
+ flow.execute(function() {
351
+ flow.execute(throwStubError);
352
+ });
353
+ }, 50).then(assert.fail, assertIsStubError);
354
+ });
355
+
356
+ it('failure is not caught', function() {
357
+ flow.wait(function() {
358
+ flow.execute(function() {
359
+ flow.execute(throwStubError);
360
+ });
361
+ }, 50);
362
+ return waitForAbort().then(assertIsStubError);
363
+ });
402
364
  });
403
- return waitForAbort().then(assertIsStubError);
404
365
  });
405
- });
406
366
 
407
- it('thrownPromiseCausesCallbackRejection', function() {
408
- let p = promise.fulfilled(1234);
409
- return promise.fulfilled().then(function() {
410
- throw p;
411
- }).then(assert.fail, function(value) {
412
- assert.strictEqual(p, value);
367
+ describe('errback throws a new error', function() {
368
+ it('start with normal promise', function() {
369
+ var error = Error('an error');
370
+ return promise.rejected(error).
371
+ catch(function(e) {
372
+ assert.equal(e, error);
373
+ throw new StubError;
374
+ }).
375
+ catch(assertIsStubError);
376
+ });
377
+
378
+ it('start with task result', function() {
379
+ var error = Error('an error');
380
+ return flow.execute(function() {
381
+ throw error;
382
+ }).
383
+ catch(function(e) {
384
+ assert.equal(e, error);
385
+ throw new StubError;
386
+ }).
387
+ catch(assertIsStubError);
388
+ });
389
+
390
+ it('start with normal promise; uncaught error', function() {
391
+ var error = Error('an error');
392
+ promise.rejected(error).
393
+ catch(function(e) {
394
+ assert.equal(e, error);
395
+ throw new StubError;
396
+ });
397
+ return waitForAbort().then(assertIsStubError);
398
+ });
399
+
400
+ it('start with task result; uncaught error', function() {
401
+ var error = Error('an error');
402
+ flow.execute(function() {
403
+ throw error;
404
+ }).
405
+ catch(function(e) {
406
+ assert.equal(e, error);
407
+ throw new StubError;
408
+ });
409
+ return waitForAbort().then(assertIsStubError);
410
+ });
413
411
  });
414
- });
415
412
 
416
- describe('task throws promise', function() {
417
- it('promise was fulfilled', function() {
418
- var toThrow = promise.fulfilled(1234);
419
- flow.execute(function() {
420
- throw toThrow;
413
+ it('thrownPromiseCausesCallbackRejection', function() {
414
+ let p = promise.fulfilled(1234);
415
+ return promise.fulfilled().then(function() {
416
+ throw p;
421
417
  }).then(assert.fail, function(value) {
422
- assert.equal(toThrow, value);
423
- return toThrow;
424
- }).then(function(value) {
425
- assert.equal(1234, value);
418
+ assert.strictEqual(p, value);
426
419
  });
427
- return waitForIdle();
428
420
  });
429
421
 
430
- it('promise was rejected', function() {
431
- var toThrow = promise.rejected(new StubError);
432
- toThrow.catch(function() {}); // For tearDown.
433
- flow.execute(function() {
434
- throw toThrow;
435
- }).then(assert.fail, function(e) {
436
- assert.equal(toThrow, e);
437
- return e;
438
- }).then(assert.fail, assertIsStubError);
439
- return waitForIdle();
422
+ describe('task throws promise', function() {
423
+ it('promise was fulfilled', function() {
424
+ var toThrow = promise.fulfilled(1234);
425
+ flow.execute(function() {
426
+ throw toThrow;
427
+ }).then(assert.fail, function(value) {
428
+ assert.equal(toThrow, value);
429
+ return toThrow;
430
+ }).then(function(value) {
431
+ assert.equal(1234, value);
432
+ });
433
+ return waitForIdle();
434
+ });
435
+
436
+ it('promise was rejected', function() {
437
+ var toThrow = promise.rejected(new StubError);
438
+ toThrow.catch(function() {}); // For tearDown.
439
+ flow.execute(function() {
440
+ throw toThrow;
441
+ }).then(assert.fail, function(e) {
442
+ assert.equal(toThrow, e);
443
+ return e;
444
+ }).then(assert.fail, assertIsStubError);
445
+ return waitForIdle();
446
+ });
440
447
  });
441
- });
442
448
 
443
- it('testFailsTaskIfThereIsAnUnhandledErrorWhileWaitingOnTaskResult', function() {
444
- var d = promise.defer();
445
- flow.execute(function() {
446
- promise.rejected(new StubError);
447
- return d.promise;
448
- }).then(assert.fail, assertIsStubError);
449
+ it('testFailsTaskIfThereIsAnUnhandledErrorWhileWaitingOnTaskResult', function() {
450
+ var d = promise.defer();
451
+ flow.execute(function() {
452
+ promise.rejected(new StubError);
453
+ return d.promise;
454
+ }).then(assert.fail, assertIsStubError);
449
455
 
450
- return waitForIdle().then(function() {
451
- return d.promise;
452
- }).then(assert.fail, function(e) {
453
- assert.equal('CancellationError: StubError', e.toString());
456
+ return waitForIdle().then(function() {
457
+ return d.promise;
458
+ }).then(assert.fail, function(e) {
459
+ assert.equal('CancellationError: StubError', e.toString());
460
+ });
454
461
  });
455
- });
456
462
 
457
- it('testFailsParentTaskIfAsyncScheduledTaskFails', function() {
458
- var d = promise.defer();
459
- flow.execute(function() {
460
- flow.execute(throwStubError);
461
- return d.promise;
462
- }).then(assert.fail, assertIsStubError);
463
+ it('testFailsParentTaskIfAsyncScheduledTaskFails', function() {
464
+ var d = promise.defer();
465
+ flow.execute(function() {
466
+ flow.execute(throwStubError);
467
+ return d.promise;
468
+ }).then(assert.fail, assertIsStubError);
463
469
 
464
- return waitForIdle().then(function() {
465
- return d.promise;
466
- }).then(assert.fail, function(e) {
467
- assert.equal('CancellationError: StubError', e.toString());
470
+ return waitForIdle().then(function() {
471
+ return d.promise;
472
+ }).then(assert.fail, function(e) {
473
+ assert.equal('CancellationError: StubError', e.toString());
474
+ });
468
475
  });
469
- });
470
476
 
471
- describe('long stack traces', function() {
472
- afterEach(() => promise.LONG_STACK_TRACES = false);
477
+ describe('long stack traces', function() {
478
+ afterEach(() => promise.LONG_STACK_TRACES = false);
473
479
 
474
- it('always includes task stacks in failures', function() {
475
- promise.LONG_STACK_TRACES = false;
476
- flow.execute(function() {
480
+ it('always includes task stacks in failures', function() {
481
+ promise.LONG_STACK_TRACES = false;
477
482
  flow.execute(function() {
478
- flow.execute(throwStubError, 'throw error');
479
- }, 'two');
480
- }, 'three').
481
- then(assert.fail, function(e) {
482
- assertIsStubError(e);
483
- if (typeof e.stack !== 'string') {
484
- return;
485
- }
486
- var messages = e.stack.split(/\n/).filter(function(line, index) {
487
- return /^From: /.test(line);
483
+ flow.execute(function() {
484
+ flow.execute(throwStubError, 'throw error');
485
+ }, 'two');
486
+ }, 'three').
487
+ then(assert.fail, function(e) {
488
+ assertIsStubError(e);
489
+ if (typeof e.stack !== 'string') {
490
+ return;
491
+ }
492
+ var messages = e.stack.split(/\n/).filter(function(line, index) {
493
+ return /^From: /.test(line);
494
+ });
495
+ assert.deepEqual([
496
+ 'From: Task: throw error',
497
+ 'From: Task: two',
498
+ 'From: Task: three'
499
+ ], messages);
488
500
  });
489
- assert.deepEqual([
490
- 'From: Task: throw error',
491
- 'From: Task: two',
492
- 'From: Task: three'
493
- ], messages);
501
+ return waitForIdle();
502
+ });
503
+
504
+ it('does not include completed tasks', function () {
505
+ flow.execute(function() {}, 'succeeds');
506
+ flow.execute(throwStubError, 'kaboom').then(assert.fail, function(e) {
507
+ assertIsStubError(e);
508
+ if (typeof e.stack !== 'string') {
509
+ return;
510
+ }
511
+ var messages = e.stack.split(/\n/).filter(function(line, index) {
512
+ return /^From: /.test(line);
513
+ });
514
+ assert.deepEqual(['From: Task: kaboom'], messages);
515
+ });
516
+ return waitForIdle();
494
517
  });
495
- return waitForIdle();
496
- });
497
518
 
498
- it('does not include completed tasks', function () {
499
- flow.execute(function() {}, 'succeeds');
500
- flow.execute(throwStubError, 'kaboom').then(assert.fail, function(e) {
501
- assertIsStubError(e);
502
- if (typeof e.stack !== 'string') {
503
- return;
504
- }
505
- var messages = e.stack.split(/\n/).filter(function(line, index) {
506
- return /^From: /.test(line);
519
+ it('does not include promise chain when disabled', function() {
520
+ promise.LONG_STACK_TRACES = false;
521
+ flow.execute(function() {
522
+ flow.execute(function() {
523
+ return promise.fulfilled().
524
+ then(function() {}).
525
+ then(function() {}).
526
+ then(throwStubError);
527
+ }, 'eventually assert.fails');
528
+ }, 'start').
529
+ then(assert.fail, function(e) {
530
+ assertIsStubError(e);
531
+ if (typeof e.stack !== 'string') {
532
+ return;
533
+ }
534
+ var messages = e.stack.split(/\n/).filter(function(line, index) {
535
+ return /^From: /.test(line);
536
+ });
537
+ assert.deepEqual([
538
+ 'From: Task: eventually assert.fails',
539
+ 'From: Task: start'
540
+ ], messages);
507
541
  });
508
- assert.deepEqual(['From: Task: kaboom'], messages);
542
+ return waitForIdle();
509
543
  });
510
- return waitForIdle();
511
- });
512
544
 
513
- it('does not include promise chain when disabled', function() {
514
- promise.LONG_STACK_TRACES = false;
515
- flow.execute(function() {
545
+ it('includes promise chain when enabled', function() {
546
+ promise.LONG_STACK_TRACES = true;
516
547
  flow.execute(function() {
517
- return promise.fulfilled().
518
- then(function() {}).
519
- then(function() {}).
520
- then(throwStubError);
521
- }, 'eventually assert.fails');
522
- }, 'start').
523
- then(assert.fail, function(e) {
524
- assertIsStubError(e);
525
- if (typeof e.stack !== 'string') {
526
- return;
527
- }
528
- var messages = e.stack.split(/\n/).filter(function(line, index) {
529
- return /^From: /.test(line);
548
+ flow.execute(function() {
549
+ return promise.fulfilled().
550
+ then(function() {}).
551
+ then(function() {}).
552
+ then(throwStubError);
553
+ }, 'eventually assert.fails');
554
+ }, 'start').
555
+ then(assert.fail, function(e) {
556
+ assertIsStubError(e);
557
+ if (typeof e.stack !== 'string') {
558
+ return;
559
+ }
560
+ var messages = e.stack.split(/\n/).filter(function(line, index) {
561
+ return /^From: /.test(line);
562
+ });
563
+ assert.deepEqual([
564
+ 'From: Promise: then',
565
+ 'From: Task: eventually assert.fails',
566
+ 'From: Task: start'
567
+ ], messages);
530
568
  });
531
- assert.deepEqual([
532
- 'From: Task: eventually assert.fails',
533
- 'From: Task: start'
534
- ], messages);
569
+ return waitForIdle();
535
570
  });
536
- return waitForIdle();
537
571
  });
538
572
 
539
- it('includes promise chain when enabled', function() {
540
- promise.LONG_STACK_TRACES = true;
541
- flow.execute(function() {
542
- flow.execute(function() {
543
- return promise.fulfilled().
544
- then(function() {}).
545
- then(function() {}).
546
- then(throwStubError);
547
- }, 'eventually assert.fails');
548
- }, 'start').
549
- then(assert.fail, function(e) {
550
- assertIsStubError(e);
551
- if (typeof e.stack !== 'string') {
552
- return;
553
- }
554
- var messages = e.stack.split(/\n/).filter(function(line, index) {
555
- return /^From: /.test(line);
573
+ describe('frame cancels remaining tasks', function() {
574
+ it('on unhandled task failure', function() {
575
+ var run = false;
576
+ return flow.execute(function() {
577
+ flow.execute(throwStubError);
578
+ flow.execute(function() { run = true; });
579
+ }).then(assert.fail, function(e) {
580
+ assertIsStubError(e);
581
+ assert.ok(!run);
556
582
  });
557
- assert.deepEqual([
558
- 'From: Promise: then',
559
- 'From: Task: eventually assert.fails',
560
- 'From: Task: start'
561
- ], messages);
562
583
  });
563
- return waitForIdle();
564
- });
565
- });
566
584
 
567
- it('testFrameCancelsRemainingTasks_onUnhandledTaskFailure', function() {
568
- var run = false;
569
- return flow.execute(function() {
570
- flow.execute(throwStubError);
571
- flow.execute(function() { run = true; });
572
- }).then(assert.fail, function(e) {
573
- assertIsStubError(e);
574
- assert.ok(!run);
575
- });
576
- });
585
+ it('on unhandled promise rejection', function() {
586
+ var run = false;
587
+ return flow.execute(function() {
588
+ promise.rejected(new StubError);
589
+ flow.execute(function() { run = true; });
590
+ }).then(assert.fail, function(e) {
591
+ assertIsStubError(e);
592
+ assert.ok(!run);
593
+ });
594
+ });
577
595
 
578
- it('testFrameCancelsRemainingTasks_onUnhandledPromiseRejection', function() {
579
- var run = false;
580
- return flow.execute(function() {
581
- promise.rejected(new StubError);
582
- flow.execute(function() { run = true; });
583
- }).then(assert.fail, function(e) {
584
- assertIsStubError(e);
585
- assert.ok(!run);
586
- });
587
- });
596
+ it('if task throws', function() {
597
+ var run = false;
598
+ return flow.execute(function() {
599
+ flow.execute(function() { run = true; });
600
+ throw new StubError;
601
+ }).then(assert.fail, function(e) {
602
+ assertIsStubError(e);
603
+ assert.ok(!run);
604
+ });
605
+ });
588
606
 
589
- it('testRegisteredTaskCallbacksAreDroppedWhenTaskIsCancelled_return', function() {
590
- var seen = [];
591
- return flow.execute(function() {
592
- flow.execute(throwStubError);
607
+ describe('task callbacks scheduled in another frame', function() {
608
+ flow = promise.controlFlow();
609
+ function noop() {}
593
610
 
594
- flow.execute(function() {
595
- seen.push(1);
596
- }).then(function() {
597
- seen.push(2);
598
- }, function() {
599
- seen.push(3);
600
- });
601
- }).then(assert.fail, function(e) {
602
- assertIsStubError(e);
603
- assert.deepEqual([], seen);
604
- });
605
- });
611
+ let subTask;
606
612
 
607
- it('testRegisteredTaskCallbacksAreDroppedWhenTaskIsCancelled_withReturn', function() {
608
- var seen = [];
609
- return flow.execute(function() {
610
- flow.execute(throwStubError);
613
+ before(function() {
614
+ flow.execute(function() {
615
+ // This task will be discarded and never run because of the error below.
616
+ subTask = flow.execute(() => 'abc');
617
+ throw new StubError('stub');
618
+ }).catch(noop);
619
+ });
611
620
 
612
- return flow.execute(function() {
613
- seen.push(1);
614
- }).then(function() {
615
- seen.push(2);
616
- }, function() {
617
- seen.push(3);
618
- });
619
- }).then(assert.fail, function(e) {
620
- assertIsStubError(e);
621
- assert.deepEqual([], seen);
622
- });
623
- });
621
+ function assertCancellation(e) {
622
+ assert.ok(e instanceof promise.CancellationError);
623
+ assert.equal(
624
+ 'Task was discarded due to a previous failure: stub', e.message);
625
+ }
624
626
 
625
- it('testTasksWithinACallbackAreDroppedIfContainingTaskIsAborted', function() {
626
- var seen = [];
627
- return flow.execute(function() {
628
- flow.execute(throwStubError);
627
+ it('are rejected with cancellation error', function() {
628
+ let result;
629
+ return Promise.resolve().then(function() {
630
+ return flow.execute(function() {
631
+ result = subTask.then(assert.fail);
632
+ });
633
+ })
634
+ .then(() => result)
635
+ .then(assert.fail, assertCancellation);
636
+ });
629
637
 
630
- // None of the callbacks on this promise should execute because the
631
- // task assert.failure above is never handled, causing the containing task to
632
- // abort.
633
- promise.fulfilled().then(function() {
634
- seen.push(1);
635
- return flow.execute(function() {
636
- seen.push(2);
638
+ it('cancellation errors propagate through callbacks (1)', function() {
639
+ let result;
640
+ return Promise.resolve().then(function() {
641
+ return flow.execute(function() {
642
+ result = subTask
643
+ .then(assert.fail, assertCancellation)
644
+ .then(() => 'abc123');
645
+ });
646
+ })
647
+ .then(() => result)
648
+ .then(value => assert.equal('abc123', value));
637
649
  });
638
- }).finally(function() {
639
- seen.push(3);
640
- });
641
650
 
642
- }).then(assert.fail, function(e) {
643
- assertIsStubError(e);
644
- assert.deepEqual([], seen);
651
+ it('cancellation errors propagate through callbacks (2)', function() {
652
+ let result;
653
+ return Promise.resolve().then(function() {
654
+ return flow.execute(function() {
655
+ result = subTask.then(assert.fail)
656
+ .then(noop, assertCancellation)
657
+ .then(() => 'fin');
658
+ });
659
+ })
660
+ // Verify result actually computed successfully all the way through.
661
+ .then(() => result)
662
+ .then(value => assert.equal('fin', value));
663
+ });
664
+ });
645
665
  });
646
- });
647
-
648
- it('testTaskIsCancelledAfterWaitTimeout', function() {
649
- var seen = [];
650
- return flow.execute(function() {
651
- flow.wait(function() {
652
- return promise.delayed(50);
653
- }, 5);
654
666
 
667
+ it('testRegisteredTaskCallbacksAreDroppedWhenTaskIsCancelled_return', function() {
668
+ var seen = [];
655
669
  return flow.execute(function() {
656
- seen.push(1);
657
- }).then(function() {
658
- seen.push(2);
659
- }, function() {
660
- seen.push(3);
661
- });
662
- }).then(assert.fail, function() {
663
- assert.deepEqual([], seen);
670
+ flow.execute(throwStubError);
671
+
672
+ flow.execute(function() {
673
+ seen.push(1);
674
+ }).then(function() {
675
+ seen.push(2);
676
+ }, function() {
677
+ seen.push(3);
678
+ });
679
+ }).then(assert.fail, function(e) {
680
+ assertIsStubError(e);
681
+ assert.deepEqual([], seen);
682
+ });
664
683
  });
665
- });
666
684
 
667
- describe('task callbacks get cancellation error if registered after task was cancelled', function() {
668
- it('(a)', function() {
669
- var task;
670
- flow.execute(function() {
685
+ it('testRegisteredTaskCallbacksAreDroppedWhenTaskIsCancelled_withReturn', function() {
686
+ var seen = [];
687
+ return flow.execute(function() {
671
688
  flow.execute(throwStubError);
672
- task = flow.execute(function() {});
673
- }).then(assert.fail, assertIsStubError);
674
- return waitForIdle().then(function() {
675
- return task.then(assert.fail, function(e) {
676
- assert.ok(e instanceof promise.CancellationError);
689
+
690
+ return flow.execute(function() {
691
+ seen.push(1);
692
+ }).then(function() {
693
+ seen.push(2);
694
+ }, function() {
695
+ seen.push(3);
677
696
  });
697
+ }).then(assert.fail, function(e) {
698
+ assertIsStubError(e);
699
+ assert.deepEqual([], seen);
678
700
  });
679
701
  });
680
702
 
681
- it('(b)', function() {
703
+ it('testTasksWithinACallbackAreDroppedIfContainingTaskIsAborted', function() {
682
704
  var seen = [];
683
-
684
- var task;
685
- flow.execute(function() {
705
+ return flow.execute(function() {
686
706
  flow.execute(throwStubError);
687
- task = flow.execute(function() {});
688
707
 
689
- task.then(() => seen.push(1))
690
- .then(() => seen.push(2));
691
- task.then(() => seen.push(3))
692
- .then(() => seen.push(4));
708
+ // None of the callbacks on this promise should execute because the
709
+ // task assert.failure above is never handled, causing the containing task to
710
+ // abort.
711
+ promise.fulfilled().then(function() {
712
+ seen.push(1);
713
+ return flow.execute(function() {
714
+ seen.push(2);
715
+ });
716
+ }).finally(function() {
717
+ seen.push(3);
718
+ });
693
719
 
694
- }).then(assert.fail, assertIsStubError);
720
+ }).then(assert.fail, function(e) {
721
+ assertIsStubError(e);
722
+ assert.deepEqual([], seen);
723
+ });
724
+ });
695
725
 
696
- return waitForIdle().then(function() {
697
- return task.then(assert.fail, function(e) {
698
- seen.push(5);
699
- assert.ok(e instanceof promise.CancellationError);
726
+ it('testTaskIsCancelledAfterWaitTimeout', function() {
727
+ var seen = [];
728
+ return flow.execute(function() {
729
+ flow.wait(function() {
730
+ return promise.delayed(50);
731
+ }, 5);
732
+
733
+ return flow.execute(function() {
734
+ seen.push(1);
735
+ }).then(function() {
736
+ seen.push(2);
737
+ }, function() {
738
+ seen.push(3);
700
739
  });
701
- }).then(() => assert.deepEqual([5], seen));
740
+ }).then(assert.fail, function() {
741
+ assert.deepEqual([], seen);
742
+ });
702
743
  });
703
- });
704
744
 
705
- it('unhandledRejectionInParallelTaskQueue', function() {
706
- var seen = [];
707
- function schedule(name) {
708
- return flow.execute(() => seen.push(name), name);
709
- }
745
+ describe('task callbacks get cancellation error if registered after task was cancelled', function() {
746
+ it('(a)', function() {
747
+ var task;
748
+ flow.execute(function() {
749
+ flow.execute(throwStubError);
750
+ task = flow.execute(function() {});
751
+ }).then(assert.fail, assertIsStubError);
752
+ return waitForIdle().then(function() {
753
+ return task.then(assert.fail, function(e) {
754
+ assert.ok(e instanceof promise.CancellationError);
755
+ });
756
+ });
757
+ });
710
758
 
711
- flow.async(function() {
712
- schedule('a.1');
713
- flow.execute(throwStubError, 'a.2 (throws)');
714
- });
759
+ it('(b)', function() {
760
+ var seen = [];
715
761
 
716
- var b3;
717
- flow.async(function() {
718
- schedule('b.1');
719
- schedule('b.2');
720
- b3 = schedule('b.3');
721
- });
762
+ var task;
763
+ flow.execute(function() {
764
+ flow.execute(throwStubError);
765
+ task = flow.execute(function() {});
722
766
 
723
- var c3;
724
- flow.async(function() {
725
- schedule('c.1');
726
- schedule('c.2');
727
- c3 = schedule('c.3');
728
- });
767
+ task.then(() => seen.push(1))
768
+ .then(() => seen.push(2));
769
+ task.then(() => seen.push(3))
770
+ .then(() => seen.push(4));
771
+
772
+ }).then(assert.fail, assertIsStubError);
729
773
 
730
- function assertWasCancelled(p) {
731
- return p.then(assert.fail, function(e) {
732
- assert.ok(e instanceof promise.CancellationError);
774
+ return waitForIdle().then(function() {
775
+ return task.then(assert.fail, function(e) {
776
+ seen.push(5);
777
+ assert.ok(e instanceof promise.CancellationError);
778
+ });
779
+ }).then(() => assert.deepEqual([5], seen));
733
780
  });
734
- }
781
+ });
735
782
 
736
- return waitForAbort()
737
- .then(function() {
738
- assert.deepEqual(['a.1', 'b.1', 'c.1', 'b.2', 'c.2'], seen);
739
- assert.ok(!b3.isPending());
740
- assert.ok(!c3.isPending());
741
- })
742
- .then(() => assertWasCancelled(b3))
743
- .then(() => assertWasCancelled(c3));
744
- });
783
+ it('unhandledRejectionInParallelTaskQueue', function() {
784
+ var seen = [];
785
+ function schedule(name) {
786
+ return flow.execute(() => seen.push(name), name);
787
+ }
745
788
 
746
- it('errorsInAsyncFunctionsAreReportedAsUnhandledRejection', function() {
747
- flow.removeAllListeners(); // For tearDown.
789
+ flow.async(function() {
790
+ schedule('a.1');
791
+ flow.execute(throwStubError, 'a.2 (throws)');
792
+ });
748
793
 
749
- var task;
750
- return new Promise(function(fulfill) {
751
- flow.once('uncaughtException', fulfill);
794
+ var b3;
752
795
  flow.async(function() {
753
- task = flow.execute(function() {});
754
- throw Error('boom');
796
+ schedule('b.1');
797
+ schedule('b.2');
798
+ b3 = schedule('b.3');
755
799
  });
756
- }).then(function(error) {
757
- assert.ok(error instanceof promise.CancellationError);
758
- assert.ok(!task.isPending());
759
- return task.catch(function(error) {
760
- assert.ok(error instanceof promise.CancellationError);
800
+
801
+ var c3;
802
+ flow.async(function() {
803
+ schedule('c.1');
804
+ schedule('c.2');
805
+ c3 = schedule('c.3');
761
806
  });
807
+
808
+ function assertWasCancelled(p) {
809
+ return p.then(assert.fail, function(e) {
810
+ assert.ok(e instanceof promise.CancellationError);
811
+ });
812
+ }
813
+
814
+ return waitForAbort()
815
+ .then(function() {
816
+ assert.deepEqual(['a.1', 'b.1', 'c.1', 'b.2', 'c.2'], seen);
817
+ })
818
+ .then(() => assertWasCancelled(b3))
819
+ .then(() => assertWasCancelled(c3));
762
820
  });
763
- });
764
821
 
765
- describe('does not wait for values thrown from callbacks to be resolved', function() {
766
- it('(a)', function() {
767
- var p1 = promise.fulfilled();
768
- var reason = promise.fulfilled('should not see me');
769
- return p1.then(function() {
770
- throw reason;
771
- }).then(assert.fail, function(e) {
772
- assert.equal(reason, e);
822
+ it('errorsInAsyncFunctionsAreReportedAsUnhandledRejection', function() {
823
+ flow.removeAllListeners(); // For tearDown.
824
+
825
+ var task;
826
+ return new Promise(function(fulfill) {
827
+ flow.once('uncaughtException', fulfill);
828
+ flow.async(function() {
829
+ task = flow.execute(function() {});
830
+ throw Error('boom');
831
+ });
832
+ }).then(function(error) {
833
+ assert.ok(error instanceof promise.CancellationError);
834
+ return task.catch(function(error) {
835
+ assert.ok(error instanceof promise.CancellationError);
836
+ });
773
837
  });
774
838
  });
775
839
 
776
- it('(b)', function() {
777
- var p1 = promise.fulfilled();
778
- var reason = promise.rejected('should not see me');
779
- reason.catch(function() {}); // For tearDown.
780
- return p1.then(function() {
781
- throw reason;
782
- }).then(assert.fail, function(e) {
783
- assert.equal(reason, e);
840
+ describe('does not wait for values thrown from callbacks to be resolved', function() {
841
+ it('(a)', function() {
842
+ var p1 = promise.fulfilled();
843
+ var reason = promise.fulfilled('should not see me');
844
+ return p1.then(function() {
845
+ throw reason;
846
+ }).then(assert.fail, function(e) {
847
+ assert.equal(reason, e);
848
+ });
784
849
  });
785
- });
786
850
 
787
- it('(c)', function() {
788
- var p1 = promise.fulfilled();
789
- var reason = promise.defer();
790
- setTimeout(() => reason.fulfill('should not see me'), 100);
791
- return p1.then(function() {
792
- throw reason.promise;
793
- }).then(assert.fail, function(e) {
794
- assert.equal(reason.promise, e);
851
+ it('(b)', function() {
852
+ var p1 = promise.fulfilled();
853
+ var reason = promise.rejected('should not see me');
854
+ reason.catch(function() {}); // For tearDown.
855
+ return p1.then(function() {
856
+ throw reason;
857
+ }).then(assert.fail, function(e) {
858
+ assert.equal(reason, e);
859
+ });
795
860
  });
796
- });
797
861
 
798
- it('(d)', function() {
799
- var p1 = promise.fulfilled();
800
- var reason = {then: function() {}}; // A thenable like object.
801
- return p1.then(function() {
802
- throw reason;
803
- }).then(assert.fail, function(e) {
804
- assert.equal(reason, e);
862
+ it('(c)', function() {
863
+ var p1 = promise.fulfilled();
864
+ var reason = promise.defer();
865
+ setTimeout(() => reason.fulfill('should not see me'), 100);
866
+ return p1.then(function() {
867
+ throw reason.promise;
868
+ }).then(assert.fail, function(e) {
869
+ assert.equal(reason.promise, e);
870
+ });
871
+ });
872
+
873
+ it('(d)', function() {
874
+ var p1 = promise.fulfilled();
875
+ var reason = {then: function() {}}; // A thenable like object.
876
+ return p1.then(function() {
877
+ throw reason;
878
+ }).then(assert.fail, function(e) {
879
+ assert.equal(reason, e);
880
+ });
805
881
  });
806
882
  });
807
883
  });