promise-prototype-finally.js 13.4 KB
Newer Older
1 2 3 4
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
// Flags: --allow-natives-syntax --ignore-unhandled-promises
6

7 8
load('test/mjsunit/test-async.js');

9
assertThrows(() => Promise.prototype.finally.call(5), TypeError);
10

11 12
testAsync(assert => {
  assert.plan(1);
13

14 15 16 17
  Promise.resolve(3).finally().then(x => {
    assert.equals(3, x);
  }, assert.unreachable);
}, "resolve/finally/then");
18

19 20 21 22 23
testAsync(assert => {
  assert.plan(1);

  Promise.reject(3).finally().then(assert.unreachable, x => {
    assert.equals(3, x);
24
  });
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
}, "reject/finally/then");

testAsync(assert => {
  assert.plan(1);

  Promise.resolve(3).finally(2).then(x => {
    assert.equals(3, x);
  }, assert.unreachable);
}, "resolve/finally-return-notcallable/then");

testAsync(assert => {
  assert.plan(1);

  Promise.reject(3).finally(2).then(assert.unreachable, e => {
    assert.equals(3, e);
40
  });
41 42 43 44
}, "reject/finally-return-notcallable/then");

testAsync(assert => {
  assert.plan(1);
45 46

  Promise.reject(3).finally().catch(reason => {
47
    assert.equals(3, reason);
48
  });
49
}, "reject/finally/catch");
50

51 52 53 54 55
testAsync(assert => {
  assert.plan(1);

  Promise.reject(3).finally().then(assert.unreachable).catch(reason => {
    assert.equals(3, reason);
56
  });
57 58 59 60
}, "reject/finally/then/catch");

testAsync(assert => {
  assert.plan(2);
61 62 63

  Promise.resolve(3)
    .then(x => {
64
      assert.equals(3, x);
65 66 67
      return x;
    })
    .finally()
68 69 70 71 72 73 74 75
    .then(x => {
      assert.equals(3, x);
    }, assert.unreachable);
}, "resolve/then/finally/then");

testAsync(assert => {
  assert.plan(2);

76 77
  Promise.reject(3)
    .catch(x => {
78
      assert.equals(3, x);
79 80 81
      return x;
    })
    .finally()
82 83 84 85 86 87 88 89
    .then(x => {
      assert.equals(3, x);
    }, assert.unreachable);
}, "reject/catch/finally/then");

testAsync(assert => {
  assert.plan(2);

90 91
  Promise.resolve(3)
    .finally(function onFinally() {
92 93
      print("in finally");
      assert.equals(0, arguments.length);
94 95
      throw 1;
    })
96 97
    .then(assert.unreachable, function onRejected(reason) {
      assert.equals(1, reason);
98
    });
99 100 101 102
}, "resolve/finally-throw/then");

testAsync(assert => {
  assert.plan(2);
103 104 105

  Promise.reject(3)
    .finally(function onFinally() {
106
      assert.equals(0, arguments.length);
107 108
      throw 1;
    })
109 110
    .then(assert.unreachable, function onRejected(reason) {
      assert.equals(1, reason);
111
    });
112 113 114 115
}, "reject/finally-throw/then");

testAsync(assert => {
  assert.plan(2);
116 117 118

  Promise.resolve(3)
    .finally(function onFinally() {
119
      assert.equals(0, arguments.length);
120 121
      return 4;
    })
122 123 124 125
    .then(x => {
      assert.equals(x, 3);
    }, assert.unreachable);
}, "resolve/finally-return/then");
126 127

// reject/finally-return/then
128 129 130
testAsync(assert => {
  assert.plan(2);

131 132
  Promise.reject(3)
    .finally(function onFinally() {
133
      assert.equals(0, arguments.length);
134 135
      return 4;
    })
136 137
    .then(assert.unreachable, x => {
      assert.equals(x, 3);
138
    });
139
});
140 141

// reject/catch-throw/finally-throw/then
142 143 144
testAsync(assert => {
  assert.plan(3);

145 146
  Promise.reject(3)
    .catch(e => {
147
      assert.equals(3, e);
148 149 150
      throw e;
    })
    .finally(function onFinally() {
151
      assert.equals(0, arguments.length);
152 153
      throw 4;
    })
154 155
    .then(assert.unreachable, function onRejected(e) {
      assert.equals(4, e);
156
    });
157 158 159 160
});

