|
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"> |
|
14 |
|
15 </div> |
|
16 <pre id="test"> |
|
17 <script type="application/javascript"><!-- |
|
18 |
|
19 function promiseResolve() { |
|
20 ok(Promise, "Promise object should exist"); |
|
21 |
|
22 var promise = new Promise(function(resolve, reject) { |
|
23 ok(resolve, "Promise.resolve exists"); |
|
24 ok(reject, "Promise.reject exists"); |
|
25 |
|
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 } |
|
36 |
|
37 function promiseResolveNoArg() { |
|
38 var promise = new Promise(function(resolve, reject) { |
|
39 ok(resolve, "Promise.resolve exists"); |
|
40 ok(reject, "Promise.reject exists"); |
|
41 |
|
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 } |
|
52 |
|
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 } |
|
65 |
|
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 } |
|
74 |
|
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 } |
|
87 |
|
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 } |
|
100 |
|
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 }); |
|
109 |
|
110 promise = null; |
|
111 |
|
112 SpecialPowers.gc(); |
|
113 SpecialPowers.forceGC(); |
|
114 SpecialPowers.forceCC(); |
|
115 |
|
116 resolve(42); |
|
117 } |
|
118 |
|
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 } |
|
134 |
|
135 function promiseDoubleThen() { |
|
136 var steps = 0; |
|
137 var promise = new Promise(function(r1, r2) { |
|
138 r1(42); |
|
139 }); |
|
140 |
|
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 }); |
|
148 |
|
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 } |
|
158 |
|
159 function promiseThenException() { |
|
160 var promise = new Promise(function(resolve, reject) { |
|
161 resolve(42); |
|
162 }); |
|
163 |
|
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 } |
|
172 |
|
173 function promiseThenCatchThen() { |
|
174 var promise = new Promise(function(resolve, reject) { |
|
175 resolve(42); |
|
176 }); |
|
177 |
|
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 }); |
|
185 |
|
186 isnot(promise, promise2, "These 2 promise objs are different"); |
|
187 |
|
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 } |
|
204 |
|
205 function promiseThenNoArg() { |
|
206 var promise = new Promise(function(resolve, reject) { |
|
207 resolve(42); |
|
208 }); |
|
209 |
|
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 } |
|
219 |
|
220 function promiseThenUndefinedResolveFunction() { |
|
221 var promise = new Promise(function(resolve, reject) { |
|
222 reject(42); |
|
223 }); |
|
224 |
|
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 } |
|
234 |
|
235 function promiseThenNullResolveFunction() { |
|
236 var promise = new Promise(function(resolve, reject) { |
|
237 reject(42); |
|
238 }); |
|
239 |
|
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 } |
|
249 |
|
250 function promiseRejectThenCatchThen() { |
|
251 var promise = new Promise(function(resolve, reject) { |
|
252 reject(42); |
|
253 }); |
|
254 |
|
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 }); |
|
262 |
|
263 isnot(promise, promise2, "These 2 promise objs are different"); |
|
264 |
|
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 } |
|
277 |
|
278 function promiseRejectThenCatchThen2() { |
|
279 var promise = new Promise(function(resolve, reject) { |
|
280 reject(42); |
|
281 }); |
|
282 |
|
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 } |
|
297 |
|
298 function promiseRejectThenCatchExceptionThen() { |
|
299 var promise = new Promise(function(resolve, reject) { |
|
300 reject(42); |
|
301 }); |
|
302 |
|
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 } |
|
319 |
|
320 function promiseThenCatchOrderingResolve() { |
|
321 var global = 0; |
|
322 var f = new Promise(function(r1, r2) { |
|
323 r1(42); |
|
324 }); |
|
325 |
|
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 } |
|
342 |
|
343 function promiseThenCatchOrderingReject() { |
|
344 var global = 0; |
|
345 var f = new Promise(function(r1, r2) { |
|
346 r2(42); |
|
347 }) |
|
348 |
|
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 } |
|
365 |
|
366 function promiseCatchNoArg() { |
|
367 var promise = new Promise(function(resolve, reject) { |
|
368 reject(42); |
|
369 }); |
|
370 |
|
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 } |
|
380 |
|
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 } |
|
392 |
|
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 } |
|
404 |
|
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 } |
|
419 |
|
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 } |
|
436 |
|
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 } |
|
445 |
|
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 } |
|
454 |
|
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 } |
|
468 |
|
469 function promiseSimpleThenableResolve() { |
|
470 var thenable = { then: function(resolve) { resolve(5); } }; |
|
471 var promise = new Promise(function(resolve, reject) { |
|
472 resolve(thenable); |
|
473 }); |
|
474 |
|
475 promise.then(function(v) { |
|
476 ok(v === 5, "promiseSimpleThenableResolve"); |
|
477 runTest(); |
|
478 }, function(e) { |
|
479 ok(false, "promiseSimpleThenableResolve: Should not reject"); |
|
480 }); |
|
481 } |
|
482 |
|
483 function promiseSimpleThenableReject() { |
|
484 var thenable = { then: function(resolve, reject) { reject(5); } }; |
|
485 var promise = new Promise(function(resolve, reject) { |
|
486 resolve(thenable); |
|
487 }); |
|
488 |
|
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 } |
|
497 |
|
498 function promiseThenableThrowsBeforeCallback() { |
|
499 var thenable = { then: function(resolve) { |
|
500 throw new TypeError("Hi there"); |
|
501 resolve(5); |
|
502 }}; |
|
503 |
|
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 } |
|
513 |
|
514 function promiseThenableThrowsAfterCallback() { |
|
515 var thenable = { then: function(resolve) { |
|
516 resolve(5); |
|
517 throw new TypeError("Hi there"); |
|
518 }}; |
|
519 |
|
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 } |
|
529 |
|
530 function promiseThenableRejectThenResolve() { |
|
531 var thenable = { then: function(resolve, reject) { |
|
532 reject(new TypeError("Hi there")); |
|
533 resolve(5); |
|
534 }}; |
|
535 |
|
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 } |
|
545 |
|
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 }); |
|
551 |
|
552 // Rogue `then` always rejects. |
|
553 promise.then = function(onFulfill, onReject) { |
|
554 onReject(new TypeError("Foo")); |
|
555 } |
|
556 |
|
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 } |
|
566 |
|
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 } |
|
575 |
|
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 } |
|
583 |
|
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 } |
|
596 |
|
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 } |
|
608 |
|
609 function promiseResolvePromise() { |
|
610 var original = Promise.resolve(true); |
|
611 var cast = Promise.resolve(original); |
|
612 |
|
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 } |
|
620 |
|
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 ]; |
|
652 |
|
653 function runTest() { |
|
654 if (!tests.length) { |
|
655 SimpleTest.finish(); |
|
656 return; |
|
657 } |
|
658 |
|
659 var test = tests.shift(); |
|
660 test(); |
|
661 } |
|
662 |
|
663 SimpleTest.waitForExplicitFinish(); |
|
664 runTest(); |
|
665 // --> |
|
666 </script> |
|
667 </pre> |
|
668 </body> |
|
669 </html> |
|
670 |