Bug 1298414 - Properly handle resolve/reject callbacks on xray'd promises. r=bz,efaust

MozReview-Commit-ID: H9dppdKlRG6
This commit is contained in:
Till Schneidereit 2016-11-03 19:07:33 +01:00
parent 6375d2a38e
commit a14435c813
3 changed files with 92 additions and 1 deletions

View File

@ -229,6 +229,19 @@ function testResolve3() {
).then(nextTest);
}
function testResolve4() {
var p = new win.Promise((res, rej) => {});
Components.utils.getJSTestingFunctions().resolvePromise(p, 42);
p.then(
function(arg) {
is(arg, 42, "Resolving an Xray to a promise with TestingFunctions resolvePromise should work");
},
function(e) {
ok(false, "Resolving an Xray to a promise with TestingFunctions resolvePromise should not fail");
}
).then(nextTest);
}
function testReject1() {
var p = win.Promise.reject(5);
ok(p instanceof win.Promise, "Promise.reject should return a promise");
@ -242,6 +255,19 @@ function testReject1() {
).then(nextTest);
}
function testReject2() {
var p = new win.Promise((res, rej) => {});
Components.utils.getJSTestingFunctions().rejectPromise(p, 42);
p.then(
function(arg) {
ok(false, "Rejecting an Xray to a promise with TestingFunctions rejectPromise should trigger catch handler");
},
function(e) {
is(e, 42, "Rejecting an Xray to a promise with TestingFunctions rejectPromise should work");
}
).then(nextTest);
}
function testThen1() {
var p = win.Promise.resolve(5);
var q = p.then((x) => x*x);
@ -314,7 +340,9 @@ var tests = [
testResolve1,
testResolve2,
testResolve3,
testResolve4,
testReject1,
testReject2,
testThen1,
testThen2,
testCatch1,

View File

@ -1039,8 +1039,11 @@ GetResolveFunctionFromPromise(PromiseObject* promise)
if (rejectFunVal.isUndefined())
return nullptr;
JSObject* rejectFunObj = &rejectFunVal.toObject();
// We can safely unwrap it because all we want is to get the resolve
// function.
if (IsWrapper(rejectFunObj))
rejectFunObj = CheckedUnwrap(rejectFunObj);
rejectFunObj = UncheckedUnwrap(rejectFunObj);
if (!rejectFunObj->is<JSFunction>())
return nullptr;

View File

@ -1493,6 +1493,60 @@ GetWaitForAllPromise(JSContext* cx, unsigned argc, Value* vp)
return true;
}
static bool
ResolvePromise(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (!args.requireAtLeast(cx, "resolvePromise", 2))
return false;
if (!args[0].isObject() || !UncheckedUnwrap(&args[0].toObject())->is<PromiseObject>()) {
JS_ReportErrorASCII(cx, "first argument must be a maybe-wrapped Promise object");
return false;
}
RootedObject promise(cx, &args[0].toObject());
RootedValue resolution(cx, args[1]);
mozilla::Maybe<AutoCompartment> ac;
if (IsWrapper(promise)) {
promise = UncheckedUnwrap(promise);
ac.emplace(cx, promise);
if (!cx->compartment()->wrap(cx, &resolution))
return false;
}
bool result = JS::ResolvePromise(cx, promise, resolution);
if (result)
args.rval().setUndefined();
return result;
}
static bool
RejectPromise(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (!args.requireAtLeast(cx, "rejectPromise", 2))
return false;
if (!args[0].isObject() || !UncheckedUnwrap(&args[0].toObject())->is<PromiseObject>()) {
JS_ReportErrorASCII(cx, "first argument must be a maybe-wrapped Promise object");
return false;
}
RootedObject promise(cx, &args[0].toObject());
RootedValue reason(cx, args[1]);
mozilla::Maybe<AutoCompartment> ac;
if (IsWrapper(promise)) {
promise = UncheckedUnwrap(promise);
ac.emplace(cx, promise);
if (!cx->compartment()->wrap(cx, &reason))
return false;
}
bool result = JS::RejectPromise(cx, promise, reason);
if (result)
args.rval().setUndefined();
return result;
}
#else
static const js::Class FakePromiseClass = {
@ -4148,6 +4202,12 @@ static const JSFunctionSpecWithHelp TestingFunctions[] = {
"getWaitForAllPromise(densePromisesArray)",
" Calls the 'GetWaitForAllPromise' JSAPI function and returns the result\n"
" Promise."),
JS_FN_HELP("resolvePromise", ResolvePromise, 2, 0,
"resolvePromise(promise, resolution)",
" Resolve a Promise by calling the JSAPI function JS::ResolvePromise."),
JS_FN_HELP("rejectPromise", RejectPromise, 2, 0,
"rejectPromise(promise, reason)",
" Reject a Promise by calling the JSAPI function JS::RejectPromise."),
#else
JS_FN_HELP("makeFakePromise", MakeFakePromise, 0, 0,
"makeFakePromise()",