Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright (C) 2026 Alistair Smith. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: >
Resolving with a native Promise whose `constructor[Symbol.species]`
getter throws, after invocation of the executor function
esid: sec-newpromiseresolvethenablejob
info: |
NewPromiseResolveThenableJob ( promiseToResolve, thenable, then )

1. Let job be a new Job Abstract Closure with no parameters that captures
promiseToResolve, thenable, and then and performs the following steps
when called:
a. Let resolvingFuncs be CreateResolvingFunctions(promiseToResolve).
b. Let thenCallResult be Completion(HostCallJobCallback(then, thenable,
« resolvingFuncs.[[Resolve]], resolvingFuncs.[[Reject]] »)).
c. If thenCallResult is an abrupt completion, then
i. Return ? Call(resolvingFuncs.[[Reject]], undefined,
« thenCallResult.[[Value]] »).
d. Return ! thenCallResult.

Promise.prototype.then ( onFulfilled, onRejected )

1. Let promise be the this value.
2. If IsPromise(promise) is false, throw a TypeError exception.
3. Let ctor be ? SpeciesConstructor(promise, %Promise%).
flags: [async]
includes: [asyncHelpers.js]
features: [Symbol.species]
---*/

var returnValue = null;
var value = {};
var resolve;
var thenable = Promise.resolve();
thenable.constructor = {};
Object.defineProperty(thenable.constructor, Symbol.species, {
get: function() {
throw value;
}
});
var promise = new Promise(function(_resolve) {
resolve = _resolve;
});

asyncTest(function() {
return promise.then(function() {
throw new Test262Error('The promise should not be fulfilled.');
}, function(val) {
assert.sameValue(val, value, 'The promise should be rejected with the thrown value.');
});
});

returnValue = resolve(thenable);

assert.sameValue(returnValue, undefined, '"resolve" return value');
54 changes: 54 additions & 0 deletions test/built-ins/Promise/resolve-prms-poisoned-species-immed.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright (C) 2026 Alistair Smith. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: >
Resolving with a native Promise whose `constructor[Symbol.species]`
getter throws, from within the executor function
esid: sec-newpromiseresolvethenablejob
info: |
NewPromiseResolveThenableJob ( promiseToResolve, thenable, then )

1. Let job be a new Job Abstract Closure with no parameters that captures
promiseToResolve, thenable, and then and performs the following steps
when called:
a. Let resolvingFuncs be CreateResolvingFunctions(promiseToResolve).
b. Let thenCallResult be Completion(HostCallJobCallback(then, thenable,
« resolvingFuncs.[[Resolve]], resolvingFuncs.[[Reject]] »)).
c. If thenCallResult is an abrupt completion, then
i. Return ? Call(resolvingFuncs.[[Reject]], undefined,
« thenCallResult.[[Value]] »).
d. Return ! thenCallResult.

Promise.prototype.then ( onFulfilled, onRejected )

1. Let promise be the this value.
2. If IsPromise(promise) is false, throw a TypeError exception.
3. Let ctor be ? SpeciesConstructor(promise, %Promise%).
flags: [async]
includes: [asyncHelpers.js]
features: [Symbol.species]
---*/

var returnValue = null;
var value = {};
var thenable = Promise.resolve();
thenable.constructor = {};
Object.defineProperty(thenable.constructor, Symbol.species, {
get: function() {
throw value;
}
});

var promise = new Promise(function(resolve) {
returnValue = resolve(thenable);
});

assert.sameValue(returnValue, undefined, '"resolve" return value');

asyncTest(function() {
return promise.then(function() {
throw new Test262Error('The promise should not be fulfilled.');
}, function(val) {
assert.sameValue(val, value, 'The promise should be rejected with the thrown value.');
});
});
47 changes: 47 additions & 0 deletions test/built-ins/Promise/resolve-thenable-then-throws-deferred.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (C) 2026 Alistair Smith. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: >
Resolving with a thenable whose `then` method throws before settling the
promise, after invocation of the executor function
esid: sec-newpromiseresolvethenablejob
info: |
NewPromiseResolveThenableJob ( promiseToResolve, thenable, then )

1. Let job be a new Job Abstract Closure with no parameters that captures
promiseToResolve, thenable, and then and performs the following steps
when called:
a. Let resolvingFuncs be CreateResolvingFunctions(promiseToResolve).
b. Let thenCallResult be Completion(HostCallJobCallback(then, thenable,
« resolvingFuncs.[[Resolve]], resolvingFuncs.[[Reject]] »)).
c. If thenCallResult is an abrupt completion, then
i. Return ? Call(resolvingFuncs.[[Reject]], undefined,
« thenCallResult.[[Value]] »).
d. Return ! thenCallResult.
flags: [async]
includes: [asyncHelpers.js]
---*/

var returnValue = null;
var value = {};
var resolve;
var thenable = {
then: function() {
throw value;
}
};
var promise = new Promise(function(_resolve) {
resolve = _resolve;
});

asyncTest(function() {
return promise.then(function() {
throw new Test262Error('The promise should not be fulfilled.');
}, function(val) {
assert.sameValue(val, value, 'The promise should be rejected with the thrown value.');
});
});

returnValue = resolve(thenable);

assert.sameValue(returnValue, undefined, '"resolve" return value');
45 changes: 45 additions & 0 deletions test/built-ins/Promise/resolve-thenable-then-throws-immed.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (C) 2026 Alistair Smith. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: >
Resolving with a thenable whose `then` method throws before settling the
promise, from within the executor function
esid: sec-newpromiseresolvethenablejob
info: |
NewPromiseResolveThenableJob ( promiseToResolve, thenable, then )

1. Let job be a new Job Abstract Closure with no parameters that captures
promiseToResolve, thenable, and then and performs the following steps
when called:
a. Let resolvingFuncs be CreateResolvingFunctions(promiseToResolve).
b. Let thenCallResult be Completion(HostCallJobCallback(then, thenable,
« resolvingFuncs.[[Resolve]], resolvingFuncs.[[Reject]] »)).
c. If thenCallResult is an abrupt completion, then
i. Return ? Call(resolvingFuncs.[[Reject]], undefined,
« thenCallResult.[[Value]] »).
d. Return ! thenCallResult.
flags: [async]
includes: [asyncHelpers.js]
---*/

var returnValue = null;
var value = {};
var thenable = {
then: function() {
throw value;
}
};

var promise = new Promise(function(resolve) {
returnValue = resolve(thenable);
});

assert.sameValue(returnValue, undefined, '"resolve" return value');

asyncTest(function() {
return promise.then(function() {
throw new Test262Error('The promise should not be fulfilled.');
}, function(val) {
assert.sameValue(val, value, 'The promise should be rejected with the thrown value.');
});
});