michael@0: function ok(a, msg) { michael@0: dump("OK: " + !!a + " => " + a + " " + msg + "\n"); michael@0: postMessage({type: 'status', status: !!a, msg: a + ": " + msg }); michael@0: } michael@0: michael@0: function is(a, b, msg) { michael@0: dump("IS: " + (a===b) + " => " + a + " | " + b + " " + msg + "\n"); michael@0: postMessage({type: 'status', status: a === b, msg: a + " === " + b + ": " + msg }); michael@0: } michael@0: michael@0: function isnot(a, b, msg) { michael@0: dump("ISNOT: " + (a!==b) + " => " + a + " | " + b + " " + msg + "\n"); michael@0: postMessage({type: 'status', status: a !== b, msg: a + " !== " + b + ": " + msg }); michael@0: } michael@0: michael@0: function promiseResolve() { michael@0: ok(Promise, "Promise object should exist"); michael@0: michael@0: var promise = new Promise(function(resolve, reject) { michael@0: ok(resolve, "Promise.resolve exists"); michael@0: ok(reject, "Promise.reject exists"); michael@0: michael@0: resolve(42); michael@0: }).then(function(what) { michael@0: ok(true, "Then - resolveCb has been called"); michael@0: is(what, 42, "ResolveCb received 42"); michael@0: runTest(); michael@0: }, function() { michael@0: ok(false, "Then - rejectCb has been called"); michael@0: runTest(); michael@0: }); michael@0: } michael@0: michael@0: function promiseResolveNoArg() { michael@0: var promise = new Promise(function(resolve, reject) { michael@0: ok(resolve, "Promise.resolve exists"); michael@0: ok(reject, "Promise.reject exists"); michael@0: michael@0: resolve(); michael@0: }).then(function(what) { michael@0: ok(true, "Then - resolveCb has been called"); michael@0: is(what, undefined, "ResolveCb received undefined"); michael@0: runTest(); michael@0: }, function() { michael@0: ok(false, "Then - rejectCb has been called"); michael@0: runTest(); michael@0: }); michael@0: } michael@0: michael@0: function promiseRejectNoHandler() { michael@0: // This test only checks that the code that reports unhandled errors in the michael@0: // Promises implementation does not crash or leak. michael@0: var promise = new Promise(function(res, rej) { michael@0: noSuchMethod(); michael@0: }); michael@0: runTest(); michael@0: } michael@0: michael@0: function promiseReject() { michael@0: var promise = new Promise(function(resolve, reject) { michael@0: reject(42); michael@0: }).then(function(what) { michael@0: ok(false, "Then - resolveCb has been called"); michael@0: runTest(); michael@0: }, function(what) { michael@0: ok(true, "Then - rejectCb has been called"); michael@0: is(what, 42, "RejectCb received 42"); michael@0: runTest(); michael@0: }); michael@0: } michael@0: michael@0: function promiseRejectNoArg() { michael@0: var promise = new Promise(function(resolve, reject) { michael@0: reject(); michael@0: }).then(function(what) { michael@0: ok(false, "Then - resolveCb has been called"); michael@0: runTest(); michael@0: }, function(what) { michael@0: ok(true, "Then - rejectCb has been called"); michael@0: is(what, undefined, "RejectCb received undefined"); michael@0: runTest(); michael@0: }); michael@0: } michael@0: michael@0: function promiseException() { michael@0: var promise = new Promise(function(resolve, reject) { michael@0: throw 42; michael@0: }).then(function(what) { michael@0: ok(false, "Then - resolveCb has been called"); michael@0: runTest(); michael@0: }, function(what) { michael@0: ok(true, "Then - rejectCb has been called"); michael@0: is(what, 42, "RejectCb received 42"); michael@0: runTest(); michael@0: }); michael@0: } michael@0: michael@0: function promiseAsync() { michael@0: var global = "foo"; michael@0: var f = new Promise(function(r1, r2) { michael@0: is(global, "foo", "Global should be foo"); michael@0: r1(42); michael@0: is(global, "foo", "Global should still be foo"); michael@0: setTimeout(function() { michael@0: is(global, "bar", "Global should still be bar!"); michael@0: runTest(); michael@0: }, 0); michael@0: }).then(function() { michael@0: global = "bar"; michael@0: }); michael@0: is(global, "foo", "Global should still be foo (2)"); michael@0: } michael@0: michael@0: function promiseDoubleThen() { michael@0: var steps = 0; michael@0: var promise = new Promise(function(r1, r2) { michael@0: r1(42); michael@0: }); michael@0: michael@0: promise.then(function(what) { michael@0: ok(true, "Then.resolve has been called"); michael@0: is(what, 42, "Value == 42"); michael@0: steps++; michael@0: }, function(what) { michael@0: ok(false, "Then.reject has been called"); michael@0: }); michael@0: michael@0: promise.then(function(what) { michael@0: ok(true, "Then.resolve has been called"); michael@0: is(steps, 1, "Then.resolve - step == 1"); michael@0: is(what, 42, "Value == 42"); michael@0: runTest(); michael@0: }, function(what) { michael@0: ok(false, "Then.reject has been called"); michael@0: }); michael@0: } michael@0: michael@0: function promiseThenException() { michael@0: var promise = new Promise(function(resolve, reject) { michael@0: resolve(42); michael@0: }); michael@0: michael@0: promise.then(function(what) { michael@0: ok(true, "Then.resolve has been called"); michael@0: throw "booh"; michael@0: }).catch(function(e) { michael@0: ok(true, "Catch has been called!"); michael@0: runTest(); michael@0: }); michael@0: } michael@0: michael@0: function promiseThenCatchThen() { michael@0: var promise = new Promise(function(resolve, reject) { michael@0: resolve(42); michael@0: }); michael@0: michael@0: var promise2 = promise.then(function(what) { michael@0: ok(true, "Then.resolve has been called"); michael@0: is(what, 42, "Value == 42"); michael@0: return what + 1; michael@0: }, function(what) { michael@0: ok(false, "Then.reject has been called"); michael@0: }); michael@0: michael@0: isnot(promise, promise2, "These 2 promise objs are different"); michael@0: michael@0: promise2.then(function(what) { michael@0: ok(true, "Then.resolve has been called"); michael@0: is(what, 43, "Value == 43"); michael@0: return what + 1; michael@0: }, function(what) { michael@0: ok(false, "Then.reject has been called"); michael@0: }).catch(function() { michael@0: ok(false, "Catch has been called"); michael@0: }).then(function(what) { michael@0: ok(true, "Then.resolve has been called"); michael@0: is(what, 44, "Value == 44"); michael@0: runTest(); michael@0: }, function(what) { michael@0: ok(false, "Then.reject has been called"); michael@0: }); michael@0: } michael@0: michael@0: function promiseRejectThenCatchThen() { michael@0: var promise = new Promise(function(resolve, reject) { michael@0: reject(42); michael@0: }); michael@0: michael@0: var promise2 = promise.then(function(what) { michael@0: ok(false, "Then.resolve has been called"); michael@0: }, function(what) { michael@0: ok(true, "Then.reject has been called"); michael@0: is(what, 42, "Value == 42"); michael@0: return what + 1; michael@0: }); michael@0: michael@0: isnot(promise, promise2, "These 2 promise objs are different"); michael@0: michael@0: promise2.then(function(what) { michael@0: ok(true, "Then.resolve has been called"); michael@0: is(what, 43, "Value == 43"); michael@0: return what+1; michael@0: }).catch(function(what) { michael@0: ok(false, "Catch has been called"); michael@0: }).then(function(what) { michael@0: ok(true, "Then.resolve has been called"); michael@0: is(what, 44, "Value == 44"); michael@0: runTest(); michael@0: }); michael@0: } michael@0: michael@0: function promiseRejectThenCatchThen2() { michael@0: var promise = new Promise(function(resolve, reject) { michael@0: reject(42); michael@0: }); michael@0: michael@0: promise.then(function(what) { michael@0: ok(true, "Then.resolve has been called"); michael@0: is(what, 42, "Value == 42"); michael@0: return what+1; michael@0: }).catch(function(what) { michael@0: is(what, 42, "Value == 42"); michael@0: ok(true, "Catch has been called"); michael@0: return what+1; michael@0: }).then(function(what) { michael@0: ok(true, "Then.resolve has been called"); michael@0: is(what, 43, "Value == 43"); michael@0: runTest(); michael@0: }); michael@0: } michael@0: michael@0: function promiseRejectThenCatchExceptionThen() { michael@0: var promise = new Promise(function(resolve, reject) { michael@0: reject(42); michael@0: }); michael@0: michael@0: promise.then(function(what) { michael@0: ok(false, "Then.resolve has been called"); michael@0: }, function(what) { michael@0: ok(true, "Then.reject has been called"); michael@0: is(what, 42, "Value == 42"); michael@0: throw(what + 1); michael@0: }).catch(function(what) { michael@0: ok(true, "Catch has been called"); michael@0: is(what, 43, "Value == 43"); michael@0: return what + 1; michael@0: }).then(function(what) { michael@0: ok(true, "Then.resolve has been called"); michael@0: is(what, 44, "Value == 44"); michael@0: runTest(); michael@0: }); michael@0: } michael@0: michael@0: function promiseThenCatchOrderingResolve() { michael@0: var global = 0; michael@0: var f = new Promise(function(r1, r2) { michael@0: r1(42); michael@0: }); michael@0: michael@0: f.then(function() { michael@0: f.then(function() { michael@0: global++; michael@0: }); michael@0: f.catch(function() { michael@0: global++; michael@0: }); michael@0: f.then(function() { michael@0: global++; michael@0: }); michael@0: setTimeout(function() { michael@0: is(global, 2, "Many steps... should return 2"); michael@0: runTest(); michael@0: }, 0); michael@0: }); michael@0: } michael@0: michael@0: function promiseThenCatchOrderingReject() { michael@0: var global = 0; michael@0: var f = new Promise(function(r1, r2) { michael@0: r2(42); michael@0: }) michael@0: michael@0: f.then(function() {}, function() { michael@0: f.then(function() { michael@0: global++; michael@0: }); michael@0: f.catch(function() { michael@0: global++; michael@0: }); michael@0: f.then(function() {}, function() { michael@0: global++; michael@0: }); michael@0: setTimeout(function() { michael@0: is(global, 2, "Many steps... should return 2"); michael@0: runTest(); michael@0: }, 0); michael@0: }); michael@0: } michael@0: michael@0: function promiseThenNoArg() { michael@0: var promise = new Promise(function(resolve, reject) { michael@0: resolve(42); michael@0: }); michael@0: michael@0: var clone = promise.then(); michael@0: isnot(promise, clone, "These 2 promise objs are different"); michael@0: promise.then(function(v) { michael@0: clone.then(function(cv) { michael@0: is(v, cv, "Both resolve to the same value"); michael@0: runTest(); michael@0: }); michael@0: }); michael@0: } michael@0: michael@0: function promiseThenUndefinedResolveFunction() { michael@0: var promise = new Promise(function(resolve, reject) { michael@0: reject(42); michael@0: }); michael@0: michael@0: try { michael@0: promise.then(undefined, function(v) { michael@0: is(v, 42, "Promise rejected with 42"); michael@0: runTest(); michael@0: }); michael@0: } catch (e) { michael@0: ok(false, "then should not throw on undefined resolve function"); michael@0: } michael@0: } michael@0: michael@0: function promiseThenNullResolveFunction() { michael@0: var promise = new Promise(function(resolve, reject) { michael@0: reject(42); michael@0: }); michael@0: michael@0: try { michael@0: promise.then(null, function(v) { michael@0: is(v, 42, "Promise rejected with 42"); michael@0: runTest(); michael@0: }); michael@0: } catch (e) { michael@0: ok(false, "then should not throw on null resolve function"); michael@0: } michael@0: } michael@0: michael@0: function promiseCatchNoArg() { michael@0: var promise = new Promise(function(resolve, reject) { michael@0: reject(42); michael@0: }); michael@0: michael@0: var clone = promise.catch(); michael@0: isnot(promise, clone, "These 2 promise objs are different"); michael@0: promise.catch(function(v) { michael@0: clone.catch(function(cv) { michael@0: is(v, cv, "Both reject to the same value"); michael@0: runTest(); michael@0: }); michael@0: }); michael@0: } michael@0: michael@0: function promiseNestedPromise() { michael@0: new Promise(function(resolve, reject) { michael@0: resolve(new Promise(function(resolve, reject) { michael@0: ok(true, "Nested promise is executed"); michael@0: resolve(42); michael@0: })); michael@0: }).then(function(value) { michael@0: is(value, 42, "Nested promise is executed and then == 42"); michael@0: runTest(); michael@0: }); michael@0: } michael@0: michael@0: function promiseNestedNestedPromise() { michael@0: new Promise(function(resolve, reject) { michael@0: resolve(new Promise(function(resolve, reject) { michael@0: ok(true, "Nested promise is executed"); michael@0: resolve(42); michael@0: }).then(function(what) { return what+1; })); michael@0: }).then(function(value) { michael@0: is(value, 43, "Nested promise is executed and then == 43"); michael@0: runTest(); michael@0: }); michael@0: } michael@0: michael@0: function promiseWrongNestedPromise() { michael@0: new Promise(function(resolve, reject) { michael@0: resolve(new Promise(function(r, r2) { michael@0: ok(true, "Nested promise is executed"); michael@0: r(42); michael@0: })); michael@0: reject(42); michael@0: }).then(function(value) { michael@0: is(value, 42, "Nested promise is executed and then == 42"); michael@0: runTest(); michael@0: }, function(value) { michael@0: ok(false, "This is wrong"); michael@0: }); michael@0: } michael@0: michael@0: function promiseLoop() { michael@0: new Promise(function(resolve, reject) { michael@0: resolve(new Promise(function(r1, r2) { michael@0: ok(true, "Nested promise is executed"); michael@0: r1(new Promise(function(r1, r2) { michael@0: ok(true, "Nested nested promise is executed"); michael@0: r1(42); michael@0: })); michael@0: })); michael@0: }).then(function(value) { michael@0: is(value, 42, "Nested nested promise is executed and then == 42"); michael@0: runTest(); michael@0: }, function(value) { michael@0: ok(false, "This is wrong"); michael@0: }); michael@0: } michael@0: michael@0: function promiseStaticReject() { michael@0: var promise = Promise.reject(42).then(function(what) { michael@0: ok(false, "This should not be called"); michael@0: }, function(what) { michael@0: is(what, 42, "Value == 42"); michael@0: runTest(); michael@0: }); michael@0: } michael@0: michael@0: function promiseStaticResolve() { michael@0: var promise = Promise.resolve(42).then(function(what) { michael@0: is(what, 42, "Value == 42"); michael@0: runTest(); michael@0: }, function() { michael@0: ok(false, "This should not be called"); michael@0: }); michael@0: } michael@0: michael@0: function promiseResolveNestedPromise() { michael@0: var promise = Promise.resolve(new Promise(function(r, r2) { michael@0: ok(true, "Nested promise is executed"); michael@0: r(42); michael@0: }, function() { michael@0: ok(false, "This should not be called"); michael@0: })).then(function(what) { michael@0: is(what, 42, "Value == 42"); michael@0: runTest(); michael@0: }, function() { michael@0: ok(false, "This should not be called"); michael@0: }); michael@0: } michael@0: michael@0: function promiseRejectNoHandler() { michael@0: // This test only checks that the code that reports unhandled errors in the michael@0: // Promises implementation does not crash or leak. michael@0: var promise = new Promise(function(res, rej) { michael@0: noSuchMethod(); michael@0: }); michael@0: runTest(); michael@0: } michael@0: michael@0: function promiseUtilitiesDefined() { michael@0: ok(Promise.all, "Promise.all must be defined when Promise is enabled."); michael@0: ok(Promise.race, "Promise.race must be defined when Promise is enabled."); michael@0: runTest(); michael@0: } michael@0: michael@0: function promiseAllArray() { michael@0: var p = Promise.all([1, new Date(), Promise.resolve("firefox")]); michael@0: ok(p instanceof Promise, "Return value of Promise.all should be a Promise."); michael@0: p.then(function(values) { michael@0: ok(Array.isArray(values), "Resolved value should be an array."); michael@0: is(values.length, 3, "Resolved array length should match iterable's length."); michael@0: is(values[0], 1, "Array values should match."); michael@0: ok(values[1] instanceof Date, "Array values should match."); michael@0: is(values[2], "firefox", "Array values should match."); michael@0: runTest(); michael@0: }, function() { michael@0: ok(false, "Promise.all shouldn't fail when iterable has no rejected Promises."); michael@0: runTest(); michael@0: }); michael@0: } michael@0: michael@0: function promiseAllWaitsForAllPromises() { michael@0: var arr = [ michael@0: new Promise(function(resolve) { michael@0: setTimeout(resolve.bind(undefined, 1), 50); michael@0: }), michael@0: new Promise(function(resolve) { michael@0: setTimeout(resolve.bind(undefined, 2), 10); michael@0: }), michael@0: new Promise(function(resolve) { michael@0: setTimeout(resolve.bind(undefined, new Promise(function(resolve2) { michael@0: resolve2(3); michael@0: })), 10); michael@0: }), michael@0: new Promise(function(resolve) { michael@0: setTimeout(resolve.bind(undefined, 4), 20); michael@0: }) michael@0: ]; michael@0: michael@0: var p = Promise.all(arr); michael@0: p.then(function(values) { michael@0: ok(Array.isArray(values), "Resolved value should be an array."); michael@0: is(values.length, 4, "Resolved array length should match iterable's length."); michael@0: is(values[0], 1, "Array values should match."); michael@0: is(values[1], 2, "Array values should match."); michael@0: is(values[2], 3, "Array values should match."); michael@0: is(values[3], 4, "Array values should match."); michael@0: runTest(); michael@0: }, function() { michael@0: ok(false, "Promise.all shouldn't fail when iterable has no rejected Promises."); michael@0: runTest(); michael@0: }); michael@0: } michael@0: michael@0: function promiseAllRejectFails() { michael@0: var arr = [ michael@0: new Promise(function(resolve) { michael@0: setTimeout(resolve.bind(undefined, 1), 50); michael@0: }), michael@0: new Promise(function(resolve, reject) { michael@0: setTimeout(reject.bind(undefined, 2), 10); michael@0: }), michael@0: new Promise(function(resolve) { michael@0: setTimeout(resolve.bind(undefined, 3), 10); michael@0: }), michael@0: new Promise(function(resolve) { michael@0: setTimeout(resolve.bind(undefined, 4), 20); michael@0: }) michael@0: ]; michael@0: michael@0: var p = Promise.all(arr); michael@0: p.then(function(values) { michael@0: ok(false, "Promise.all shouldn't resolve when iterable has rejected Promises."); michael@0: runTest(); michael@0: }, function(e) { michael@0: ok(true, "Promise.all should reject when iterable has rejected Promises."); michael@0: is(e, 2, "Rejection value should match."); michael@0: runTest(); michael@0: }); michael@0: } michael@0: michael@0: function promiseRaceEmpty() { michael@0: var p = Promise.race([]); michael@0: ok(p instanceof Promise, "Should return a Promise."); michael@0: // An empty race never resolves! michael@0: runTest(); michael@0: } michael@0: michael@0: function promiseRaceValuesArray() { michael@0: var p = Promise.race([true, new Date(), 3]); michael@0: ok(p instanceof Promise, "Should return a Promise."); michael@0: p.then(function(winner) { michael@0: is(winner, true, "First value should win."); michael@0: runTest(); michael@0: }, function(err) { michael@0: ok(false, "Should not fail " + err + "."); michael@0: runTest(); michael@0: }); michael@0: } michael@0: michael@0: function promiseRacePromiseArray() { michael@0: var arr = [ michael@0: new Promise(function(resolve) { michael@0: resolve("first"); michael@0: }), michael@0: Promise.resolve("second"), michael@0: new Promise(function() {}), michael@0: new Promise(function(resolve) { michael@0: setTimeout(function() { michael@0: setTimeout(function() { michael@0: resolve("fourth"); michael@0: }, 0); michael@0: }, 0); michael@0: }), michael@0: ]; michael@0: michael@0: var p = Promise.race(arr); michael@0: p.then(function(winner) { michael@0: is(winner, "first", "First queued resolution should win the race."); michael@0: runTest(); michael@0: }); michael@0: } michael@0: michael@0: function promiseRaceReject() { michael@0: var p = Promise.race([ michael@0: Promise.reject(new Error("Fail bad!")), michael@0: new Promise(function(resolve) { michael@0: setTimeout(resolve, 0); michael@0: }) michael@0: ]); michael@0: michael@0: p.then(function() { michael@0: ok(false, "Should not resolve when winning Promise rejected."); michael@0: runTest(); michael@0: }, function(e) { michael@0: ok(true, "Should be rejected"); michael@0: ok(e instanceof Error, "Should reject with Error."); michael@0: ok(e.message == "Fail bad!", "Message should match."); michael@0: runTest(); michael@0: }); michael@0: } michael@0: michael@0: function promiseRaceThrow() { michael@0: var p = Promise.race([ michael@0: new Promise(function(resolve) { michael@0: nonExistent(); michael@0: }), michael@0: new Promise(function(resolve) { michael@0: setTimeout(resolve, 0); michael@0: }) michael@0: ]); michael@0: michael@0: p.then(function() { michael@0: ok(false, "Should not resolve when winning Promise had an error."); michael@0: runTest(); michael@0: }, function(e) { michael@0: ok(true, "Should be rejected"); michael@0: ok(e instanceof ReferenceError, "Should reject with ReferenceError for function nonExistent()."); michael@0: runTest(); michael@0: }); michael@0: } michael@0: michael@0: function promiseResolveArray() { michael@0: var p = Promise.resolve([1,2,3]); michael@0: ok(p instanceof Promise, "Should return a Promise."); michael@0: p.then(function(v) { michael@0: ok(Array.isArray(v), "Resolved value should be an Array"); michael@0: is(v.length, 3, "Length should match"); michael@0: is(v[0], 1, "Resolved value should match original"); michael@0: is(v[1], 2, "Resolved value should match original"); michael@0: is(v[2], 3, "Resolved value should match original"); michael@0: runTest(); michael@0: }); michael@0: } michael@0: michael@0: function promiseResolveThenable() { michael@0: var p = Promise.resolve({ then: function(onFulfill, onReject) { onFulfill(2); } }); michael@0: ok(p instanceof Promise, "Should cast to a Promise."); michael@0: p.then(function(v) { michael@0: is(v, 2, "Should resolve to 2."); michael@0: runTest(); michael@0: }, function(e) { michael@0: ok(false, "promiseResolveThenable should've resolved"); michael@0: runTest(); michael@0: }); michael@0: } michael@0: michael@0: function promiseResolvePromise() { michael@0: var original = Promise.resolve(true); michael@0: var cast = Promise.resolve(original); michael@0: michael@0: ok(cast instanceof Promise, "Should cast to a Promise."); michael@0: is(cast, original, "Should return original Promise."); michael@0: cast.then(function(v) { michael@0: is(v, true, "Should resolve to true."); michael@0: runTest(); michael@0: }); michael@0: } michael@0: michael@0: var tests = [ michael@0: promiseResolve, michael@0: promiseReject, michael@0: promiseException, michael@0: promiseAsync, michael@0: promiseDoubleThen, michael@0: promiseThenException, michael@0: promiseThenCatchThen, michael@0: promiseRejectThenCatchThen, michael@0: promiseRejectThenCatchThen2, michael@0: promiseRejectThenCatchExceptionThen, michael@0: promiseThenCatchOrderingResolve, michael@0: promiseThenCatchOrderingReject, michael@0: promiseNestedPromise, michael@0: promiseNestedNestedPromise, michael@0: promiseWrongNestedPromise, michael@0: promiseLoop, michael@0: promiseStaticReject, michael@0: promiseStaticResolve, michael@0: promiseResolveNestedPromise, michael@0: promiseResolveNoArg, michael@0: promiseRejectNoArg, michael@0: michael@0: promiseThenNoArg, michael@0: promiseThenUndefinedResolveFunction, michael@0: promiseThenNullResolveFunction, michael@0: promiseCatchNoArg, michael@0: promiseRejectNoHandler, michael@0: michael@0: promiseUtilitiesDefined, michael@0: michael@0: promiseAllArray, michael@0: promiseAllWaitsForAllPromises, michael@0: promiseAllRejectFails, michael@0: michael@0: promiseRaceEmpty, michael@0: promiseRaceValuesArray, michael@0: promiseRacePromiseArray, michael@0: promiseRaceReject, michael@0: promiseRaceThrow, michael@0: michael@0: promiseResolveArray, michael@0: promiseResolveThenable, michael@0: promiseResolvePromise, michael@0: ]; michael@0: michael@0: function runTest() { michael@0: if (!tests.length) { michael@0: postMessage({ type: 'finish' }); michael@0: return; michael@0: } michael@0: michael@0: var test = tests.shift(); michael@0: test(); michael@0: } michael@0: michael@0: onmessage = function() { michael@0: runTest(); michael@0: }