зеркало из https://github.com/mozilla/gecko-dev.git
729 строки
19 KiB
HTML
729 строки
19 KiB
HTML
<!--
|
|
Any copyright is dedicated to the Public Domain.
|
|
http://creativecommons.org/publicdomain/zero/1.0/
|
|
-->
|
|
<html>
|
|
<head>
|
|
<title>Basic Promise Test</title>
|
|
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
|
</head>
|
|
<body>
|
|
<p id="display"></p>
|
|
<div id="content" style="display: none">
|
|
|
|
</div>
|
|
<pre id="test">
|
|
<script type="application/javascript"><!--
|
|
|
|
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 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 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 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 promiseGC() {
|
|
var resolve;
|
|
var promise = new Promise(function(r1, r2) {
|
|
resolve = r1;
|
|
}).then(function(what) {
|
|
ok(true, "Then - promise is still alive");
|
|
runTest();
|
|
});
|
|
|
|
promise = null;
|
|
|
|
SpecialPowers.gc();
|
|
SpecialPowers.forceGC();
|
|
SpecialPowers.forceCC();
|
|
|
|
resolve(42);
|
|
}
|
|
|
|
function promiseAsync() {
|
|
var global = "foo";
|
|
var f = new Promise(function(r1, r2) {
|
|
is(global, "foo", "Global should be foo");
|
|
r1(42);
|
|
is(global, "foo", "Global should still be foo");
|
|
setTimeout(function() {
|
|
is(global, "bar", "Global should still be bar!");
|
|
runTest();
|
|
}, 0);
|
|
}).then(function() {
|
|
global = "bar";
|
|
});
|
|
is(global, "foo", "Global should still be foo (2)");
|
|
}
|
|
|
|
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, "window.onerror 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 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 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 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(resolve, reject) {
|
|
ok(true, "Nested promise is executed");
|
|
resolve(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(resolve, reject) {
|
|
ok(true, "Nested promise is executed");
|
|
resolve(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(r1, r2) {
|
|
ok(true, "Nested nested promise is executed");
|
|
r1(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 promiseSimpleThenableResolve() {
|
|
var thenable = { then: function(resolve) { resolve(5); } };
|
|
var promise = new Promise(function(resolve, reject) {
|
|
resolve(thenable);
|
|
});
|
|
|
|
promise.then(function(v) {
|
|
ok(v === 5, "promiseSimpleThenableResolve");
|
|
runTest();
|
|
}, function(e) {
|
|
ok(false, "promiseSimpleThenableResolve: Should not reject");
|
|
});
|
|
}
|
|
|
|
function promiseSimpleThenableReject() {
|
|
var thenable = { then: function(resolve, reject) { reject(5); } };
|
|
var promise = new Promise(function(resolve, reject) {
|
|
resolve(thenable);
|
|
});
|
|
|
|
promise.then(function() {
|
|
ok(false, "promiseSimpleThenableReject: Should not resolve");
|
|
runTest();
|
|
}, function(e) {
|
|
ok(e === 5, "promiseSimpleThenableReject");
|
|
runTest();
|
|
});
|
|
}
|
|
|
|
function promiseThenableThrowsBeforeCallback() {
|
|
var thenable = { then: function(resolve) {
|
|
throw new TypeError("Hi there");
|
|
resolve(5);
|
|
}};
|
|
|
|
var promise = Promise.resolve(thenable);
|
|
promise.then(function(v) {
|
|
ok(false, "promiseThenableThrowsBeforeCallback: Should've rejected");
|
|
runTest();
|
|
}, function(e) {
|
|
ok(e instanceof TypeError, "promiseThenableThrowsBeforeCallback");
|
|
runTest();
|
|
});
|
|
}
|
|
|
|
function promiseThenableThrowsAfterCallback() {
|
|
var thenable = { then: function(resolve) {
|
|
resolve(5);
|
|
throw new TypeError("Hi there");
|
|
}};
|
|
|
|
var promise = Promise.resolve(thenable);
|
|
promise.then(function(v) {
|
|
ok(v === 5, "promiseThenableThrowsAfterCallback");
|
|
runTest();
|
|
}, function(e) {
|
|
ok(false, "promiseThenableThrowsAfterCallback: Should've resolved");
|
|
runTest();
|
|
});
|
|
}
|
|
|
|
function promiseThenableRejectThenResolve() {
|
|
var thenable = { then: function(resolve, reject) {
|
|
reject(new TypeError("Hi there"));
|
|
resolve(5);
|
|
}};
|
|
|
|
var promise = Promise.resolve(thenable);
|
|
promise.then(function(v) {
|
|
ok(false, "promiseThenableRejectThenResolve should have rejected");
|
|
runTest();
|
|
}, function(e) {
|
|
ok(e instanceof TypeError, "promiseThenableRejectThenResolve");
|
|
runTest();
|
|
});
|
|
}
|
|
|
|
function promiseWithThenReplaced() {
|
|
// Ensure that we call the 'then' on the promise and not the internal then.
|
|
var promise = new Promise(function(resolve, reject) {
|
|
resolve(5);
|
|
});
|
|
|
|
// Rogue `then` always rejects.
|
|
promise.then = function(onFulfill, onReject) {
|
|
onReject(new TypeError("Foo"));
|
|
}
|
|
|
|
var promise2 = Promise.resolve(promise);
|
|
promise2.then(function(v) {
|
|
ok(false, "promiseWithThenReplaced: Should've rejected");
|
|
runTest();
|
|
}, function(e) {
|
|
ok(e instanceof TypeError, "promiseWithThenReplaced");
|
|
runTest();
|
|
});
|
|
}
|
|
|
|
function promiseStrictHandlers() {
|
|
var promise = Promise.resolve(5);
|
|
promise.then(function() {
|
|
"use strict";
|
|
ok(this === undefined, "Strict mode callback should have this === undefined.");
|
|
runTest();
|
|
});
|
|
}
|
|
|
|
function promiseStrictExecutorThisArg() {
|
|
var promise = new Promise(function(resolve, reject) {
|
|
"use strict";
|
|
ok(this === undefined, "thisArg should be undefined.");
|
|
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: function(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 1008467 - Promise fails with "too much recursion".
|
|
// The bug was that the callbacks passed to a thenable would resolve the
|
|
// promise synchronously when the fulfill handler returned a non-thenable.
|
|
//
|
|
// For example:
|
|
// var p = new Promise(function(resolve) {
|
|
// resolve(5);
|
|
// });
|
|
// var m = Promise.resolve(p);
|
|
//
|
|
// At this point `m` is a Promise that is resolved with a thenable `p`, so it
|
|
// calls `p.then()` with two callbacks, both of which would synchronously resolve
|
|
// `m` when `p` invoked them (on account of itself being resolved, possibly
|
|
// synchronously. A chain of these 'Promise resolved by a Promise' would lead to
|
|
// stack overflow.
|
|
function promiseTestAsyncThenableResolution()
|
|
{
|
|
var k = 3000;
|
|
Promise.resolve().then(function next() {
|
|
k--;
|
|
if (k > 0) return Promise.resolve().then(next);
|
|
}).then(function () {
|
|
ok(true, "Resolution of a chain of thenables should not be synchronous.");
|
|
runTest();
|
|
});
|
|
}
|
|
|
|
var tests = [ promiseResolve, promiseReject,
|
|
promiseException, promiseGC, promiseAsync,
|
|
promiseDoubleThen, promiseThenException,
|
|
promiseThenCatchThen, promiseRejectThenCatchThen,
|
|
promiseRejectThenCatchThen2,
|
|
promiseRejectThenCatchExceptionThen,
|
|
promiseThenCatchOrderingResolve,
|
|
promiseThenCatchOrderingReject,
|
|
promiseNestedPromise, promiseNestedNestedPromise,
|
|
promiseWrongNestedPromise, promiseLoop,
|
|
promiseStaticReject, promiseStaticResolve,
|
|
promiseResolveNestedPromise,
|
|
promiseResolveNoArg,
|
|
promiseRejectNoArg,
|
|
promiseThenNoArg,
|
|
promiseThenUndefinedResolveFunction,
|
|
promiseThenNullResolveFunction,
|
|
promiseCatchNoArg,
|
|
promiseRejectNoHandler,
|
|
promiseSimpleThenableResolve,
|
|
promiseSimpleThenableReject,
|
|
promiseThenableThrowsBeforeCallback,
|
|
promiseThenableThrowsAfterCallback,
|
|
promiseThenableRejectThenResolve,
|
|
promiseWithThenReplaced,
|
|
promiseStrictHandlers,
|
|
promiseStrictExecutorThisArg,
|
|
promiseResolveArray,
|
|
promiseResolveThenable,
|
|
promiseResolvePromise,
|
|
promiseResolveThenableCleanStack,
|
|
promiseTestAsyncThenableResolution,
|
|
];
|
|
|
|
function runTest() {
|
|
if (!tests.length) {
|
|
SimpleTest.finish();
|
|
return;
|
|
}
|
|
|
|
var test = tests.shift();
|
|
test();
|
|
}
|
|
|
|
SimpleTest.waitForExplicitFinish();
|
|
runTest();
|
|
// -->
|
|
</script>
|
|
</pre>
|
|
</body>
|
|
</html>
|
|
|