diff options
Diffstat (limited to 'dom/workers/test/promise_worker.js')
-rw-r--r-- | dom/workers/test/promise_worker.js | 1007 |
1 files changed, 1007 insertions, 0 deletions
diff --git a/dom/workers/test/promise_worker.js b/dom/workers/test/promise_worker.js new file mode 100644 index 0000000000..fd4a9177d6 --- /dev/null +++ b/dom/workers/test/promise_worker.js @@ -0,0 +1,1007 @@ +"use strict"; + +function ok(a, msg) { + dump("OK: " + !!a + " => " + a + " " + msg + "\n"); + postMessage({ type: "status", status: !!a, msg: a + ": " + msg }); +} + +function is(a, b, msg) { + dump("IS: " + (a === b) + " => " + a + " | " + b + " " + msg + "\n"); + postMessage({ + type: "status", + status: a === b, + msg: a + " === " + b + ": " + msg, + }); +} + +function isnot(a, b, msg) { + dump("ISNOT: " + (a !== b) + " => " + a + " | " + b + " " + msg + "\n"); + postMessage({ + type: "status", + status: a !== b, + msg: a + " !== " + b + ": " + msg, + }); +} + +function promiseResolve() { + ok(Promise, "Promise object should exist"); + + var promise = new Promise(function (resolve, reject) { + ok(resolve, "Promise.resolve exists"); + ok(reject, "Promise.reject exists"); + + resolve(42); + }).then( + function (what) { + ok(true, "Then - resolveCb has been called"); + is(what, 42, "ResolveCb received 42"); + runTest(); + }, + function () { + ok(false, "Then - rejectCb has been called"); + runTest(); + } + ); +} + +function promiseResolveNoArg() { + var promise = new Promise(function (resolve, reject) { + ok(resolve, "Promise.resolve exists"); + ok(reject, "Promise.reject exists"); + + resolve(); + }).then( + function (what) { + ok(true, "Then - resolveCb has been called"); + is(what, undefined, "ResolveCb received undefined"); + runTest(); + }, + function () { + ok(false, "Then - rejectCb has been called"); + runTest(); + } + ); +} + +function promiseRejectNoHandler() { + // This test only checks that the code that reports unhandled errors in the + // Promises implementation does not crash or leak. + var promise = new Promise(function (res, rej) { + noSuchMethod(); + }); + runTest(); +} + +function promiseReject() { + var promise = new Promise(function (resolve, reject) { + reject(42); + }).then( + function (what) { + ok(false, "Then - resolveCb has been called"); + runTest(); + }, + function (what) { + ok(true, "Then - rejectCb has been called"); + is(what, 42, "RejectCb received 42"); + runTest(); + } + ); +} + +function promiseRejectNoArg() { + var promise = new Promise(function (resolve, reject) { + reject(); + }).then( + function (what) { + ok(false, "Then - resolveCb has been called"); + runTest(); + }, + function (what) { + ok(true, "Then - rejectCb has been called"); + is(what, undefined, "RejectCb received undefined"); + runTest(); + } + ); +} + +function promiseException() { + var promise = new Promise(function (resolve, reject) { + throw 42; + }).then( + function (what) { + ok(false, "Then - resolveCb has been called"); + runTest(); + }, + function (what) { + ok(true, "Then - rejectCb has been called"); + is(what, 42, "RejectCb received 42"); + runTest(); + } + ); +} + +function promiseAsync_TimeoutResolveThen() { + var handlerExecuted = false; + + setTimeout(function () { + ok(handlerExecuted, "Handler should have been called before the timeout."); + + // Allow other assertions to run so the test could fail before the next one. + setTimeout(runTest, 0); + }, 0); + + Promise.resolve().then(function () { + handlerExecuted = true; + }); + + ok(!handlerExecuted, "Handlers are not called before 'then' returns."); +} + +function promiseAsync_ResolveTimeoutThen() { + var handlerExecuted = false; + + var promise = Promise.resolve(); + + setTimeout(function () { + ok(handlerExecuted, "Handler should have been called before the timeout."); + + // Allow other assertions to run so the test could fail before the next one. + setTimeout(runTest, 0); + }, 0); + + promise.then(function () { + handlerExecuted = true; + }); + + ok(!handlerExecuted, "Handlers are not called before 'then' returns."); +} + +function promiseAsync_ResolveThenTimeout() { + var handlerExecuted = false; + + Promise.resolve().then(function () { + handlerExecuted = true; + }); + + setTimeout(function () { + ok(handlerExecuted, "Handler should have been called before the timeout."); + + // Allow other assertions to run so the test could fail before the next one. + setTimeout(runTest, 0); + }, 0); + + ok(!handlerExecuted, "Handlers are not called before 'then' returns."); +} + +function promiseAsync_SyncXHRAndImportScripts() { + var handlerExecuted = false; + + Promise.resolve().then(function () { + handlerExecuted = true; + + // Allow other assertions to run so the test could fail before the next one. + setTimeout(runTest, 0); + }); + + ok(!handlerExecuted, "Handlers are not called until the next microtask."); + + var xhr = new XMLHttpRequest(); + xhr.open("GET", "testXHR.txt", false); + xhr.send(null); + + ok(!handlerExecuted, "Sync XHR should not trigger microtask execution."); + + importScripts("../../../dom/xhr/tests/relativeLoad_import.js"); + + ok(!handlerExecuted, "importScripts should not trigger microtask execution."); +} + +function promiseDoubleThen() { + var steps = 0; + var promise = new Promise(function (r1, r2) { + r1(42); + }); + + promise.then( + function (what) { + ok(true, "Then.resolve has been called"); + is(what, 42, "Value == 42"); + steps++; + }, + function (what) { + ok(false, "Then.reject has been called"); + } + ); + + promise.then( + function (what) { + ok(true, "Then.resolve has been called"); + is(steps, 1, "Then.resolve - step == 1"); + is(what, 42, "Value == 42"); + runTest(); + }, + function (what) { + ok(false, "Then.reject has been called"); + } + ); +} + +function promiseThenException() { + var promise = new Promise(function (resolve, reject) { + resolve(42); + }); + + promise + .then(function (what) { + ok(true, "Then.resolve has been called"); + throw "booh"; + }) + .catch(function (e) { + ok(true, "Catch has been called!"); + runTest(); + }); +} + +function promiseThenCatchThen() { + var promise = new Promise(function (resolve, reject) { + resolve(42); + }); + + var promise2 = promise.then( + function (what) { + ok(true, "Then.resolve has been called"); + is(what, 42, "Value == 42"); + return what + 1; + }, + function (what) { + ok(false, "Then.reject has been called"); + } + ); + + isnot(promise, promise2, "These 2 promise objs are different"); + + promise2 + .then( + function (what) { + ok(true, "Then.resolve has been called"); + is(what, 43, "Value == 43"); + return what + 1; + }, + function (what) { + ok(false, "Then.reject has been called"); + } + ) + .catch(function () { + ok(false, "Catch has been called"); + }) + .then( + function (what) { + ok(true, "Then.resolve has been called"); + is(what, 44, "Value == 44"); + runTest(); + }, + function (what) { + ok(false, "Then.reject has been called"); + } + ); +} + +function promiseRejectThenCatchThen() { + var promise = new Promise(function (resolve, reject) { + reject(42); + }); + + var promise2 = promise.then( + function (what) { + ok(false, "Then.resolve has been called"); + }, + function (what) { + ok(true, "Then.reject has been called"); + is(what, 42, "Value == 42"); + return what + 1; + } + ); + + isnot(promise, promise2, "These 2 promise objs are different"); + + promise2 + .then(function (what) { + ok(true, "Then.resolve has been called"); + is(what, 43, "Value == 43"); + return what + 1; + }) + .catch(function (what) { + ok(false, "Catch has been called"); + }) + .then(function (what) { + ok(true, "Then.resolve has been called"); + is(what, 44, "Value == 44"); + runTest(); + }); +} + +function promiseRejectThenCatchThen2() { + var promise = new Promise(function (resolve, reject) { + reject(42); + }); + + promise + .then(function (what) { + ok(true, "Then.resolve has been called"); + is(what, 42, "Value == 42"); + return what + 1; + }) + .catch(function (what) { + is(what, 42, "Value == 42"); + ok(true, "Catch has been called"); + return what + 1; + }) + .then(function (what) { + ok(true, "Then.resolve has been called"); + is(what, 43, "Value == 43"); + runTest(); + }); +} + +function promiseRejectThenCatchExceptionThen() { + var promise = new Promise(function (resolve, reject) { + reject(42); + }); + + promise + .then( + function (what) { + ok(false, "Then.resolve has been called"); + }, + function (what) { + ok(true, "Then.reject has been called"); + is(what, 42, "Value == 42"); + throw what + 1; + } + ) + .catch(function (what) { + ok(true, "Catch has been called"); + is(what, 43, "Value == 43"); + return what + 1; + }) + .then(function (what) { + ok(true, "Then.resolve has been called"); + is(what, 44, "Value == 44"); + runTest(); + }); +} + +function promiseThenCatchOrderingResolve() { + var global = 0; + var f = new Promise(function (r1, r2) { + r1(42); + }); + + f.then(function () { + f.then(function () { + global++; + }); + f.catch(function () { + global++; + }); + f.then(function () { + global++; + }); + setTimeout(function () { + is(global, 2, "Many steps... should return 2"); + runTest(); + }, 0); + }); +} + +function promiseThenCatchOrderingReject() { + var global = 0; + var f = new Promise(function (r1, r2) { + r2(42); + }); + + f.then( + function () {}, + function () { + f.then(function () { + global++; + }); + f.catch(function () { + global++; + }); + f.then( + function () {}, + function () { + global++; + } + ); + setTimeout(function () { + is(global, 2, "Many steps... should return 2"); + runTest(); + }, 0); + } + ); +} + +function promiseThenNoArg() { + var promise = new Promise(function (resolve, reject) { + resolve(42); + }); + + var clone = promise.then(); + isnot(promise, clone, "These 2 promise objs are different"); + promise.then(function (v) { + clone.then(function (cv) { + is(v, cv, "Both resolve to the same value"); + runTest(); + }); + }); +} + +function promiseThenUndefinedResolveFunction() { + var promise = new Promise(function (resolve, reject) { + reject(42); + }); + + try { + promise.then(undefined, function (v) { + is(v, 42, "Promise rejected with 42"); + runTest(); + }); + } catch (e) { + ok(false, "then should not throw on undefined resolve function"); + } +} + +function promiseThenNullResolveFunction() { + var promise = new Promise(function (resolve, reject) { + reject(42); + }); + + try { + promise.then(null, function (v) { + is(v, 42, "Promise rejected with 42"); + runTest(); + }); + } catch (e) { + ok(false, "then should not throw on null resolve function"); + } +} + +function promiseCatchNoArg() { + var promise = new Promise(function (resolve, reject) { + reject(42); + }); + + var clone = promise.catch(); + isnot(promise, clone, "These 2 promise objs are different"); + promise.catch(function (v) { + clone.catch(function (cv) { + is(v, cv, "Both reject to the same value"); + runTest(); + }); + }); +} + +function promiseNestedPromise() { + new Promise(function (resolve, reject) { + resolve( + new Promise(function (r) { + ok(true, "Nested promise is executed"); + r(42); + }) + ); + }).then(function (value) { + is(value, 42, "Nested promise is executed and then == 42"); + runTest(); + }); +} + +function promiseNestedNestedPromise() { + new Promise(function (resolve, reject) { + resolve( + new Promise(function (r) { + ok(true, "Nested promise is executed"); + r(42); + }).then(function (what) { + return what + 1; + }) + ); + }).then(function (value) { + is(value, 43, "Nested promise is executed and then == 43"); + runTest(); + }); +} + +function promiseWrongNestedPromise() { + new Promise(function (resolve, reject) { + resolve( + new Promise(function (r, r2) { + ok(true, "Nested promise is executed"); + r(42); + }) + ); + reject(42); + }).then( + function (value) { + is(value, 42, "Nested promise is executed and then == 42"); + runTest(); + }, + function (value) { + ok(false, "This is wrong"); + } + ); +} + +function promiseLoop() { + new Promise(function (resolve, reject) { + resolve( + new Promise(function (r1, r2) { + ok(true, "Nested promise is executed"); + r1( + new Promise(function (r3, r4) { + ok(true, "Nested nested promise is executed"); + r3(42); + }) + ); + }) + ); + }).then( + function (value) { + is(value, 42, "Nested nested promise is executed and then == 42"); + runTest(); + }, + function (value) { + ok(false, "This is wrong"); + } + ); +} + +function promiseStaticReject() { + var promise = Promise.reject(42).then( + function (what) { + ok(false, "This should not be called"); + }, + function (what) { + is(what, 42, "Value == 42"); + runTest(); + } + ); +} + +function promiseStaticResolve() { + var promise = Promise.resolve(42).then( + function (what) { + is(what, 42, "Value == 42"); + runTest(); + }, + function () { + ok(false, "This should not be called"); + } + ); +} + +function promiseResolveNestedPromise() { + var promise = Promise.resolve( + new Promise( + function (r, r2) { + ok(true, "Nested promise is executed"); + r(42); + }, + function () { + ok(false, "This should not be called"); + } + ) + ).then( + function (what) { + is(what, 42, "Value == 42"); + runTest(); + }, + function () { + ok(false, "This should not be called"); + } + ); +} + +function promiseUtilitiesDefined() { + ok(Promise.all, "Promise.all must be defined when Promise is enabled."); + ok(Promise.race, "Promise.race must be defined when Promise is enabled."); + runTest(); +} + +function promiseAllArray() { + var p = Promise.all([1, new Date(), Promise.resolve("firefox")]); + ok(p instanceof Promise, "Return value of Promise.all should be a Promise."); + p.then( + function (values) { + ok(Array.isArray(values), "Resolved value should be an array."); + is( + values.length, + 3, + "Resolved array length should match iterable's length." + ); + is(values[0], 1, "Array values should match."); + ok(values[1] instanceof Date, "Array values should match."); + is(values[2], "firefox", "Array values should match."); + runTest(); + }, + function () { + ok( + false, + "Promise.all shouldn't fail when iterable has no rejected Promises." + ); + runTest(); + } + ); +} + +function promiseAllWaitsForAllPromises() { + var arr = [ + new Promise(function (resolve) { + setTimeout(resolve.bind(undefined, 1), 50); + }), + new Promise(function (resolve) { + setTimeout(resolve.bind(undefined, 2), 10); + }), + new Promise(function (resolve) { + setTimeout( + resolve.bind( + undefined, + new Promise(function (resolve2) { + resolve2(3); + }) + ), + 10 + ); + }), + new Promise(function (resolve) { + setTimeout(resolve.bind(undefined, 4), 20); + }), + ]; + + var p = Promise.all(arr); + p.then( + function (values) { + ok(Array.isArray(values), "Resolved value should be an array."); + is( + values.length, + 4, + "Resolved array length should match iterable's length." + ); + is(values[0], 1, "Array values should match."); + is(values[1], 2, "Array values should match."); + is(values[2], 3, "Array values should match."); + is(values[3], 4, "Array values should match."); + runTest(); + }, + function () { + ok( + false, + "Promise.all shouldn't fail when iterable has no rejected Promises." + ); + runTest(); + } + ); +} + +function promiseAllRejectFails() { + var arr = [ + new Promise(function (resolve) { + setTimeout(resolve.bind(undefined, 1), 50); + }), + new Promise(function (resolve, reject) { + setTimeout(reject.bind(undefined, 2), 10); + }), + new Promise(function (resolve) { + setTimeout(resolve.bind(undefined, 3), 10); + }), + new Promise(function (resolve) { + setTimeout(resolve.bind(undefined, 4), 20); + }), + ]; + + var p = Promise.all(arr); + p.then( + function (values) { + ok( + false, + "Promise.all shouldn't resolve when iterable has rejected Promises." + ); + runTest(); + }, + function (e) { + ok( + true, + "Promise.all should reject when iterable has rejected Promises." + ); + is(e, 2, "Rejection value should match."); + runTest(); + } + ); +} + +function promiseRaceEmpty() { + var p = Promise.race([]); + ok(p instanceof Promise, "Should return a Promise."); + // An empty race never resolves! + runTest(); +} + +function promiseRaceValuesArray() { + var p = Promise.race([true, new Date(), 3]); + ok(p instanceof Promise, "Should return a Promise."); + p.then( + function (winner) { + is(winner, true, "First value should win."); + runTest(); + }, + function (err) { + ok(false, "Should not fail " + err + "."); + runTest(); + } + ); +} + +function promiseRacePromiseArray() { + var arr = [ + new Promise(function (resolve) { + resolve("first"); + }), + Promise.resolve("second"), + new Promise(function () {}), + new Promise(function (resolve) { + setTimeout(function () { + setTimeout(function () { + resolve("fourth"); + }, 0); + }, 0); + }), + ]; + + var p = Promise.race(arr); + p.then(function (winner) { + is(winner, "first", "First queued resolution should win the race."); + runTest(); + }); +} + +function promiseRaceReject() { + var p = Promise.race([ + Promise.reject(new Error("Fail bad!")), + new Promise(function (resolve) { + setTimeout(resolve, 0); + }), + ]); + + p.then( + function () { + ok(false, "Should not resolve when winning Promise rejected."); + runTest(); + }, + function (e) { + ok(true, "Should be rejected"); + ok(e instanceof Error, "Should reject with Error."); + ok(e.message == "Fail bad!", "Message should match."); + runTest(); + } + ); +} + +function promiseRaceThrow() { + var p = Promise.race([ + new Promise(function (resolve) { + nonExistent(); + }), + new Promise(function (resolve) { + setTimeout(resolve, 0); + }), + ]); + + p.then( + function () { + ok(false, "Should not resolve when winning Promise had an error."); + runTest(); + }, + function (e) { + ok(true, "Should be rejected"); + ok( + e instanceof ReferenceError, + "Should reject with ReferenceError for function nonExistent()." + ); + runTest(); + } + ); +} + +function promiseResolveArray() { + var p = Promise.resolve([1, 2, 3]); + ok(p instanceof Promise, "Should return a Promise."); + p.then(function (v) { + ok(Array.isArray(v), "Resolved value should be an Array"); + is(v.length, 3, "Length should match"); + is(v[0], 1, "Resolved value should match original"); + is(v[1], 2, "Resolved value should match original"); + is(v[2], 3, "Resolved value should match original"); + runTest(); + }); +} + +function promiseResolveThenable() { + var p = Promise.resolve({ + then(onFulfill, onReject) { + onFulfill(2); + }, + }); + ok(p instanceof Promise, "Should cast to a Promise."); + p.then( + function (v) { + is(v, 2, "Should resolve to 2."); + runTest(); + }, + function (e) { + ok(false, "promiseResolveThenable should've resolved"); + runTest(); + } + ); +} + +function promiseResolvePromise() { + var original = Promise.resolve(true); + var cast = Promise.resolve(original); + + ok(cast instanceof Promise, "Should cast to a Promise."); + is(cast, original, "Should return original Promise."); + cast.then(function (v) { + is(v, true, "Should resolve to true."); + runTest(); + }); +} + +// Bug 1009569. +// Ensure that thenables are run on a clean stack asynchronously. +// Test case adopted from +// https://gist.github.com/getify/d64bb01751b50ed6b281#file-bug1-js. +function promiseResolveThenableCleanStack() { + function immed(s) { + x++; + s(); + } + function incX() { + x++; + } + + var x = 0; + var thenable = { then: immed }; + var results = []; + + var p = Promise.resolve(thenable).then(incX); + results.push(x); + + // check what happens after all "next cycle" steps + // have had a chance to complete + setTimeout(function () { + // Result should be [0, 2] since `thenable` will be called async. + is(results[0], 0, "Expected thenable to be called asynchronously"); + // See Bug 1023547 comment 13 for why this check has to be gated on p. + p.then(function () { + results.push(x); + is(results[1], 2, "Expected thenable to be called asynchronously"); + runTest(); + }); + }, 1000); +} + +// Bug 1062323 +function promiseWrapperAsyncResolution() { + var p = new Promise(function (resolve, reject) { + resolve(); + }); + + var results = []; + var q = p + .then(function () { + results.push("1-1"); + }) + .then(function () { + results.push("1-2"); + }) + .then(function () { + results.push("1-3"); + }); + + var r = p + .then(function () { + results.push("2-1"); + }) + .then(function () { + results.push("2-2"); + }) + .then(function () { + results.push("2-3"); + }); + + Promise.all([q, r]).then( + function () { + var match = + results[0] == "1-1" && + results[1] == "2-1" && + results[2] == "1-2" && + results[3] == "2-2" && + results[4] == "1-3" && + results[5] == "2-3"; + ok(match, "Chained promises should resolve asynchronously."); + runTest(); + }, + function () { + ok(false, "promiseWrapperAsyncResolution: One of the promises failed."); + runTest(); + } + ); +} + +var tests = [ + promiseResolve, + promiseReject, + promiseException, + promiseAsync_TimeoutResolveThen, + promiseAsync_ResolveTimeoutThen, + promiseAsync_ResolveThenTimeout, + promiseAsync_SyncXHRAndImportScripts, + promiseDoubleThen, + promiseThenException, + promiseThenCatchThen, + promiseRejectThenCatchThen, + promiseRejectThenCatchThen2, + promiseRejectThenCatchExceptionThen, + promiseThenCatchOrderingResolve, + promiseThenCatchOrderingReject, + promiseNestedPromise, + promiseNestedNestedPromise, + promiseWrongNestedPromise, + promiseLoop, + promiseStaticReject, + promiseStaticResolve, + promiseResolveNestedPromise, + promiseResolveNoArg, + promiseRejectNoArg, + + promiseThenNoArg, + promiseThenUndefinedResolveFunction, + promiseThenNullResolveFunction, + promiseCatchNoArg, + promiseRejectNoHandler, + + promiseUtilitiesDefined, + + promiseAllArray, + promiseAllWaitsForAllPromises, + promiseAllRejectFails, + + promiseRaceEmpty, + promiseRaceValuesArray, + promiseRacePromiseArray, + promiseRaceReject, + promiseRaceThrow, + + promiseResolveArray, + promiseResolveThenable, + promiseResolvePromise, + + promiseResolveThenableCleanStack, + + promiseWrapperAsyncResolution, +]; + +function runTest() { + if (!tests.length) { + postMessage({ type: "finish" }); + return; + } + + var test = tests.shift(); + test(); +} + +onmessage = function () { + runTest(); +}; |