Backed out changeset 06f41c22f3a6 (bug 1888460) for causing linux xpcshell failures...
[gecko.git] / dom / workers / test / promise_worker.js
blob1c2d080e5bb524991e53d5b267f6b44af42a7850
1 "use strict";
3 /* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */
5 function ok(a, msg) {
6   dump("OK: " + !!a + "  =>  " + a + " " + msg + "\n");
7   postMessage({ type: "status", status: !!a, msg: a + ": " + msg });
10 function is(a, b, msg) {
11   dump("IS: " + (a === b) + "  =>  " + a + " | " + b + " " + msg + "\n");
12   postMessage({
13     type: "status",
14     status: a === b,
15     msg: a + " === " + b + ": " + msg,
16   });
19 function isnot(a, b, msg) {
20   dump("ISNOT: " + (a !== b) + "  =>  " + a + " | " + b + " " + msg + "\n");
21   postMessage({
22     type: "status",
23     status: a !== b,
24     msg: a + " !== " + b + ": " + msg,
25   });
28 function promiseResolve() {
29   ok(Promise, "Promise object should exist");
31   var promise = new Promise(function (resolve, reject) {
32     ok(resolve, "Promise.resolve exists");
33     ok(reject, "Promise.reject exists");
35     resolve(42);
36   }).then(
37     function (what) {
38       ok(true, "Then - resolveCb has been called");
39       is(what, 42, "ResolveCb received 42");
40       runTest();
41     },
42     function () {
43       ok(false, "Then - rejectCb has been called");
44       runTest();
45     }
46   );
49 function promiseResolveNoArg() {
50   var promise = new Promise(function (resolve, reject) {
51     ok(resolve, "Promise.resolve exists");
52     ok(reject, "Promise.reject exists");
54     resolve();
55   }).then(
56     function (what) {
57       ok(true, "Then - resolveCb has been called");
58       is(what, undefined, "ResolveCb received undefined");
59       runTest();
60     },
61     function () {
62       ok(false, "Then - rejectCb has been called");
63       runTest();
64     }
65   );
68 function promiseRejectNoHandler() {
69   // This test only checks that the code that reports unhandled errors in the
70   // Promises implementation does not crash or leak.
71   var promise = new Promise(function (res, rej) {
72     noSuchMethod();
73   });
74   runTest();
77 function promiseReject() {
78   var promise = new Promise(function (resolve, reject) {
79     reject(42);
80   }).then(
81     function (what) {
82       ok(false, "Then - resolveCb has been called");
83       runTest();
84     },
85     function (what) {
86       ok(true, "Then - rejectCb has been called");
87       is(what, 42, "RejectCb received 42");
88       runTest();
89     }
90   );
93 function promiseRejectNoArg() {
94   var promise = new Promise(function (resolve, reject) {
95     reject();
96   }).then(
97     function (what) {
98       ok(false, "Then - resolveCb has been called");
99       runTest();
100     },
101     function (what) {
102       ok(true, "Then - rejectCb has been called");
103       is(what, undefined, "RejectCb received undefined");
104       runTest();
105     }
106   );
109 function promiseException() {
110   var promise = new Promise(function (resolve, reject) {
111     throw 42;
112   }).then(
113     function (what) {
114       ok(false, "Then - resolveCb has been called");
115       runTest();
116     },
117     function (what) {
118       ok(true, "Then - rejectCb has been called");
119       is(what, 42, "RejectCb received 42");
120       runTest();
121     }
122   );
125 function promiseAsync_TimeoutResolveThen() {
126   var handlerExecuted = false;
128   setTimeout(function () {
129     ok(handlerExecuted, "Handler should have been called before the timeout.");
131     // Allow other assertions to run so the test could fail before the next one.
132     setTimeout(runTest, 0);
133   }, 0);
135   Promise.resolve().then(function () {
136     handlerExecuted = true;
137   });
139   ok(!handlerExecuted, "Handlers are not called before 'then' returns.");
142 function promiseAsync_ResolveTimeoutThen() {
143   var handlerExecuted = false;
145   var promise = Promise.resolve();
147   setTimeout(function () {
148     ok(handlerExecuted, "Handler should have been called before the timeout.");
150     // Allow other assertions to run so the test could fail before the next one.
151     setTimeout(runTest, 0);
152   }, 0);
154   promise.then(function () {
155     handlerExecuted = true;
156   });
158   ok(!handlerExecuted, "Handlers are not called before 'then' returns.");
161 function promiseAsync_ResolveThenTimeout() {
162   var handlerExecuted = false;
164   Promise.resolve().then(function () {
165     handlerExecuted = true;
166   });
168   setTimeout(function () {
169     ok(handlerExecuted, "Handler should have been called before the timeout.");
171     // Allow other assertions to run so the test could fail before the next one.
172     setTimeout(runTest, 0);
173   }, 0);
175   ok(!handlerExecuted, "Handlers are not called before 'then' returns.");
178 function promiseAsync_SyncXHRAndImportScripts() {
179   var handlerExecuted = false;
181   Promise.resolve().then(function () {
182     handlerExecuted = true;
184     // Allow other assertions to run so the test could fail before the next one.
185     setTimeout(runTest, 0);
186   });
188   ok(!handlerExecuted, "Handlers are not called until the next microtask.");
190   var xhr = new XMLHttpRequest();
191   xhr.open("GET", "testXHR.txt", false);
192   xhr.send(null);
194   ok(!handlerExecuted, "Sync XHR should not trigger microtask execution.");
196   importScripts("../../../dom/xhr/tests/relativeLoad_import.js");
198   ok(!handlerExecuted, "importScripts should not trigger microtask execution.");
201 function promiseDoubleThen() {
202   var steps = 0;
203   var promise = new Promise(function (r1, r2) {
204     r1(42);
205   });
207   promise.then(
208     function (what) {
209       ok(true, "Then.resolve has been called");
210       is(what, 42, "Value == 42");
211       steps++;
212     },
213     function (what) {
214       ok(false, "Then.reject has been called");
215     }
216   );
218   promise.then(
219     function (what) {
220       ok(true, "Then.resolve has been called");
221       is(steps, 1, "Then.resolve - step == 1");
222       is(what, 42, "Value == 42");
223       runTest();
224     },
225     function (what) {
226       ok(false, "Then.reject has been called");
227     }
228   );
231 function promiseThenException() {
232   var promise = new Promise(function (resolve, reject) {
233     resolve(42);
234   });
236   promise
237     .then(function (what) {
238       ok(true, "Then.resolve has been called");
239       throw "booh";
240     })
241     .catch(function (e) {
242       ok(true, "Catch has been called!");
243       runTest();
244     });
247 function promiseThenCatchThen() {
248   var promise = new Promise(function (resolve, reject) {
249     resolve(42);
250   });
252   var promise2 = promise.then(
253     function (what) {
254       ok(true, "Then.resolve has been called");
255       is(what, 42, "Value == 42");
256       return what + 1;
257     },
258     function (what) {
259       ok(false, "Then.reject has been called");
260     }
261   );
263   isnot(promise, promise2, "These 2 promise objs are different");
265   promise2
266     .then(
267       function (what) {
268         ok(true, "Then.resolve has been called");
269         is(what, 43, "Value == 43");
270         return what + 1;
271       },
272       function (what) {
273         ok(false, "Then.reject has been called");
274       }
275     )
276     .catch(function () {
277       ok(false, "Catch has been called");
278     })
279     .then(
280       function (what) {
281         ok(true, "Then.resolve has been called");
282         is(what, 44, "Value == 44");
283         runTest();
284       },
285       function (what) {
286         ok(false, "Then.reject has been called");
287       }
288     );
291 function promiseRejectThenCatchThen() {
292   var promise = new Promise(function (resolve, reject) {
293     reject(42);
294   });
296   var promise2 = promise.then(
297     function (what) {
298       ok(false, "Then.resolve has been called");
299     },
300     function (what) {
301       ok(true, "Then.reject has been called");
302       is(what, 42, "Value == 42");
303       return what + 1;
304     }
305   );
307   isnot(promise, promise2, "These 2 promise objs are different");
309   promise2
310     .then(function (what) {
311       ok(true, "Then.resolve has been called");
312       is(what, 43, "Value == 43");
313       return what + 1;
314     })
315     .catch(function (what) {
316       ok(false, "Catch has been called");
317     })
318     .then(function (what) {
319       ok(true, "Then.resolve has been called");
320       is(what, 44, "Value == 44");
321       runTest();
322     });
325 function promiseRejectThenCatchThen2() {
326   var promise = new Promise(function (resolve, reject) {
327     reject(42);
328   });
330   promise
331     .then(function (what) {
332       ok(true, "Then.resolve has been called");
333       is(what, 42, "Value == 42");
334       return what + 1;
335     })
336     .catch(function (what) {
337       is(what, 42, "Value == 42");
338       ok(true, "Catch has been called");
339       return what + 1;
340     })
341     .then(function (what) {
342       ok(true, "Then.resolve has been called");
343       is(what, 43, "Value == 43");
344       runTest();
345     });
348 function promiseRejectThenCatchExceptionThen() {
349   var promise = new Promise(function (resolve, reject) {
350     reject(42);
351   });
353   promise
354     .then(
355       function (what) {
356         ok(false, "Then.resolve has been called");
357       },
358       function (what) {
359         ok(true, "Then.reject has been called");
360         is(what, 42, "Value == 42");
361         throw what + 1;
362       }
363     )
364     .catch(function (what) {
365       ok(true, "Catch has been called");
366       is(what, 43, "Value == 43");
367       return what + 1;
368     })
369     .then(function (what) {
370       ok(true, "Then.resolve has been called");
371       is(what, 44, "Value == 44");
372       runTest();
373     });
376 function promiseThenCatchOrderingResolve() {
377   var global = 0;
378   var f = new Promise(function (r1, r2) {
379     r1(42);
380   });
382   f.then(function () {
383     f.then(function () {
384       global++;
385     });
386     f.catch(function () {
387       global++;
388     });
389     f.then(function () {
390       global++;
391     });
392     setTimeout(function () {
393       is(global, 2, "Many steps... should return 2");
394       runTest();
395     }, 0);
396   });
399 function promiseThenCatchOrderingReject() {
400   var global = 0;
401   var f = new Promise(function (r1, r2) {
402     r2(42);
403   });
405   f.then(
406     function () {},
407     function () {
408       f.then(function () {
409         global++;
410       });
411       f.catch(function () {
412         global++;
413       });
414       f.then(
415         function () {},
416         function () {
417           global++;
418         }
419       );
420       setTimeout(function () {
421         is(global, 2, "Many steps... should return 2");
422         runTest();
423       }, 0);
424     }
425   );
428 function promiseThenNoArg() {
429   var promise = new Promise(function (resolve, reject) {
430     resolve(42);
431   });
433   var clone = promise.then();
434   isnot(promise, clone, "These 2 promise objs are different");
435   promise.then(function (v) {
436     clone.then(function (cv) {
437       is(v, cv, "Both resolve to the same value");
438       runTest();
439     });
440   });
443 function promiseThenUndefinedResolveFunction() {
444   var promise = new Promise(function (resolve, reject) {
445     reject(42);
446   });
448   try {
449     promise.then(undefined, function (v) {
450       is(v, 42, "Promise rejected with 42");
451       runTest();
452     });
453   } catch (e) {
454     ok(false, "then should not throw on undefined resolve function");
455   }
458 function promiseThenNullResolveFunction() {
459   var promise = new Promise(function (resolve, reject) {
460     reject(42);
461   });
463   try {
464     promise.then(null, function (v) {
465       is(v, 42, "Promise rejected with 42");
466       runTest();
467     });
468   } catch (e) {
469     ok(false, "then should not throw on null resolve function");
470   }
473 function promiseCatchNoArg() {
474   var promise = new Promise(function (resolve, reject) {
475     reject(42);
476   });
478   var clone = promise.catch();
479   isnot(promise, clone, "These 2 promise objs are different");
480   promise.catch(function (v) {
481     clone.catch(function (cv) {
482       is(v, cv, "Both reject to the same value");
483       runTest();
484     });
485   });
488 function promiseNestedPromise() {
489   new Promise(function (resolve, reject) {
490     resolve(
491       new Promise(function (r) {
492         ok(true, "Nested promise is executed");
493         r(42);
494       })
495     );
496   }).then(function (value) {
497     is(value, 42, "Nested promise is executed and then == 42");
498     runTest();
499   });
502 function promiseNestedNestedPromise() {
503   new Promise(function (resolve, reject) {
504     resolve(
505       new Promise(function (r) {
506         ok(true, "Nested promise is executed");
507         r(42);
508       }).then(function (what) {
509         return what + 1;
510       })
511     );
512   }).then(function (value) {
513     is(value, 43, "Nested promise is executed and then == 43");
514     runTest();
515   });
518 function promiseWrongNestedPromise() {
519   new Promise(function (resolve, reject) {
520     resolve(
521       new Promise(function (r, r2) {
522         ok(true, "Nested promise is executed");
523         r(42);
524       })
525     );
526     reject(42);
527   }).then(
528     function (value) {
529       is(value, 42, "Nested promise is executed and then == 42");
530       runTest();
531     },
532     function (value) {
533       ok(false, "This is wrong");
534     }
535   );
538 function promiseLoop() {
539   new Promise(function (resolve, reject) {
540     resolve(
541       new Promise(function (r1, r2) {
542         ok(true, "Nested promise is executed");
543         r1(
544           new Promise(function (r3, r4) {
545             ok(true, "Nested nested promise is executed");
546             r3(42);
547           })
548         );
549       })
550     );
551   }).then(
552     function (value) {
553       is(value, 42, "Nested nested promise is executed and then == 42");
554       runTest();
555     },
556     function (value) {
557       ok(false, "This is wrong");
558     }
559   );
562 function promiseStaticReject() {
563   var promise = Promise.reject(42).then(
564     function (what) {
565       ok(false, "This should not be called");
566     },
567     function (what) {
568       is(what, 42, "Value == 42");
569       runTest();
570     }
571   );
574 function promiseStaticResolve() {
575   var promise = Promise.resolve(42).then(
576     function (what) {
577       is(what, 42, "Value == 42");
578       runTest();
579     },
580     function () {
581       ok(false, "This should not be called");
582     }
583   );
586 function promiseResolveNestedPromise() {
587   var promise = Promise.resolve(
588     new Promise(
589       function (r, r2) {
590         ok(true, "Nested promise is executed");
591         r(42);
592       },
593       function () {
594         ok(false, "This should not be called");
595       }
596     )
597   ).then(
598     function (what) {
599       is(what, 42, "Value == 42");
600       runTest();
601     },
602     function () {
603       ok(false, "This should not be called");
604     }
605   );
608 function promiseUtilitiesDefined() {
609   ok(Promise.all, "Promise.all must be defined when Promise is enabled.");
610   ok(Promise.race, "Promise.race must be defined when Promise is enabled.");
611   runTest();
614 function promiseAllArray() {
615   var p = Promise.all([1, new Date(), Promise.resolve("firefox")]);
616   ok(p instanceof Promise, "Return value of Promise.all should be a Promise.");
617   p.then(
618     function (values) {
619       ok(Array.isArray(values), "Resolved value should be an array.");
620       is(
621         values.length,
622         3,
623         "Resolved array length should match iterable's length."
624       );
625       is(values[0], 1, "Array values should match.");
626       ok(values[1] instanceof Date, "Array values should match.");
627       is(values[2], "firefox", "Array values should match.");
628       runTest();
629     },
630     function () {
631       ok(
632         false,
633         "Promise.all shouldn't fail when iterable has no rejected Promises."
634       );
635       runTest();
636     }
637   );
640 function promiseAllWaitsForAllPromises() {
641   var arr = [
642     new Promise(function (resolve) {
643       setTimeout(resolve.bind(undefined, 1), 50);
644     }),
645     new Promise(function (resolve) {
646       setTimeout(resolve.bind(undefined, 2), 10);
647     }),
648     new Promise(function (resolve) {
649       setTimeout(
650         resolve.bind(
651           undefined,
652           new Promise(function (resolve2) {
653             resolve2(3);
654           })
655         ),
656         10
657       );
658     }),
659     new Promise(function (resolve) {
660       setTimeout(resolve.bind(undefined, 4), 20);
661     }),
662   ];
664   var p = Promise.all(arr);
665   p.then(
666     function (values) {
667       ok(Array.isArray(values), "Resolved value should be an array.");
668       is(
669         values.length,
670         4,
671         "Resolved array length should match iterable's length."
672       );
673       is(values[0], 1, "Array values should match.");
674       is(values[1], 2, "Array values should match.");
675       is(values[2], 3, "Array values should match.");
676       is(values[3], 4, "Array values should match.");
677       runTest();
678     },
679     function () {
680       ok(
681         false,
682         "Promise.all shouldn't fail when iterable has no rejected Promises."
683       );
684       runTest();
685     }
686   );
689 function promiseAllRejectFails() {
690   var arr = [
691     new Promise(function (resolve) {
692       setTimeout(resolve.bind(undefined, 1), 50);
693     }),
694     new Promise(function (resolve, reject) {
695       setTimeout(reject.bind(undefined, 2), 10);
696     }),
697     new Promise(function (resolve) {
698       setTimeout(resolve.bind(undefined, 3), 10);
699     }),
700     new Promise(function (resolve) {
701       setTimeout(resolve.bind(undefined, 4), 20);
702     }),
703   ];
705   var p = Promise.all(arr);
706   p.then(
707     function (values) {
708       ok(
709         false,
710         "Promise.all shouldn't resolve when iterable has rejected Promises."
711       );
712       runTest();
713     },
714     function (e) {
715       ok(
716         true,
717         "Promise.all should reject when iterable has rejected Promises."
718       );
719       is(e, 2, "Rejection value should match.");
720       runTest();
721     }
722   );
725 function promiseRaceEmpty() {
726   var p = Promise.race([]);
727   ok(p instanceof Promise, "Should return a Promise.");
728   // An empty race never resolves!
729   runTest();
732 function promiseRaceValuesArray() {
733   var p = Promise.race([true, new Date(), 3]);
734   ok(p instanceof Promise, "Should return a Promise.");
735   p.then(
736     function (winner) {
737       is(winner, true, "First value should win.");
738       runTest();
739     },
740     function (err) {
741       ok(false, "Should not fail " + err + ".");
742       runTest();
743     }
744   );
747 function promiseRacePromiseArray() {
748   var arr = [
749     new Promise(function (resolve) {
750       resolve("first");
751     }),
752     Promise.resolve("second"),
753     new Promise(function () {}),
754     new Promise(function (resolve) {
755       setTimeout(function () {
756         setTimeout(function () {
757           resolve("fourth");
758         }, 0);
759       }, 0);
760     }),
761   ];
763   var p = Promise.race(arr);
764   p.then(function (winner) {
765     is(winner, "first", "First queued resolution should win the race.");
766     runTest();
767   });
770 function promiseRaceReject() {
771   var p = Promise.race([
772     Promise.reject(new Error("Fail bad!")),
773     new Promise(function (resolve) {
774       setTimeout(resolve, 0);
775     }),
776   ]);
778   p.then(
779     function () {
780       ok(false, "Should not resolve when winning Promise rejected.");
781       runTest();
782     },
783     function (e) {
784       ok(true, "Should be rejected");
785       ok(e instanceof Error, "Should reject with Error.");
786       ok(e.message == "Fail bad!", "Message should match.");
787       runTest();
788     }
789   );
792 function promiseRaceThrow() {
793   var p = Promise.race([
794     new Promise(function (resolve) {
795       nonExistent();
796     }),
797     new Promise(function (resolve) {
798       setTimeout(resolve, 0);
799     }),
800   ]);
802   p.then(
803     function () {
804       ok(false, "Should not resolve when winning Promise had an error.");
805       runTest();
806     },
807     function (e) {
808       ok(true, "Should be rejected");
809       ok(
810         e instanceof ReferenceError,
811         "Should reject with ReferenceError for function nonExistent()."
812       );
813       runTest();
814     }
815   );
818 function promiseResolveArray() {
819   var p = Promise.resolve([1, 2, 3]);
820   ok(p instanceof Promise, "Should return a Promise.");
821   p.then(function (v) {
822     ok(Array.isArray(v), "Resolved value should be an Array");
823     is(v.length, 3, "Length should match");
824     is(v[0], 1, "Resolved value should match original");
825     is(v[1], 2, "Resolved value should match original");
826     is(v[2], 3, "Resolved value should match original");
827     runTest();
828   });
831 function promiseResolveThenable() {
832   var p = Promise.resolve({
833     then(onFulfill, onReject) {
834       onFulfill(2);
835     },
836   });
837   ok(p instanceof Promise, "Should cast to a Promise.");
838   p.then(
839     function (v) {
840       is(v, 2, "Should resolve to 2.");
841       runTest();
842     },
843     function (e) {
844       ok(false, "promiseResolveThenable should've resolved");
845       runTest();
846     }
847   );
850 function promiseResolvePromise() {
851   var original = Promise.resolve(true);
852   var cast = Promise.resolve(original);
854   ok(cast instanceof Promise, "Should cast to a Promise.");
855   is(cast, original, "Should return original Promise.");
856   cast.then(function (v) {
857     is(v, true, "Should resolve to true.");
858     runTest();
859   });
862 // Bug 1009569.
863 // Ensure that thenables are run on a clean stack asynchronously.
864 // Test case adopted from
865 // https://gist.github.com/getify/d64bb01751b50ed6b281#file-bug1-js.
866 function promiseResolveThenableCleanStack() {
867   function immed(s) {
868     x++;
869     s();
870   }
871   function incX() {
872     x++;
873   }
875   var x = 0;
876   var thenable = { then: immed };
877   var results = [];
879   var p = Promise.resolve(thenable).then(incX);
880   results.push(x);
882   // check what happens after all "next cycle" steps
883   // have had a chance to complete
884   setTimeout(function () {
885     // Result should be [0, 2] since `thenable` will be called async.
886     is(results[0], 0, "Expected thenable to be called asynchronously");
887     // See Bug 1023547 comment 13 for why this check has to be gated on p.
888     p.then(function () {
889       results.push(x);
890       is(results[1], 2, "Expected thenable to be called asynchronously");
891       runTest();
892     });
893   }, 1000);
896 // Bug 1062323
897 function promiseWrapperAsyncResolution() {
898   var p = new Promise(function (resolve, reject) {
899     resolve();
900   });
902   var results = [];
903   var q = p
904     .then(function () {
905       results.push("1-1");
906     })
907     .then(function () {
908       results.push("1-2");
909     })
910     .then(function () {
911       results.push("1-3");
912     });
914   var r = p
915     .then(function () {
916       results.push("2-1");
917     })
918     .then(function () {
919       results.push("2-2");
920     })
921     .then(function () {
922       results.push("2-3");
923     });
925   Promise.all([q, r]).then(
926     function () {
927       var match =
928         results[0] == "1-1" &&
929         results[1] == "2-1" &&
930         results[2] == "1-2" &&
931         results[3] == "2-2" &&
932         results[4] == "1-3" &&
933         results[5] == "2-3";
934       ok(match, "Chained promises should resolve asynchronously.");
935       runTest();
936     },
937     function () {
938       ok(false, "promiseWrapperAsyncResolution: One of the promises failed.");
939       runTest();
940     }
941   );
944 var tests = [
945   promiseResolve,
946   promiseReject,
947   promiseException,
948   promiseAsync_TimeoutResolveThen,
949   promiseAsync_ResolveTimeoutThen,
950   promiseAsync_ResolveThenTimeout,
951   promiseAsync_SyncXHRAndImportScripts,
952   promiseDoubleThen,
953   promiseThenException,
954   promiseThenCatchThen,
955   promiseRejectThenCatchThen,
956   promiseRejectThenCatchThen2,
957   promiseRejectThenCatchExceptionThen,
958   promiseThenCatchOrderingResolve,
959   promiseThenCatchOrderingReject,
960   promiseNestedPromise,
961   promiseNestedNestedPromise,
962   promiseWrongNestedPromise,
963   promiseLoop,
964   promiseStaticReject,
965   promiseStaticResolve,
966   promiseResolveNestedPromise,
967   promiseResolveNoArg,
968   promiseRejectNoArg,
970   promiseThenNoArg,
971   promiseThenUndefinedResolveFunction,
972   promiseThenNullResolveFunction,
973   promiseCatchNoArg,
974   promiseRejectNoHandler,
976   promiseUtilitiesDefined,
978   promiseAllArray,
979   promiseAllWaitsForAllPromises,
980   promiseAllRejectFails,
982   promiseRaceEmpty,
983   promiseRaceValuesArray,
984   promiseRacePromiseArray,
985   promiseRaceReject,
986   promiseRaceThrow,
988   promiseResolveArray,
989   promiseResolveThenable,
990   promiseResolvePromise,
992   promiseResolveThenableCleanStack,
994   promiseWrapperAsyncResolution,
997 function runTest() {
998   if (!tests.length) {
999     postMessage({ type: "finish" });
1000     return;
1001   }
1003   var test = tests.shift();
1004   test();
1007 onmessage = function () {
1008   runTest();