Skip to content

[await-dictionary] add runtime keyed Promise combinator tests#4932

Open
danialasaria wants to merge 5 commits intotc39:mainfrom
danialasaria:dasaria/await-dictionary-keyed-runtime-tests
Open

[await-dictionary] add runtime keyed Promise combinator tests#4932
danialasaria wants to merge 5 commits intotc39:mainfrom
danialasaria:dasaria/await-dictionary-keyed-runtime-tests

Conversation

@danialasaria
Copy link
Contributor

@danialasaria danialasaria commented Feb 18, 2026

Summary

This PR adds the first runtime/behavioral coverage for the await-dictionary proposal’s Promise keyed combinators:

  • Promise.allKeyed
  • Promise.allSettledKeyed

It follows the initial boilerplate-only PR and focuses on high-signal success/failure semantics and ordering behavior.

What this PR covers

Shared coverage for both methods

For both Promise.allKeyed and Promise.allSettledKeyed, this PR adds tests for:

  • rejecting when promises is not an Object (primitive matrix: undefined, null, number, string, boolean, symbol)
  • throwing when invoked with a non-constructor receiver (NewPromiseCapability path)
  • rejecting when the constructor’s resolve is non-callable (GetPromiseResolve / IfAbruptRejectPromise path)
  • resolving {} to an empty null-prototype result object
  • ignoring non-enumerable own properties
  • preserving output key order from property enumeration order (not settlement order)

Promise.allKeyed-specific

  • rejection from a synchronously rejected input promise
  • rejection from an asynchronously rejected input promise

Promise.allSettledKeyed-specific

  • all-fulfilled keyed results with { status: "fulfilled", value }
  • all-rejected keyed results with { status: "rejected", reason }
  • mixed fulfilled/rejected keyed results with correct per-key shapes

Notes

  • All tests are feature-gated with features: [await-dictionary].
  • New tests mirror existing naming/style patterns used in Promise/all and Promise/allSettled.
  • These tests intentionally validate keyed combinator result-object behavior (including null-prototype output), which differs from array-based combinators.

What this PR does not cover

This PR intentionally leaves some deeper edge paths for follow-up work, including:

  • constructor-throws / malformed promise capability variants
  • promiseResolve throwing or returning a non-thenable
  • exotic object abrupt completions in [[OwnPropertyKeys]] / [[GetOwnProperty]]
  • synchronous-thenable remainingElementsCount step-8 edge behavior
  • additional low-level closure/idempotency stress cases

References

Cover shared failure/success behavior for Promise.allKeyed and Promise.allSettledKeyed, including non-object rejection, non-constructor context, key ordering, and allSettled result-shape outcomes.
@danialasaria danialasaria force-pushed the dasaria/await-dictionary-keyed-runtime-tests branch from d6a6c31 to 50702d4 Compare February 23, 2026 16:22
Comment on lines +48 to +50
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.

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.

});
}

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!

…nt coverage

- Change key-order-preserved settle sequence to 2nd, 3rd, 1st to avoid false
  passes from reverse-order implementations
- Use Reflect.ownKeys instead of Object.keys in empty-object assertions for
  exhaustive own-key verification
- Add separate BigInt rejection tests gated behind BigInt feature flag
@danialasaria danialasaria force-pushed the dasaria/await-dictionary-keyed-runtime-tests branch from 607531a to 589f4da Compare February 26, 2026 19:20
@danialasaria danialasaria marked this pull request as ready for review March 2, 2026 17:00
@danialasaria danialasaria requested a review from a team as a code owner March 2, 2026 17:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants