promise-zy
Version:
A simple implementation of Promies/A+
941 lines (928 loc) • 77.7 kB
Plain Text
2.1.2.1: When fulfilled, a promise: must not transition to any other state.
√ already-fulfilled
√ immediately-fulfilled
√ eventually-fulfilled
√ trying to fulfill then immediately reject
√ trying to fulfill then reject, delayed
√ trying to fulfill immediately then reject delayed
2.1.3.1: When rejected, a promise: must not transition to any other state.
√ already-rejected
√ immediately-rejected
√ eventually-rejected
√ trying to reject then immediately fulfill
√ trying to reject then fulfill, delayed
√ trying to reject immediately then fulfill delayed
2.2.1: Both `onFulfilled` and `onRejected` are optional arguments.
2.2.1.1: If `onFulfilled` is not a function, it must be ignored.
applied to a directly-rejected promise
√ `onFulfilled` is `undefined`
√ `onFulfilled` is `null`
√ `onFulfilled` is `false`
√ `onFulfilled` is `5`
√ `onFulfilled` is an object
applied to a promise rejected and then chained off of
√ `onFulfilled` is `undefined`
√ `onFulfilled` is `null`
√ `onFulfilled` is `false`
√ `onFulfilled` is `5`
√ `onFulfilled` is an object
2.2.1.2: If `onRejected` is not a function, it must be ignored.
applied to a directly-fulfilled promise
√ `onRejected` is `undefined`
√ `onRejected` is `null`
√ `onRejected` is `false`
√ `onRejected` is `5`
√ `onRejected` is an object
applied to a promise fulfilled and then chained off of
√ `onFulfilled` is `undefined`
√ `onFulfilled` is `null`
√ `onFulfilled` is `false`
√ `onFulfilled` is `5`
√ `onFulfilled` is an object
2.2.2: If `onFulfilled` is a function,
2.2.2.1: it must be called after `promise` is fulfilled, with `promise`’s fu lfillment value as its first argument.
√ already-fulfilled
√ immediately-fulfilled
√ eventually-fulfilled
2.2.2.2: it must not be called before `promise` is fulfilled
√ fulfilled after a delay
√ never fulfilled
2.2.2.3: it must not be called more than once.
√ already-fulfilled
√ trying to fulfill a pending promise more than once, immediately
√ trying to fulfill a pending promise more than once, delayed
√ trying to fulfill a pending promise more than once, immediately then del ayed
√ when multiple `then` calls are made, spaced apart in time
√ when `then` is interleaved with fulfillment
2.2.3: If `onRejected` is a function,
2.2.3.1: it must be called after `promise` is rejected, with `promise`’s rej ection reason as its first argument.
√ already-rejected
√ immediately-rejected
√ eventually-rejected
2.2.3.2: it must not be called before `promise` is rejected
√ rejected after a delay
√ never rejected
2.2.3.3: it must not be called more than once.
√ already-rejected
√ trying to reject a pending promise more than once, immediately
√ trying to reject a pending promise more than once, delayed
√ trying to reject a pending promise more than once, immediately then dela yed
√ when multiple `then` calls are made, spaced apart in time
√ when `then` is interleaved with rejection
2.2.4: `onFulfilled` or `onRejected` must not be called until the execution co ntext stack contains only platform code.
`then` returns before the promise becomes fulfilled or rejected
√ already-fulfilled
√ immediately-fulfilled
√ eventually-fulfilled
√ already-rejected
√ immediately-rejected
√ eventually-rejected
Clean-stack execution ordering tests (fulfillment case)
√ when `onFulfilled` is added immediately before the promise is fulfilled
√ when `onFulfilled` is added immediately after the promise is fulfilled
√ when one `onFulfilled` is added inside another `onFulfilled`
√ when `onFulfilled` is added inside an `onRejected`
√ when the promise is fulfilled asynchronously
Clean-stack execution ordering tests (rejection case)
√ when `onRejected` is added immediately before the promise is rejected
√ when `onRejected` is added immediately after the promise is rejected
√ when `onRejected` is added inside an `onFulfilled`
√ when one `onRejected` is added inside another `onRejected`
√ when the promise is rejected asynchronously
2.2.5 `onFulfilled` and `onRejected` must be called as functions (i.e. with no `this` value).
strict mode
√ fulfilled
√ rejected
sloppy mode
√ fulfilled
√ rejected
2.2.6: `then` may be called multiple times on the same promise.
2.2.6.1: If/when `promise` is fulfilled, all respective `onFulfilled` callba cks must execute in the order of their originating calls to `then`.
multiple boring fulfillment handlers
√ already-fulfilled
√ immediately-fulfilled
√ eventually-fulfilled
multiple fulfillment handlers, one of which throws
√ already-fulfilled
√ immediately-fulfilled
√ eventually-fulfilled
results in multiple branching chains with their own fulfillment values
√ already-fulfilled
√ immediately-fulfilled
√ eventually-fulfilled
`onFulfilled` handlers are called in the original order
√ already-fulfilled
√ immediately-fulfilled
√ eventually-fulfilled
even when one handler is added inside another handler
√ already-fulfilled
√ immediately-fulfilled
√ eventually-fulfilled
2.2.6.2: If/when `promise` is rejected, all respective `onRejected` callbacks must execute in the order of their originating calls to `then`.
multiple boring rejection handlers
√ already-rejected
√ immediately-rejected
√ eventually-rejected
multiple rejection handlers, one of which throws
√ already-rejected
√ immediately-rejected
√ eventually-rejected
results in multiple branching chains with their own fulfillment values
√ already-rejected
√ immediately-rejected
√ eventually-rejected
`onRejected` handlers are called in the original order
√ already-rejected
√ immediately-rejected
√ eventually-rejected
even when one handler is added inside another handler
√ already-rejected
√ immediately-rejected
√ eventually-rejected
2.2.7: `then` must return a promise: `promise2 = promise1.then(onFulfilled, onRejected)`
√ is a promise
2.2.7.1: If either `onFulfilled` or `onRejected` returns a value `x`, run the Promise Resolution Procedure `[[Resolve]](promise2, x)`
√ see separate 3.3 tests
2.2.7.2: If either `onFulfilled` or `onRejected` throws an exception `e`, `promise2` must be rejected with `e` as the reason.
The reason is `undefined`
√ already-fulfilled
√ immediately-fulfilled
√ eventually-fulfilled
√ already-rejected
√ immediately-rejected
√ eventually-rejected
The reason is `null`
√ already-fulfilled
√ immediately-fulfilled
√ eventually-fulfilled
√ already-rejected
√ immediately-rejected
√ eventually-rejected
The reason is `false`
√ already-fulfilled
√ immediately-fulfilled
√ eventually-fulfilled
√ already-rejected
√ immediately-rejected
√ eventually-rejected
The reason is `0`
√ already-fulfilled
√ immediately-fulfilled
√ eventually-fulfilled
√ already-rejected
√ immediately-rejected
√ eventually-rejected
The reason is an error
√ already-fulfilled
√ immediately-fulfilled
√ eventually-fulfilled
√ already-rejected
√ immediately-rejected
√ eventually-rejected
The reason is an error without a stack
√ already-fulfilled
√ immediately-fulfilled
√ eventually-fulfilled
√ already-rejected
√ immediately-rejected
√ eventually-rejected
The reason is a date
√ already-fulfilled
√ immediately-fulfilled
√ eventually-fulfilled
√ already-rejected
√ immediately-rejected
√ eventually-rejected
The reason is an object
√ already-fulfilled
√ immediately-fulfilled
√ eventually-fulfilled
√ already-rejected
√ immediately-rejected
√ eventually-rejected
The reason is an always-pending thenable
√ already-fulfilled
√ immediately-fulfilled
√ eventually-fulfilled
√ already-rejected
√ immediately-rejected
√ eventually-rejected
The reason is a fulfilled promise
√ already-fulfilled
√ immediately-fulfilled
√ eventually-fulfilled
√ already-rejected
√ immediately-rejected
√ eventually-rejected
The reason is a rejected promise
√ already-fulfilled
√ immediately-fulfilled
√ eventually-fulfilled
√ already-rejected
√ immediately-rejected
√ eventually-rejected
2.2.7.3: If `onFulfilled` is not a function and `promise1` is fulfilled, `promise2` must be fulfilled with the same value.
`onFulfilled` is `undefined`
√ already-fulfilled
√ immediately-fulfilled
√ eventually-fulfilled
`onFulfilled` is `null`
√ already-fulfilled
√ immediately-fulfilled
√ eventually-fulfilled
`onFulfilled` is `false`
√ already-fulfilled
√ immediately-fulfilled
√ eventually-fulfilled
`onFulfilled` is `5`
√ already-fulfilled
√ immediately-fulfilled
√ eventually-fulfilled
`onFulfilled` is an object
√ already-fulfilled
√ immediately-fulfilled
√ eventually-fulfilled
`onFulfilled` is an array containing a function
√ already-fulfilled
√ immediately-fulfilled
√ eventually-fulfilled
2.2.7.4: If `onRejected` is not a function and `promise1` is rejected, `promise2` must be rejected with the same reason.
`onRejected` is `undefined`
√ already-rejected
√ immediately-rejected
√ eventually-rejected
`onRejected` is `null`
√ already-rejected
√ immediately-rejected
√ eventually-rejected
`onRejected` is `false`
√ already-rejected
√ immediately-rejected
√ eventually-rejected
`onRejected` is `5`
√ already-rejected
√ immediately-rejected
√ eventually-rejected
`onRejected` is an object
√ already-rejected
√ immediately-rejected
√ eventually-rejected
`onRejected` is an array containing a function
√ already-rejected
√ immediately-rejected
√ eventually-rejected
2.3.1: If `promise` and `x` refer to the same object, reject `promise` with a `TypeError' as the reason.
√ via return from a fulfilled promise
√ via return from a rejected promise
2.3.2: If `x` is a promise, adopt its state
2.3.2.1: If `x` is pending, `promise` must remain pending until `x` is fulfilled or rejected.
√ via return from a fulfilled promise
√ via return from a rejected promise
2.3.2.2: If/when `x` is fulfilled, fulfill `promise` with the same value.
`x` is already-fulfilled
√ via return from a fulfilled promise
√ via return from a rejected promise
`x` is eventually-fulfilled
√ via return from a fulfilled promise
√ via return from a rejected promise
2.3.2.3: If/when `x` is rejected, reject `promise` with the same reason.
`x` is already-rejected
√ via return from a fulfilled promise
√ via return from a rejected promise
`x` is eventually-rejected
√ via return from a fulfilled promise
√ via return from a rejected promise
2.3.3: Otherwise, if `x` is an object or function,
2.3.3.1: Let `then` be `x.then`
`x` is an object with null prototype
√ via return from a fulfilled promise
√ via return from a rejected promise
`x` is an object with normal Object.prototype
√ via return from a fulfilled promise
√ via return from a rejected promise
`x` is a function
√ via return from a fulfilled promise
√ via return from a rejected promise
2.3.3.2: If retrieving the property `x.then` results in a thrown exception `e`, reject `promise` with `e` as the reason.
`e` is `undefined`
√ via return from a fulfilled promise
√ via return from a rejected promise
`e` is `null`
√ via return from a fulfilled promise
√ via return from a rejected promise
`e` is `false`
√ via return from a fulfilled promise
√ via return from a rejected promise
`e` is `0`
√ via return from a fulfilled promise
√ via return from a rejected promise
`e` is an error
√ via return from a fulfilled promise
√ via return from a rejected promise
`e` is an error without a stack
√ via return from a fulfilled promise
√ via return from a rejected promise
`e` is a date
√ via return from a fulfilled promise
√ via return from a rejected promise
`e` is an object
√ via return from a fulfilled promise
√ via return from a rejected promise
`e` is an always-pending thenable
√ via return from a fulfilled promise
√ via return from a rejected promise
`e` is a fulfilled promise
√ via return from a fulfilled promise
√ via return from a rejected promise
`e` is a rejected promise
√ via return from a fulfilled promise
√ via return from a rejected promise
2.3.3.3: If `then` is a function, call it with `x` as `this`, first argument `resolvePromise`, and second argument `rejectPromise`
Calls with `x` as `this` and two function arguments
√ via return from a fulfilled promise
√ via return from a rejected promise
Uses the original value of `then`
√ via return from a fulfilled promise
√ via return from a rejected promise
2.3.3.3.1: If/when `resolvePromise` is called with value `y`, run `[[Resolve]](promise, y)`
`y` is not a thenable
`y` is `undefined`
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is `null`
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is `false`
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is `5`
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is an object
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is an array
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a thenable
`y` is a synchronously-fulfilled custom thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is an asynchronously-fulfilled custom thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a synchronously-fulfilled one-time thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a thenable that tries to fulfill twice
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a thenable that fulfills but then throws
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is an already-fulfilled promise
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is an eventually-fulfilled promise
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a synchronously-rejected custom thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is an asynchronously-rejected custom thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a synchronously-rejected one-time thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a thenable that immediately throws in `then`
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is an object with a throwing `then` accessor
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is an already-rejected promise
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is an eventually-rejected promise
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a thenable for a thenable
`y` is a synchronously-fulfilled custom thenable for a synchronously-fulfilled custom thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a synchronously-fulfilled custom thenable for an asynchronously-fulfilled custom thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a synchronously-fulfilled custom thenable for a synchronously-fulfilled one-time thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a synchronously-fulfilled custom thenable for a thenable that tries to fulfill twice
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a synchronously-fulfilled custom thenable for a thenable that fulfills but then throws
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a synchronously-fulfilled custom thenable for an already-fulfilled promise
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a synchronously-fulfilled custom thenable for an eventually-fulfilled promise
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a synchronously-fulfilled custom thenable for a synchronously-rejected custom thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a synchronously-fulfilled custom thenable for an asynchronously-rejected custom thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a synchronously-fulfilled custom thenable for a synchronously-rejected one-time thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a synchronously-fulfilled custom thenable for a thenable that immediately throws in `then`
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a synchronously-fulfilled custom thenable for an object with a throwing `then` accessor
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a synchronously-fulfilled custom thenable for an already-rejected promise
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a synchronously-fulfilled custom thenable for an eventually-rejected promise
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is an asynchronously-fulfilled custom thenable for a synchronously-fulfilled custom thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is an asynchronously-fulfilled custom thenable for an asynchronously-fulfilled custom thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is an asynchronously-fulfilled custom thenable for a synchronously-fulfilled one-time thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is an asynchronously-fulfilled custom thenable for a thenable that tries to fulfill twice
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is an asynchronously-fulfilled custom thenable for a thenable that fulfills but then throws
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is an asynchronously-fulfilled custom thenable for an already-fulfilled promise
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is an asynchronously-fulfilled custom thenable for an eventually-fulfilled promise
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is an asynchronously-fulfilled custom thenable for a synchronously-rejected custom thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is an asynchronously-fulfilled custom thenable for an asynchronously-rejected custom thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is an asynchronously-fulfilled custom thenable for a synchronously-rejected one-time thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is an asynchronously-fulfilled custom thenable for a thenable that immediately throws in `then`
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is an asynchronously-fulfilled custom thenable for an object with a throwing `then` accessor
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is an asynchronously-fulfilled custom thenable for an already-rejected promise
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is an asynchronously-fulfilled custom thenable for an eventually-rejected promise
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a synchronously-fulfilled one-time thenable for a synchronously-fulfilled custom thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a synchronously-fulfilled one-time thenable for an asynchronously-fulfilled custom thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a synchronously-fulfilled one-time thenable for a synchronously-fulfilled one-time thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a synchronously-fulfilled one-time thenable for a thenable that tries to fulfill twice
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a synchronously-fulfilled one-time thenable for a thenable that fulfills but then throws
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a synchronously-fulfilled one-time thenable for an already-fulfilled promise
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a synchronously-fulfilled one-time thenable for an eventually-fulfilled promise
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a synchronously-fulfilled one-time thenable for a synchronously-rejected custom thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a synchronously-fulfilled one-time thenable for an asynchronously-rejected custom thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a synchronously-fulfilled one-time thenable for a synchronously-rejected one-time thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a synchronously-fulfilled one-time thenable for a thenable that immediately throws in `then`
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a synchronously-fulfilled one-time thenable for an object with a throwing `then` accessor
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a synchronously-fulfilled one-time thenable for an already-rejected promise
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a synchronously-fulfilled one-time thenable for an eventually-rejected promise
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a thenable that tries to fulfill twice for a synchronously-fulfilled custom thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a thenable that tries to fulfill twice for an asynchronously-fulfilled custom thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a thenable that tries to fulfill twice for a synchronously-fulfilled one-time thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a thenable that tries to fulfill twice for a thenable that tries to fulfill twice
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a thenable that tries to fulfill twice for a thenable that fulfills but then throws
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a thenable that tries to fulfill twice for an already-fulfilled promise
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a thenable that tries to fulfill twice for an eventually-fulfilled promise
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a thenable that tries to fulfill twice for a synchronously-rejected custom thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a thenable that tries to fulfill twice for an asynchronously-rejected custom thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a thenable that tries to fulfill twice for a synchronously-rejected one-time thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a thenable that tries to fulfill twice for a thenable that immediately throws in `then`
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a thenable that tries to fulfill twice for an object with a throwing `then` accessor
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a thenable that tries to fulfill twice for an already-rejected promise
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a thenable that tries to fulfill twice for an eventually-rejected promise
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a thenable that fulfills but then throws for a synchronously-fulfilled custom thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a thenable that fulfills but then throws for an asynchronously-fulfilled custom thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a thenable that fulfills but then throws for a synchronously-fulfilled one-time thenable
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a thenable that fulfills but then throws for a thenable that tries to fulfill twice
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a thenable that fulfills but then throws for a thenable that fulfills but then throws
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a thenable that fulfills but then throws for an already-fulfilled promise
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`then` calls `resolvePromise` asynchronously
√ via return from a fulfilled promise
√ via return from a rejected promise
`y` is a thenable that fulfills but then throws for an eventually-fulfilled promise
`then` calls `resolvePromise` synchronously
√ via return from a fulfilled promise
√ via return from a rejected promise