Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions test/built-ins/Promise/allKeyed/arg-not-object-reject.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright (C) 2026 Danial Asaria (Bloomberg LP). All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-promise.allkeyed
description: >
Promise.allKeyed rejects when the promises argument is not an Object
info: |
Promise.allKeyed ( promises )

...
5. If promises is not an Object, then
a. Let error be a newly created TypeError object.
b. Perform ? Call(promiseCapability.[[Reject]], undefined, « error »).
c. Return promiseCapability.[[Promise]].
flags: [async]
features: [await-dictionary, Symbol]
---*/

function checkRejects(value) {
return Promise.allKeyed(value).then(function() {
throw new Test262Error('The promise should be rejected for ' + typeof value);
}, function(error) {
assert(error instanceof TypeError, 'rejects with TypeError for ' + typeof value);
});
}

checkRejects(undefined)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what the precedent is here, but it should also reject for a BigInt. The test currently tests all other primitives. I presume it might be to make the test work for engines that don't support BigInt - if so maybe we can have a separate test or feature detect them?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a separate arg-not-object-reject-bigint.js test file with a features: [BigInt] flag so engines without BigInt support aren't gated!

.then(function() { return checkRejects(null); })
.then(function() { return checkRejects(86); })
.then(function() { return checkRejects('string'); })
.then(function() { return checkRejects(true); })
.then(function() { return checkRejects(Symbol()); })
.then($DONE, $DONE);
22 changes: 22 additions & 0 deletions test/built-ins/Promise/allKeyed/ctx-non-ctor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (C) 2026 Danial Asaria (Bloomberg LP). All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-promise.allkeyed
description: >
Promise.allKeyed invoked on a non-constructor value
info: |
Promise.allKeyed ( promises )

1. Let C be the this value.
2. Let promiseCapability be ? NewPromiseCapability(C).

NewPromiseCapability ( C )

1. If IsConstructor(C) is false, throw a TypeError exception.
features: [await-dictionary]
---*/

assert.throws(TypeError, function() {
Promise.allKeyed.call(eval);
});
58 changes: 58 additions & 0 deletions test/built-ins/Promise/allKeyed/key-order-preserved.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright (C) 2026 Danial Asaria (Bloomberg LP). All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-performpromiseallkeyed
description: >
Promise.allKeyed result key order matches property key order, not settlement order
info: |
PerformPromiseAllKeyed ( variant, promises, constructor, resultCapability, promiseResolve )

...
1. Let allKeys be ? promises.[[OwnPropertyKeys]]().
...
6. For each element key of allKeys, do
...
b. If desc is not undefined and desc.[[Enumerable]] is true, then
...
ii. Append key to keys.
...
...
...
8. If remainingElementsCount.[[Value]] = 0, then
...
b. Let result be CreateKeyedPromiseCombinatorResultObject(keys, values).
includes: [compareArray.js]
flags: [async]
features: [await-dictionary]
---*/

var resolveFirst;
var resolveSecond;
var resolveThird;

var input = {
first: new Promise(function(resolve) {
resolveFirst = resolve;
}),
second: new Promise(function(resolve) {
resolveSecond = resolve;
}),
third: new Promise(function(resolve) {
resolveThird = resolve;
})
};

var combined = Promise.allKeyed(input);

resolveThird('third');
resolveSecond('second');
resolveFirst('first');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it would be better to resolve 2nd, 3rd, 1st. To avoid the test passing for an incorrect implementation that adds them in reverse resolved order (e.g. it stores them in a stack and then pops them off).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call — changed to resolve in 2nd, 3rd, 1st order so a stack-based implementation wouldn't accidentally pass.


combined.then(function(result) {
assert.sameValue(Object.getPrototypeOf(result), null);
assert.compareArray(Object.keys(result), ['first', 'second', 'third']);
assert.sameValue(result.first, 'first');
assert.sameValue(result.second, 'second');
assert.sameValue(result.third, 'third');
}).then($DONE, $DONE);
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (C) 2026 Danial Asaria (Bloomberg LP). All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-performpromiseallkeyed
description: >
Promise.allKeyed ignores non-enumerable own properties
info: |
PerformPromiseAllKeyed ( variant, promises, constructor, resultCapability, promiseResolve )

...
6. For each element key of allKeys, do
a. Let desc be ? promises.[[GetOwnProperty]](key).
b. If desc is not undefined and desc.[[Enumerable]] is true, then
...
includes: [compareArray.js]
flags: [async]
features: [await-dictionary]
---*/

var input = {
visible: Promise.resolve(2)
};

Object.defineProperty(input, 'hidden', {
enumerable: false,
value: Promise.resolve(1)
});

Promise.allKeyed(input).then(function(result) {
assert.sameValue(Object.getPrototypeOf(result), null);
assert.compareArray(Object.keys(result), ['visible']);
assert.sameValue(result.visible, 2);
assert.sameValue(Object.prototype.hasOwnProperty.call(result, 'hidden'), false);
}).then($DONE, $DONE);
36 changes: 36 additions & 0 deletions test/built-ins/Promise/allKeyed/reject-deferred.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (C) 2026 Danial Asaria (Bloomberg LP). All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-performpromiseallkeyed
description: Rejecting from an asynchronously rejected input promise
info: |
PerformPromiseAllKeyed ( variant, promises, constructor, resultCapability, promiseResolve )

...
6. For each element key of allKeys, do
...
b. If desc is not undefined and desc.[[Enumerable]] is true, then
...
8. If variant is all, then
a. Let onRejected be resultCapability.[[Reject]].
...
11. Perform ? Invoke(nextPromise, "then", « onFulfilled, onRejected »).
flags: [async]
features: [await-dictionary]
---*/