testAsync(assert => {
  assert.plan(3);
161 162 163

  Promise.resolve(3)
    .then(e => {
164
      assert.equals(3, e);
165 166 167
      throw e;
    })
    .finally(function onFinally() {
168
      assert.equals(0, arguments.length);
169 170
      throw 4;
    })
171 172
    .then(assert.unreachable, function onRejected(e) {
      assert.equals(4, e);
173
    });
174 175 176 177
}, "resolve/then-throw/finally-throw/then");

testAsync(assert => {
  assert.plan(2);
178 179 180

  Promise.resolve(3)
    .finally(function onFinally() {
181
      assert.equals(0, arguments.length);
182 183
      return Promise.reject(4);
    })
184 185
    .then(assert.unreachable, e => {
      assert.equals(4, e);
186
    });
187 188 189 190
}, "resolve/finally-return-rejected-promise/then");

testAsync(assert => {
  assert.plan(2);
191 192 193

  Promise.reject(3)
    .finally(function onFinally() {
194
      assert.equals(0, arguments.length);
195 196
      return Promise.reject(4);
    })
197 198
    .then(assert.unreachable, e => {
      assert.equals(4, e);
199
    });
200 201 202 203
}, "reject/finally-return-rejected-promise/then");

testAsync(assert => {
  assert.plan(2);
204 205 206

  Promise.resolve(3)
    .finally(function onFinally() {
207
      assert.equals(0, arguments.length);
208 209
      return Promise.resolve(4);
    })
210 211 212 213 214 215 216 217
    .then(x => {
      assert.equals(3, x);
    }, assert.unreachable);
}, "resolve/finally-return-resolved-promise/then");

testAsync(assert => {
  assert.plan(2);

218 219
  Promise.reject(3)
    .finally(function onFinally() {
220
      assert.equals(0, arguments.length);
221 222
      return Promise.resolve(4);
    })
223 224
    .then(assert.unreachable, e => {
      assert.equals(3, e);
225
    });
226 227 228 229
}, "reject/finally-return-resolved-promise/then");

testAsync(assert => {
  assert.plan(2);
230 231 232

  Promise.reject(3)
    .finally(function onFinally() {
233
      assert.equals(0, arguments.length);
234 235
      return Promise.resolve(4);
    })
236 237
    .then(assert.unreachable, e => {
      assert.equals(3, e);
238
    });
239 240 241 242
}, "reject/finally-return-resolved-promise/then");

testAsync(assert => {
  assert.plan(2);
243 244 245 246 247 248 249 250 251

  var thenable = {
    then: function(onResolve, onReject) {
      onResolve(5);
    }
  };

  Promise.resolve(5)
    .finally(function onFinally() {
252
      assert.equals(0, arguments.length);
253 254
      return thenable;
    })
255 256 257 258
    .then(x => {
      assert.equals(5, x);
    }, assert.unreachable);
}, "resolve/finally-thenable-resolve/then");
259

260 261
testAsync(assert => {
  assert.plan(2);
262 263 264 265 266 267 268 269 270

  var thenable = {
    then: function(onResolve, onReject) {
      onResolve(1);
    }
  };

  Promise.reject(5)
    .finally(function onFinally() {
271
      assert.equals(0, arguments.length);
272 273
      return thenable;
    })
274 275
    .then(assert.unreachable, e => {
      assert.equals(5, e);
276
    });
277
}, "reject/finally-thenable-resolve/then");
278

279 280
testAsync(assert => {
  assert.plan(2);
281 282 283 284 285 286 287 288 289

  var thenable = {
    then: function(onResolve, onReject) {
      onReject(1);
    }
  };

  Promise.reject(5)
    .finally(function onFinally() {
290
      assert.equals(0, arguments.length);
291 292
      return thenable;
    })
293 294
    .then(assert.unreachable, e => {
      assert.equals(1, e);
295
    });
296
}, "reject/finally-thenable-reject/then");
297

298 299
testAsync(assert => {
  assert.plan(2);
300 301 302 303 304 305 306 307 308

  var thenable = {
    then: function(onResolve, onReject) {
      onReject(1);
    }
  };

  Promise.resolve(5)
    .finally(function onFinally() {
309
      assert.equals(0, arguments.length);
310 311
      return thenable;
    })
312 313
    .then(assert.unreachable, e => {
      assert.equals(1, e);
314
    });
315
}, "resolve/finally-thenable-reject/then");
316

