Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 <!--
2 Any copyright is dedicated to the Public Domain.
3 http://creativecommons.org/publicdomain/zero/1.0/
4 -->
5 <html>
6 <head>
7 <title>Basic Promise Test</title>
8 <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
9 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
10 </head>
11 <body>
12 <p id="display"></p>
13 <div id="content" style="display: none">
15 </div>
16 <pre id="test">
17 <script type="application/javascript"><!--
19 function promiseResolve() {
20 ok(Promise, "Promise object should exist");
22 var promise = new Promise(function(resolve, reject) {
23 ok(resolve, "Promise.resolve exists");
24 ok(reject, "Promise.reject exists");
26 resolve(42);
27 }).then(function(what) {
28 ok(true, "Then - resolveCb has been called");
29 is(what, 42, "ResolveCb received 42");
30 runTest();
31 }, function() {
32 ok(false, "Then - rejectCb has been called");
33 runTest();
34 });
35 }
37 function promiseResolveNoArg() {
38 var promise = new Promise(function(resolve, reject) {
39 ok(resolve, "Promise.resolve exists");
40 ok(reject, "Promise.reject exists");
42 resolve();
43 }).then(function(what) {
44 ok(true, "Then - resolveCb has been called");
45 is(what, undefined, "ResolveCb received undefined");
46 runTest();
47 }, function() {
48 ok(false, "Then - rejectCb has been called");
49 runTest();
50 });
51 }
53 function promiseReject() {
54 var promise = new Promise(function(resolve, reject) {
55 reject(42);
56 }).then(function(what) {
57 ok(false, "Then - resolveCb has been called");
58 runTest();
59 }, function(what) {
60 ok(true, "Then - rejectCb has been called");
61 is(what, 42, "RejectCb received 42");
62 runTest();
63 });
64 }
66 function promiseRejectNoHandler() {
67 // This test only checks that the code that reports unhandled errors in the
68 // Promises implementation does not crash or leak.
69 var promise = new Promise(function(res, rej) {
70 noSuchMethod();
71 });
72 runTest();
73 }
75 function promiseRejectNoArg() {
76 var promise = new Promise(function(resolve, reject) {
77 reject();
78 }).then(function(what) {
79 ok(false, "Then - resolveCb has been called");
80 runTest();
81 }, function(what) {
82 ok(true, "Then - rejectCb has been called");
83 is(what, undefined, "RejectCb received undefined");
84 runTest();
85 });
86 }
88 function promiseException() {
89 var promise = new Promise(function(resolve, reject) {
90 throw 42;
91 }).then(function(what) {
92 ok(false, "Then - resolveCb has been called");
93 runTest();
94 }, function(what) {
95 ok(true, "Then - rejectCb has been called");
96 is(what, 42, "RejectCb received 42");
97 runTest();
98 });
99 }
101 function promiseGC() {
102 var resolve;
103 var promise = new Promise(function(r1, r2) {
104 resolve = r1;
105 }).then(function(what) {
106 ok(true, "Then - promise is still alive");
107 runTest();
108 });
110 promise = null;
112 SpecialPowers.gc();
113 SpecialPowers.forceGC();
114 SpecialPowers.forceCC();
116 resolve(42);
117 }
119 function promiseAsync() {
120 var global = "foo";
121 var f = new Promise(function(r1, r2) {
122 is(global, "foo", "Global should be foo");
123 r1(42);
124 is(global, "foo", "Global should still be foo");
125 setTimeout(function() {
126 is(global, "bar", "Global should still be bar!");
127 runTest();
128 }, 0);
129 }).then(function() {
130 global = "bar";
131 });
132 is(global, "foo", "Global should still be foo (2)");
133 }
135 function promiseDoubleThen() {
136 var steps = 0;
137 var promise = new Promise(function(r1, r2) {
138 r1(42);
139 });
141 promise.then(function(what) {
142 ok(true, "Then.resolve has been called");
143 is(what, 42, "Value == 42");
144 steps++;
145 }, function(what) {
146 ok(false, "Then.reject has been called");
147 });
149 promise.then(function(what) {
150 ok(true, "Then.resolve has been called");
151 is(steps, 1, "Then.resolve - step == 1");
152 is(what, 42, "Value == 42");
153 runTest();
154 }, function(what) {
155 ok(false, "Then.reject has been called");
156 });
157 }
159 function promiseThenException() {
160 var promise = new Promise(function(resolve, reject) {
161 resolve(42);
162 });
164 promise.then(function(what) {
165 ok(true, "Then.resolve has been called");
166 throw "booh";
167 }).catch(function(e) {
168 ok(true, "window.onerror has been called!");
169 runTest();
170 });
171 }
173 function promiseThenCatchThen() {
174 var promise = new Promise(function(resolve, reject) {
175 resolve(42);
176 });
178 var promise2 = promise.then(function(what) {
179 ok(true, "Then.resolve has been called");
180 is(what, 42, "Value == 42");
181 return what + 1;
182 }, function(what) {
183 ok(false, "Then.reject has been called");
184 });
186 isnot(promise, promise2, "These 2 promise objs are different");
188 promise2.then(function(what) {
189 ok(true, "Then.resolve has been called");
190 is(what, 43, "Value == 43");
191 return what + 1;
192 }, function(what) {
193 ok(false, "Then.reject has been called");
194 }).catch(function() {
195 ok(false, "Catch has been called");
196 }).then(function(what) {
197 ok(true, "Then.resolve has been called");
198 is(what, 44, "Value == 44");
199 runTest();
200 }, function(what) {
201 ok(false, "Then.reject has been called");
202 });
203 }
205 function promiseThenNoArg() {
206 var promise = new Promise(function(resolve, reject) {
207 resolve(42);
208 });
210 var clone = promise.then();
211 isnot(promise, clone, "These 2 promise objs are different");
212 promise.then(function(v) {
213 clone.then(function(cv) {
214 is(v, cv, "Both resolve to the same value");
215 runTest();
216 });
217 });
218 }
220 function promiseThenUndefinedResolveFunction() {
221 var promise = new Promise(function(resolve, reject) {
222 reject(42);
223 });
225 try {
226 promise.then(undefined, function(v) {
227 is(v, 42, "Promise rejected with 42");
228 runTest();
229 });
230 } catch (e) {
231 ok(false, "then should not throw on undefined resolve function");
232 }
233 }
235 function promiseThenNullResolveFunction() {
236 var promise = new Promise(function(resolve, reject) {
237 reject(42);
238 });
240 try {
241 promise.then(null, function(v) {
242 is(v, 42, "Promise rejected with 42");
243 runTest();
244 });
245 } catch (e) {
246 ok(false, "then should not throw on null resolve function");
247 }
248 }
250 function promiseRejectThenCatchThen() {
251 var promise = new Promise(function(resolve, reject) {
252 reject(42);
253 });
255 var promise2 = promise.then(function(what) {
256 ok(false, "Then.resolve has been called");
257 }, function(what) {
258 ok(true, "Then.reject has been called");
259 is(what, 42, "Value == 42");
260 return what + 1;
261 });
263 isnot(promise, promise2, "These 2 promise objs are different");
265 promise2.then(function(what) {
266 ok(true, "Then.resolve has been called");
267 is(what, 43, "Value == 43");
268 return what+1;
269 }).catch(function(what) {
270 ok(false, "Catch has been called");
271 }).then(function(what) {
272 ok(true, "Then.resolve has been called");
273 is(what, 44, "Value == 44");
274 runTest();
275 });
276 }
278 function promiseRejectThenCatchThen2() {
279 var promise = new Promise(function(resolve, reject) {
280 reject(42);
281 });
283 promise.then(function(what) {
284 ok(true, "Then.resolve has been called");
285 is(what, 42, "Value == 42");
286 return what+1;
287 }).catch(function(what) {
288 is(what, 42, "Value == 42");
289 ok(true, "Catch has been called");
290 return what+1;
291 }).then(function(what) {
292 ok(true, "Then.resolve has been called");
293 is(what, 43, "Value == 43");
294 runTest();
295 });
296 }
298 function promiseRejectThenCatchExceptionThen() {
299 var promise = new Promise(function(resolve, reject) {
300 reject(42);
301 });
303 promise.then(function(what) {
304 ok(false, "Then.resolve has been called");
305 }, function(what) {
306 ok(true, "Then.reject has been called");
307 is(what, 42, "Value == 42");
308 throw(what + 1);
309 }).catch(function(what) {
310 ok(true, "Catch has been called");
311 is(what, 43, "Value == 43");
312 return what + 1;
313 }).then(function(what) {
314 ok(true, "Then.resolve has been called");
315 is(what, 44, "Value == 44");
316 runTest();
317 });
318 }
320 function promiseThenCatchOrderingResolve() {
321 var global = 0;
322 var f = new Promise(function(r1, r2) {
323 r1(42);
324 });
326 f.then(function() {
327 f.then(function() {
328 global++;
329 });
330 f.catch(function() {
331 global++;
332 });
333 f.then(function() {
334 global++;
335 });
336 setTimeout(function() {
337 is(global, 2, "Many steps... should return 2");
338 runTest();
339 }, 0);
340 });
341 }
343 function promiseThenCatchOrderingReject() {
344 var global = 0;
345 var f = new Promise(function(r1, r2) {
346 r2(42);
347 })
349 f.then(function() {}, function() {
350 f.then(function() {
351 global++;
352 });
353 f.catch(function() {
354 global++;
355 });
356 f.then(function() {}, function() {
357 global++;
358 });
359 setTimeout(function() {
360 is(global, 2, "Many steps... should return 2");
361 runTest();
362 }, 0);
363 });
364 }
366 function promiseCatchNoArg() {
367 var promise = new Promise(function(resolve, reject) {
368 reject(42);
369 });
371 var clone = promise.catch();
372 isnot(promise, clone, "These 2 promise objs are different");
373 promise.catch(function(v) {
374 clone.catch(function(cv) {
375 is(v, cv, "Both reject to the same value");
376 runTest();
377 });
378 });
379 }
381 function promiseNestedPromise() {
382 new Promise(function(resolve, reject) {
383 resolve(new Promise(function(resolve, reject) {
384 ok(true, "Nested promise is executed");
385 resolve(42);
386 }));
387 }).then(function(value) {
388 is(value, 42, "Nested promise is executed and then == 42");
389 runTest();
390 });
391 }
393 function promiseNestedNestedPromise() {
394 new Promise(function(resolve, reject) {
395 resolve(new Promise(function(resolve, reject) {
396 ok(true, "Nested promise is executed");
397 resolve(42);
398 }).then(function(what) { return what+1; }));
399 }).then(function(value) {
400 is(value, 43, "Nested promise is executed and then == 43");
401 runTest();
402 });
403 }
405 function promiseWrongNestedPromise() {
406 new Promise(function(resolve, reject) {
407 resolve(new Promise(function(r, r2) {
408 ok(true, "Nested promise is executed");
409 r(42);
410 }));
411 reject(42);
412 }).then(function(value) {
413 is(value, 42, "Nested promise is executed and then == 42");
414 runTest();
415 }, function(value) {
416 ok(false, "This is wrong");
417 });
418 }
420 function promiseLoop() {
421 new Promise(function(resolve, reject) {
422 resolve(new Promise(function(r1, r2) {
423 ok(true, "Nested promise is executed");
424 r1(new Promise(function(r1, r2) {
425 ok(true, "Nested nested promise is executed");
426 r1(42);
427 }));
428 }));
429 }).then(function(value) {
430 is(value, 42, "Nested nested promise is executed and then == 42");
431 runTest();
432 }, function(value) {
433 ok(false, "This is wrong");
434 });
435 }
437 function promiseStaticReject() {
438 var promise = Promise.reject(42).then(function(what) {
439 ok(false, "This should not be called");
440 }, function(what) {
441 is(what, 42, "Value == 42");
442 runTest();
443 });
444 }
446 function promiseStaticResolve() {
447 var promise = Promise.resolve(42).then(function(what) {
448 is(what, 42, "Value == 42");
449 runTest();
450 }, function() {
451 ok(false, "This should not be called");
452 });
453 }
455 function promiseResolveNestedPromise() {
456 var promise = Promise.resolve(new Promise(function(r, r2) {
457 ok(true, "Nested promise is executed");
458 r(42);
459 }, function() {
460 ok(false, "This should not be called");
461 })).then(function(what) {
462 is(what, 42, "Value == 42");
463 runTest();
464 }, function() {
465 ok(false, "This should not be called");
466 });
467 }
469 function promiseSimpleThenableResolve() {
470 var thenable = { then: function(resolve) { resolve(5); } };
471 var promise = new Promise(function(resolve, reject) {
472 resolve(thenable);
473 });
475 promise.then(function(v) {
476 ok(v === 5, "promiseSimpleThenableResolve");
477 runTest();
478 }, function(e) {
479 ok(false, "promiseSimpleThenableResolve: Should not reject");
480 });
481 }
483 function promiseSimpleThenableReject() {
484 var thenable = { then: function(resolve, reject) { reject(5); } };
485 var promise = new Promise(function(resolve, reject) {
486 resolve(thenable);
487 });
489 promise.then(function() {
490 ok(false, "promiseSimpleThenableReject: Should not resolve");
491 runTest();
492 }, function(e) {
493 ok(e === 5, "promiseSimpleThenableReject");
494 runTest();
495 });
496 }
498 function promiseThenableThrowsBeforeCallback() {
499 var thenable = { then: function(resolve) {
500 throw new TypeError("Hi there");
501 resolve(5);
502 }};
504 var promise = Promise.resolve(thenable);
505 promise.then(function(v) {
506 ok(false, "promiseThenableThrowsBeforeCallback: Should've rejected");
507 runTest();
508 }, function(e) {
509 ok(e instanceof TypeError, "promiseThenableThrowsBeforeCallback");
510 runTest();
511 });
512 }
514 function promiseThenableThrowsAfterCallback() {
515 var thenable = { then: function(resolve) {
516 resolve(5);
517 throw new TypeError("Hi there");
518 }};
520 var promise = Promise.resolve(thenable);
521 promise.then(function(v) {
522 ok(v === 5, "promiseThenableThrowsAfterCallback");
523 runTest();
524 }, function(e) {
525 ok(false, "promiseThenableThrowsAfterCallback: Should've resolved");
526 runTest();
527 });
528 }
530 function promiseThenableRejectThenResolve() {
531 var thenable = { then: function(resolve, reject) {
532 reject(new TypeError("Hi there"));
533 resolve(5);
534 }};
536 var promise = Promise.resolve(thenable);
537 promise.then(function(v) {
538 ok(false, "promiseThenableRejectThenResolve should have rejected");
539 runTest();
540 }, function(e) {
541 ok(e instanceof TypeError, "promiseThenableRejectThenResolve");
542 runTest();
543 });
544 }
546 function promiseWithThenReplaced() {
547 // Ensure that we call the 'then' on the promise and not the internal then.
548 var promise = new Promise(function(resolve, reject) {
549 resolve(5);
550 });
552 // Rogue `then` always rejects.
553 promise.then = function(onFulfill, onReject) {
554 onReject(new TypeError("Foo"));
555 }
557 var promise2 = Promise.resolve(promise);
558 promise2.then(function(v) {
559 ok(false, "promiseWithThenReplaced: Should've rejected");
560 runTest();
561 }, function(e) {
562 ok(e instanceof TypeError, "promiseWithThenReplaced");
563 runTest();
564 });
565 }
567 function promiseStrictHandlers() {
568 var promise = Promise.resolve(5);
569 promise.then(function() {
570 "use strict";
571 ok(this === undefined, "Strict mode callback should have this === undefined.");
572 runTest();
573 });
574 }
576 function promiseStrictExecutorThisArg() {
577 var promise = new Promise(function(resolve, reject) {
578 "use strict";
579 ok(this === undefined, "thisArg should be undefined.");
580 runTest();
581 });
582 }
584 function promiseResolveArray() {
585 var p = Promise.resolve([1,2,3]);
586 ok(p instanceof Promise, "Should return a Promise.");
587 p.then(function(v) {
588 ok(Array.isArray(v), "Resolved value should be an Array");
589 is(v.length, 3, "Length should match");
590 is(v[0], 1, "Resolved value should match original");
591 is(v[1], 2, "Resolved value should match original");
592 is(v[2], 3, "Resolved value should match original");
593 runTest();
594 });
595 }
597 function promiseResolveThenable() {
598 var p = Promise.resolve({ then: function(onFulfill, onReject) { onFulfill(2); } });
599 ok(p instanceof Promise, "Should cast to a Promise.");
600 p.then(function(v) {
601 is(v, 2, "Should resolve to 2.");
602 runTest();
603 }, function(e) {
604 ok(false, "promiseResolveThenable should've resolved");
605 runTest();
606 });
607 }
609 function promiseResolvePromise() {
610 var original = Promise.resolve(true);
611 var cast = Promise.resolve(original);
613 ok(cast instanceof Promise, "Should cast to a Promise.");
614 is(cast, original, "Should return original Promise.");
615 cast.then(function(v) {
616 is(v, true, "Should resolve to true.");
617 runTest();
618 });
619 }
621 var tests = [ promiseResolve, promiseReject,
622 promiseException, promiseGC, promiseAsync,
623 promiseDoubleThen, promiseThenException,
624 promiseThenCatchThen, promiseRejectThenCatchThen,
625 promiseRejectThenCatchThen2,
626 promiseRejectThenCatchExceptionThen,
627 promiseThenCatchOrderingResolve,
628 promiseThenCatchOrderingReject,
629 promiseNestedPromise, promiseNestedNestedPromise,
630 promiseWrongNestedPromise, promiseLoop,
631 promiseStaticReject, promiseStaticResolve,
632 promiseResolveNestedPromise,
633 promiseResolveNoArg,
634 promiseRejectNoArg,
635 promiseThenNoArg,
636 promiseThenUndefinedResolveFunction,
637 promiseThenNullResolveFunction,
638 promiseCatchNoArg,
639 promiseRejectNoHandler,
640 promiseSimpleThenableResolve,
641 promiseSimpleThenableReject,
642 promiseThenableThrowsBeforeCallback,
643 promiseThenableThrowsAfterCallback,
644 promiseThenableRejectThenResolve,
645 promiseWithThenReplaced,
646 promiseStrictHandlers,
647 promiseStrictExecutorThisArg,
648 promiseResolveArray,
649 promiseResolveThenable,
650 promiseResolvePromise,
651 ];
653 function runTest() {
654 if (!tests.length) {
655 SimpleTest.finish();
656 return;
657 }
659 var test = tests.shift();
660 test();
661 }
663 SimpleTest.waitForExplicitFinish();
664 runTest();
665 // -->
666 </script>
667 </pre>
668 </body>
669 </html>