Issue #2089 - Implement the Promise.any combinator

Based-on: m-c 1568903/9,1560300
This commit is contained in:
Martok 2023-01-27 20:44:09 +01:00 committed by roytam1
commit f75e9d9441
9 changed files with 577 additions and 50 deletions

View file

@ -0,0 +1,69 @@
// |reftest| skip-if(!Promise.any)
function toMessage(stack) {
// Provide the stack string in the error message for debugging.
return `[stack: ${stack.replace(/\n/g, "\\n")}]`;
}
// Test when AggregateError isn't created from a Promise Job.
{
let p = Promise.any([]); // line 10
p.then(v => {
reportCompare(0, 1, "expected error");
}, e => {
assertEq(e.name, "AggregateError");
var {stack} = e;
assertEq(/^@.+any-stack.js:10/m.test(stack), true, toMessage(stack));
});
}
// Same as above, but now with surrounding function context.
function testNoJobQueue() {
let p = Promise.any([]); // line 24
p.then(v => {
reportCompare(0, 1, "expected error");
}, e => {
assertEq(e.name, "AggregateError");
var {stack} = e;
assertEq(/^testNoJobQueue@.+any-stack.js:24/m.test(stack), true, toMessage(stack));
});
}
testNoJobQueue();
// Test when AggregateError is created from a Promise Job.
{
let rejected = Promise.reject(0);
let p = Promise.any([rejected]); // line 40
p.then(v => {
reportCompare(0, 1, "expected error");
}, e => {
assertEq(e.name, "AggregateError");
var {stack} = e;
assertEq(/^Promise.any\*@.+any-stack.js:40/m.test(stack), true, toMessage(stack));
});
}
// Same as above, but now with surrounding function context.
function testFromJobQueue() {
let rejected = Promise.reject(0);
let p = Promise.any([rejected]); // line 55
p.then(v => {
reportCompare(0, 1, "expected error");
}, e => {
assertEq(e.name, "AggregateError");
var {stack} = e;
assertEq(/^Promise.any\*testFromJobQueue@.+any-stack.js:55/m.test(stack), true, toMessage(stack));
});
}
testFromJobQueue();
if (typeof reportCompare === "function")
reportCompare(0, 0);

View file

@ -0,0 +1,78 @@
// |reftest| skip-if(!Promise.any)
// Smoke test for `Promise.any`, test262 should cover the function in
// more detail.
function expectedError() {
reportCompare(true, false, "expected error");
}
// Empty elements.
Promise.any([]).then(expectedError, e => {
assertEq(e instanceof AggregateError, true);
assertEq(e.errors.length, 0);
});
// Single element.
Promise.any([Promise.resolve(0)]).then(v => {
assertEq(v, 0);
});
Promise.any([Promise.reject(1)]).then(expectedError, e => {
assertEq(e instanceof AggregateError, true);
assertEq(e.errors.length, 1);
assertEq(e.errors[0], 1);
});
// Multiple elements.
Promise.any([Promise.resolve(1), Promise.resolve(2)]).then(v => {
assertEq(v, 1);
});
Promise.any([Promise.resolve(3), Promise.reject(4)]).then(v => {
assertEq(v, 3);
});
Promise.any([Promise.reject(5), Promise.resolve(6)]).then(v => {
assertEq(v, 6);
});
Promise.any([Promise.reject(7), Promise.reject(8)]).then(expectedError, e => {
assertEq(e instanceof AggregateError, true);
assertEq(e.errors.length, 2);
assertEq(e.errors[0], 7);
assertEq(e.errors[1], 8);
});
// Cross-Realm tests.
//
// Note: When |g| is a cross-compartment global, Promise.any creates the errors
// array and the AggregateError in |g|'s Realm. This doesn't follow the spec, but
// the code in js/src/builtin/Promise.cpp claims this is useful when the Promise
// compartment is less-privileged. This means for this test we can't use
// assertDeepEq below, because the result array/error may have the wrong prototype.
let g = newGlobal();
if (typeof isSameCompartment !== "function") {
var isSameCompartment = SpecialPowers.Cu.getJSTestingFunctions().isSameCompartment;
}
// Test wrapping when no `Promise.any Reject Element Function` is called.
Promise.any.call(g.Promise, []).then(expectedError, e => {
assertEq(e.name, "AggregateError");
assertEq(isSameCompartment(e, g), true);
assertEq(isSameCompartment(e.errors, g), true);
assertEq(e.errors.length, 0);
});
// Test wrapping in `Promise.any Reject Element Function`.
Promise.any.call(g.Promise, [Promise.reject("err")]).then(expectedError, e => {
assertEq(e.name, "AggregateError");
assertEq(isSameCompartment(e, g), true);
assertEq(isSameCompartment(e.errors, g), true);
assertEq(e.errors.length, 1);
assertEq(e.errors[0], "err");
});
if (typeof reportCompare === "function")
reportCompare(0, 0);