317 318
testAsync(assert => {
  assert.plan(3);
319 320 321

  Promise.resolve(5)
    .finally(function onFinally() {
322
      assert.equals(0, arguments.length);
323 324
    })
    .finally(function onFinally() {
325 326 327 328 329 330 331 332 333 334
      assert.equals(0, arguments.length);
    })
    .then(x => {
      assert.equals(5, x);
    }, assert.unreachable);
}, "resolve/finally/finally/then");

testAsync(assert => {
  assert.plan(3);

335 336
  Promise.resolve(5)
    .finally(function onFinally() {
337
      assert.equals(0, arguments.length);
338 339 340
      throw 1;
    })
    .finally(function onFinally() {
341
      assert.equals(0, arguments.length);
342
    })
343 344
    .then(assert.unreachable, e => {
      assert.equals(1, e);
345
    });
346
}, "resolve/finally-throw/finally/then");
347

348 349
testAsync(assert => {
  assert.plan(3);
350 351 352

  Promise.resolve(5)
    .finally(function onFinally() {
353
      assert.equals(0, arguments.length);
354 355 356
      return Promise.reject(1);
    })
    .finally(function onFinally() {
357
      assert.equals(0, arguments.length);
358
    })
359 360
    .then(assert.unreachable, e => {
      assert.equals(1, e);
361
    });
362
}, "resolve/finally-return-rejected-promise/finally/then");
363

364 365
testAsync(assert => {
  assert.plan(3);
366 367 368

  Promise.reject(5)
    .finally(function onFinally() {
369
      assert.equals(0, arguments.length);
370 371
    })
    .finally(function onFinally() {
372
      assert.equals(0, arguments.length);
373
    })
374 375
    .then(assert.unreachable, e => {
      assert.equals(5, e);
376
    });
377
}, "reject/finally/finally/then");
378

379 380
testAsync(assert => {
  assert.plan(3);
381 382 383

  Promise.reject(5)
    .finally(function onFinally() {
384
      assert.equals(0, arguments.length);
385 386 387
      throw 1;
    })
    .finally(function onFinally() {
388
      assert.equals(0, arguments.length);
389
    })
390 391
    .then(assert.unreachable, e => {
      assert.equals(1, e);
392
    });
393
}, "reject/finally-throw/finally/then");
394

395 396
testAsync(assert => {
  assert.plan(3);
397 398 399

  Promise.reject(5)
    .finally(function onFinally() {
400
      assert.equals(0, arguments.length);
401 402 403
      return Promise.reject(1);
    })
    .finally(function onFinally() {
404
      assert.equals(0, arguments.length);
405
    })
406 407
    .then(assert.unreachable, e => {
      assert.equals(1, e);
408
    });
409
}, "reject/finally-return-rejected-promise/finally/then");
410

411 412
testAsync(assert => {
  assert.plan(2);
413 414 415 416 417 418

  var resolve, reject;
  var deferred = new Promise((x, y) => {
    resolve = x;
    reject = y;
  });
419

420 421
  Promise.resolve(1)
    .finally(function onFinally() {
422
      assert.equals(0, arguments.length);
423 424
      return deferred;
    })
425 426 427
    .then(x => {
      assert.equals(1, x);
    }, assert.unreachable);
428 429

  resolve(5);
430 431 432 433 434
}, "resolve/finally-deferred-resolve/then");

//
testAsync(assert => {
  assert.plan(2);
435 436 437 438 439 440 441 442

  var resolve, reject;
  var deferred = new Promise((x, y) => {
    resolve = x;
    reject = y;
  });
  Promise.resolve(1)
    .finally(function onFinally() {
443
      assert.equals(0, arguments.length);
444 445
      return deferred;
    })
446 447
    .then(assert.unreachable, e => {
      assert.equals(5, e);
448 449 450
    });

  reject(5);
451 452 453 454
}, "resolve/finally-deferred-reject/then");

testAsync(assert => {
  assert.plan(2);
455 456 457 458 459 460 461 462

  var resolve, reject;
  var deferred = new Promise((x, y) => {
    resolve = x;
    reject = y;
  });
  Promise.all([deferred])
    .finally(function onFinally() {
463
      assert.equals(0, arguments.length);
464
    })
465 466 467
    .then(([x]) => {
      assert.equals(1, x);
    }, assert.unreachable);
468 469

  resolve(1);
470 471 472 473
}, "all/finally/then");