var error = new Test262Error();

var p = new Promise(function(_, reject) {
Promise.resolve().then(function() {
reject(error);
});
});

Promise.allKeyed({ key: p })
.then(function() {
throw new Test262Error('The promise should not be fulfilled.');
}, function(reason) {
assert.sameValue(reason, error);
}).then($DONE, $DONE);
34 changes: 34 additions & 0 deletions test/built-ins/Promise/allKeyed/reject-immed.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright (C) 2026 Danial Asaria (Bloomberg LP). All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-performpromiseallkeyed
description: Rejecting from a synchronously rejected input promise
info: |
PerformPromiseAllKeyed ( variant, promises, constructor, resultCapability, promiseResolve )

...
6. For each element key of allKeys, do
...
b. If desc is not undefined and desc.[[Enumerable]] is true, then
...
8. If variant is all, then
a. Let onRejected be resultCapability.[[Reject]].
...
11. Perform ? Invoke(nextPromise, "then", « onFulfilled, onRejected »).
flags: [async]
features: [await-dictionary]
---*/

var error = new Test262Error();

var p = new Promise(function(_, reject) {
reject(error);
});

Promise.allKeyed({ key: p })
.then(function() {
throw new Test262Error('The promise should not be fulfilled.');
}, function(reason) {
assert.sameValue(reason, error);
}).then($DONE, $DONE);
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright (C) 2026 Danial Asaria (Bloomberg LP). All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-promise.allkeyed
description: >
If the constructor's `resolve` method is not callable, reject with a TypeError.
info: |
Promise.allKeyed ( promises )

...
3. Let promiseResolve be Completion(GetPromiseResolve(C)).
4. IfAbruptRejectPromise(promiseResolve, promiseCapability).
...

GetPromiseResolve ( promiseConstructor )

...
3. If IsCallable(promiseResolve) is false, throw a TypeError exception.
flags: [async]
features: [await-dictionary]
---*/

Promise.resolve = null;

Promise.allKeyed({ key: 1 })
.then(
function() {
$DONE('The promise should not be resolved.');
},
function(error) {
assert(error instanceof TypeError);
}
).then($DONE, $DONE);
27 changes: 27 additions & 0 deletions test/built-ins/Promise/allKeyed/resolves-empty-object.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (C) 2026 Danial Asaria (Bloomberg LP). All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-performpromiseallkeyed
description: >
Promise.allKeyed resolves an empty object to an empty null-prototype object
info: |
PerformPromiseAllKeyed ( variant, promises, constructor, resultCapability, promiseResolve )

...
1. Let allKeys be ? promises.[[OwnPropertyKeys]]().
...
7. Set remainingElementsCount.[[Value]] to remainingElementsCount.[[Value]] - 1.
8. If remainingElementsCount.[[Value]] = 0, then
a. Let result be CreateKeyedPromiseCombinatorResultObject(keys, values).
b. Perform ? Call(resultCapability.[[Resolve]], undefined, « result »).
includes: [compareArray.js]
flags: [async]
features: [await-dictionary]
---*/

Promise.allKeyed({}).then(function(result) {
assert.sameValue(Object.getPrototypeOf(result), null);
assert.sameValue(result.hasOwnProperty, undefined);
assert.compareArray(Object.keys(result), []);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what the precedent here is, but I'm wondering if it would be better to use Reflect.allKeys or Object.getOwnPropertyDescriptors as these are exhaustive whereas Object.keys will ignore non-enumerable and symbol keys.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think so too! Switched to Reflect.ownKeys which covers non-enumerable and symbol keys as well.

}).then($DONE, $DONE);
34 changes: 34 additions & 0 deletions test/built-ins/Promise/allSettledKeyed/arg-not-object-reject.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright (C) 2026 Danial Asaria (Bloomberg LP). All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-promise.allsettledkeyed
description: >
Promise.allSettledKeyed rejects when the promises argument is not an Object
info: |
Promise.allSettledKeyed ( promises )

...
5. If promises is not an Object, then
a. Let error be a newly created TypeError object.
b. Perform ? Call(promiseCapability.[[Reject]], undefined, « error »).
c. Return promiseCapability.[[Promise]].
flags: [async]
features: [await-dictionary, Symbol]
---*/

function checkRejects(value) {
return Promise.allSettledKeyed(value).then(function() {
throw new Test262Error('The promise should be rejected for ' + typeof value);
}, function(error) {
assert(error instanceof TypeError, 'rejects with TypeError for ' + typeof value);
});
}

checkRejects(undefined)
.then(function() { return checkRejects(null); })
.then(function() { return checkRejects(86); })
.then(function() { return checkRejects('string'); })
.then(function() { return checkRejects(true); })
.then(function() { return checkRejects(Symbol()); })
.then($DONE, $DONE);
22 changes: 22 additions & 0 deletions test/built-ins/Promise/allSettledKeyed/ctx-non-ctor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (C) 2026 Danial Asaria (Bloomberg LP). All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-promise.allsettledkeyed
description: >
Promise.allSettledKeyed invoked on a non-constructor value
info: |
Promise.allSettledKeyed ( promises )

1. Let C be the this value.
2. Let promiseCapability be ? NewPromiseCapability(C).

NewPromiseCapability ( C )

1. If IsConstructor(C) is false, throw a TypeError exception.
features: [await-dictionary]
---*/

assert.throws(TypeError, function() {
Promise.allSettledKeyed.call(eval);
});
Loading