testAsync(assert => {
  assert.plan(2);
474 475 476 477 478 479 480 481 482 483 484 485

  var resolve, reject;
  var d1 = new Promise((x, y) => {
    resolve = x;
    reject = y;
  });
  var d2 = new Promise((x, y) => {
    resolve = x;
    reject = y;
  });
  Promise.race([d1, d2])
    .finally(function onFinally() {
486
      assert.equals(0, arguments.length);
487
    })
488 489 490
    .then(x => {
      assert.equals(1, x);
    }, assert.unreachable);
491 492

  resolve(1);
493 494 495 496
}, "race/finally/then");

testAsync(assert => {
  assert.plan(2);
497 498

  class MyPromise extends Promise {
499 500 501 502 503
    then(onFulfilled, onRejected) {
      assert.equals(5, onFulfilled);
      assert.equals(5, onRejected);
      return super.then(onFulfilled, onRejected);
    }
504 505 506
  }

  MyPromise.resolve(3).finally(5);
507
}, "resolve/finally-customthen/then");
508

509 510
testAsync(assert => {
  assert.plan(2);
511 512

  class MyPromise extends Promise {
513 514 515 516 517
    then(onFulfilled, onRejected) {
      assert.equals(5, onFulfilled);
      assert.equals(5, onRejected);
      return super.then(onFulfilled, onRejected);
    }
518 519 520
  }

  MyPromise.reject(3).finally(5);
521
}, "reject/finally-customthen/then");
522

523
var descriptor = Object.getOwnPropertyDescriptor(Promise.prototype, "finally");
524 525 526 527 528
assertTrue(descriptor.writable);
assertTrue(descriptor.configurable);
assertFalse(descriptor.enumerable);
assertEquals("finally", Promise.prototype.finally.name);
assertEquals(1, Promise.prototype.finally.length);
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609

var count = 0;
class FooPromise extends Promise {
  constructor(resolve, reject) {
    count++;
    return super(resolve, reject);
  }
}

testAsync(assert => {
  assert.plan(1);
  count = 0;

  new FooPromise(r => r()).finally(() => {}).then(() => {
    assert.equals(6, count);
  });
}, "finally/speciesconstructor");

testAsync(assert => {
  assert.plan(1);
  count = 0;

  FooPromise.resolve().finally(() => {}).then(() => {
    assert.equals(6, count);
  })
}, "resolve/finally/speciesconstructor");

testAsync(assert => {
  assert.plan(1);
  count = 0;

  FooPromise.reject().finally(() => {}).catch(() => {
    assert.equals(6, count);
  })
}, "reject/finally/speciesconstructor");

testAsync(assert => {
  assert.plan(2);

  class MyPromise extends Promise {
    static get [Symbol.species]() { return Promise; }
  }

  var p = Promise
      .resolve()
      .finally(() => MyPromise.resolve());

  assert.equals(true, p instanceof Promise);
  assert.equals(false, p instanceof MyPromise);
}, "finally/Symbol.Species");

testAsync(assert => {
  assert.plan(3);
  let resolve;
  let value = 0;

  let p = new Promise(r => { resolve = r });

  Promise.resolve()
    .finally(() => {
      return p;
    })
    .then(() => {
      value = 1;
    });

  // This makes sure we take the fast path in PromiseResolve that just
  // returns the promise it receives as value. If we had to create
  // another wrapper promise, that would cause an additional tick in
  // the microtask queue.
  Promise.resolve()
    // onFinally has run.
    .then(() => { resolve(); })
    // thenFinally has run.
    .then(() => assert.equals(0, value))
    // promise returned by .finally has been resolved.
    .then(() => assert.equals(0, value))
    // onFulfilled callback of .then() has run.
    .then(() => assert.equals(1, value));

}, "PromiseResolve-ordering");
610 611 612 613 614 615 616 617 618 619

(function testIsObject() {
  var called = false;
  var p = new Proxy(Promise.resolve(), {});
  var oldThen = Promise.prototype.then;
  Promise.prototype.then = () => called = true;
  Promise.prototype.finally.call(p);
  assertTrue(called);
  Promise.prototype.then = oldThen;
})();