Skip to content
Snippets Groups Projects
Commit 5279bcb1 authored by André Bargull's avatar André Bargull
Browse files

Improve test coverage for various Promise methods

parent fd44cd73
No related branches found
No related tags found
No related merge requests found
Showing
with 1195 additions and 0 deletions
// Copyright (C) 2015 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
es6id: 25.4.4.1.2
description: >
Cannot change result value of resolved Promise.all element after Promise.all() returned.
info: >
Promise.all Resolve Element Functions
1. Let alreadyCalled be the value of F's [[AlreadyCalled]] internal slot.
2. If alreadyCalled.[[value]] is true, return undefined.
3. Set alreadyCalled.[[value]] to true.
...
---*/
var callCount = 0;
var valuesArray;
function Constructor(executor) {
function resolve(values) {
callCount += 1;
valuesArray = values;
assert(Array.isArray(values), "values is array");
assert.sameValue(values.length, 1, "values.length");
assert.sameValue(values[0], "expectedValue", "values[0]");
}
executor(resolve, $ERROR);
}
Constructor.resolve = function(v) { return v; };
var p1OnFulfilled;
var p1 = {
then: function(onFulfilled, onRejected) {
p1OnFulfilled = onFulfilled;
onFulfilled("expectedValue");
}
};
assert.sameValue(callCount, 0, "callCount before call to all()");
Promise.all.call(Constructor, [p1]);
assert.sameValue(callCount, 1, "callCount after call to all()");
assert.sameValue(valuesArray[0], "expectedValue", "valuesArray after call to all()");
p1OnFulfilled("unexpectedValue");
assert.sameValue(callCount, 1, "callCount after call to onFulfilled()");
assert.sameValue(valuesArray[0], "expectedValue", "valuesArray after call to onFulfilled()");
// Copyright (C) 2015 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
es6id: 25.4.4.1.2
description: >
Cannot change result value of resolved Promise.all elements.
info: >
Promise.all Resolve Element Functions
1. Let alreadyCalled be the value of F's [[AlreadyCalled]] internal slot.
2. If alreadyCalled.[[value]] is true, return undefined.
3. Set alreadyCalled.[[value]] to true.
...
---*/
var callCount = 0;
function Constructor(executor) {
function resolve(values) {
callCount += 1;
assert(Array.isArray(values), "values is array");
assert.sameValue(values.length, 2, "values length");
assert.sameValue(values[0], "expectedValue-p1", "values[0]");
assert.sameValue(values[1], "expectedValue-p2", "values[1]");
}
executor(resolve, $ERROR);
}
Constructor.resolve = function(v) { return v; };
var p1 = {
then: function(onFulfilled, onRejected) {
onFulfilled("expectedValue-p1");
onFulfilled("unexpectedValue-p1");
}
};
var p2 = {
then: function(onFulfilled, onRejected) {
onFulfilled("expectedValue-p2");
onFulfilled("unexpectedValue-p2");
}
};
assert.sameValue(callCount, 0, "callCount before call to all()");
Promise.all.call(Constructor, [p1, p2]);
assert.sameValue(callCount, 1, "callCount after call to all()");
// Copyright (C) 2015 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
es6id: 25.4.4.1.2
description: >
Cannot change result value of resolved Promise.all element.
info: >
Promise.all Resolve Element Functions
1. Let alreadyCalled be the value of F's [[AlreadyCalled]] internal slot.
2. If alreadyCalled.[[value]] is true, return undefined.
3. Set alreadyCalled.[[value]] to true.
...
---*/
var callCount = 0;
function Constructor(executor) {
function resolve(values) {
callCount += 1;
assert(Array.isArray(values), "values is array");
assert.sameValue(values.length, 1, "values length");
assert.sameValue(values[0], "expectedValue", "values[0]");
}
executor(resolve, $ERROR);
}
Constructor.resolve = function(v) { return v; };
var p1 = {
then: function(onFulfilled, onRejected) {
onFulfilled("expectedValue");
onFulfilled("unexpectedValue");
}
};
assert.sameValue(callCount, 0, "callCount before call to all()");
Promise.all.call(Constructor, [p1]);
assert.sameValue(callCount, 1, "callCount after call to all()");
// Copyright (C) 2015 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
es6id: 25.4.4.1
description: >
Throws a TypeError if capabilities executor already called with non-undefined values.
info: >
Promise.all ( iterable )
...
6. Let promiseCapability be NewPromiseCapability(C).
7. ReturnIfAbrupt(promiseCapability).
...
25.4.1.5.1 GetCapabilitiesExecutor Functions
...
3. If promiseCapability.[[Resolve]] is not undefined, throw a TypeError exception.
4. If promiseCapability.[[Reject]] is not undefined, throw a TypeError exception.
5. Set promiseCapability.[[Resolve]] to resolve.
6. Set promiseCapability.[[Reject]] to reject.
...
---*/
var checkPoint = "";
Promise.all.call(function(executor) {
checkPoint += "a";
executor();
checkPoint += "b";
executor(function(){}, function(){});
checkPoint += "c";
}, []);
assert.sameValue(checkPoint, "abc", "executor initially called with no arguments");
var checkPoint = "";
Promise.all.call(function(executor) {
checkPoint += "a";
executor(undefined, undefined);
checkPoint += "b";
executor(function(){}, function(){});
checkPoint += "c";
}, []);
assert.sameValue(checkPoint, "abc", "executor initially called with (undefined, undefined)");
var checkPoint = "";
assert.throws(TypeError, function() {
Promise.all.call(function(executor) {
checkPoint += "a";
executor(undefined, function(){});
checkPoint += "b";
executor(function(){}, function(){});
checkPoint += "c";
}, []);
}, "executor initially called with (undefined, function)");
assert.sameValue(checkPoint, "ab", "executor initially called with (undefined, function)");
var checkPoint = "";
assert.throws(TypeError, function() {
Promise.all.call(function(executor) {
checkPoint += "a";
executor(function(){}, undefined);
checkPoint += "b";
executor(function(){}, function(){});
checkPoint += "c";
}, []);
}, "executor initially called with (function, undefined)");
assert.sameValue(checkPoint, "ab", "executor initially called with (function, undefined)");
var checkPoint = "";
assert.throws(TypeError, function() {
Promise.all.call(function(executor) {
checkPoint += "a";
executor("invalid value", 123);
checkPoint += "b";
executor(function(){}, function(){});
checkPoint += "c";
}, []);
}, "executor initially called with (String, Number)");
assert.sameValue(checkPoint, "ab", "executor initially called with (String, Number)");
// Copyright (C) 2015 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
es6id: 25.4.4.1
description: >
Throws a TypeError if either resolve or reject capability is not callable.
info: >
Promise.all ( iterable )
...
6. Let promiseCapability be NewPromiseCapability(C).
7. ReturnIfAbrupt(promiseCapability).
...
25.4.1.5 NewPromiseCapability ( C )
...
4. Let executor be a new built-in function object as defined in GetCapabilitiesExecutor Functions (25.4.1.5.1).
5. Set the [[Capability]] internal slot of executor to promiseCapability.
6. Let promise be Construct(C, «executor»).
7. ReturnIfAbrupt(promise).
8. If IsCallable(promiseCapability.[[Resolve]]) is false, throw a TypeError exception.
9. If IsCallable(promiseCapability.[[Reject]]) is false, throw a TypeError exception.
...
---*/
var checkPoint = "";
assert.throws(TypeError, function() {
Promise.all.call(function(executor) {
checkPoint += "a";
}, []);
}, "executor not called at all");
assert.sameValue(checkPoint, "a", "executor not called at all");
var checkPoint = "";
assert.throws(TypeError, function() {
Promise.all.call(function(executor) {
checkPoint += "a";
executor();
checkPoint += "b";
}, []);
}, "executor called with no arguments");
assert.sameValue(checkPoint, "ab", "executor called with no arguments");
var checkPoint = "";
assert.throws(TypeError, function() {
Promise.all.call(function(executor) {
checkPoint += "a";
executor(undefined, undefined);
checkPoint += "b";
}, []);
}, "executor called with (undefined, undefined)");
assert.sameValue(checkPoint, "ab", "executor called with (undefined, undefined)");
var checkPoint = "";
assert.throws(TypeError, function() {
Promise.all.call(function(executor) {
checkPoint += "a";
executor(undefined, function(){});
checkPoint += "b";
}, []);
}, "executor called with (undefined, function)");
assert.sameValue(checkPoint, "ab", "executor called with (undefined, function)");
var checkPoint = "";
assert.throws(TypeError, function() {
Promise.all.call(function(executor) {
checkPoint += "a";
executor(function(){}, undefined);
checkPoint += "b";
}, []);
}, "executor called with (function, undefined)");
assert.sameValue(checkPoint, "ab", "executor called with (function, undefined)");
var checkPoint = "";
assert.throws(TypeError, function() {
Promise.all.call(function(executor) {
checkPoint += "a";
executor(123, "invalid value");
checkPoint += "b";
}, []);
}, "executor called with (Number, String)");
assert.sameValue(checkPoint, "ab", "executor called with (Number, String)");
// Copyright (C) 2015 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
es6id: 25.4.4.1.1
description: >
Indexed setter properties on Array.prototype are not invoked.
info: >
Runtime Semantics: PerformPromiseAll( iteratorRecord, constructor, resultCapability)
...
4. Let remainingElementsCount be a new Record { [[value]]: 1 }.
...
6.d ...
ii. Set remainingElementsCount.[[value]] to remainingElementsCount.[[value]] − 1.
iii. If remainingElementsCount.[[value]] is 0,
1. Let valuesArray be CreateArrayFromList(values).
...
...
7.3.16 CreateArrayFromList (elements)
...
4. For each element e of elements
a. Let status be CreateDataProperty(array, ToString(n), e).
b. Assert: status is true.
...
---*/
Object.defineProperty(Array.prototype, 0, {
set: function() {
$ERROR("Setter on Array.prototype called");
}
});
Promise.all([42]).then(function(){ $DONE(); }, $DONE);
// Copyright (C) 2015 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
es6id: 25.4.4.1.1
description: >
Each Promise.all element is called with a new Promise.all Resolve Element function.
info: >
Runtime Semantics: PerformPromiseAll( iteratorRecord, constructor, resultCapability)
...
k. Let resolveElement be a new built-in function object as defined in Promise.all Resolve Element Functions.
...
r. Let result be Invoke(nextPromise, "then", «resolveElement, resultCapability.[[Reject]]»).
...
---*/
function resolveFunction() { }
function Constructor(executor) {
executor(resolveFunction, $ERROR);
}
Constructor.resolve = function(v) { return v; };
var callCount1 = 0, callCount2 = 0;
var p1OnFulfilled;
var p1 = {
then: function(onFulfilled, onRejected) {
callCount1 += 1;
p1OnFulfilled = onFulfilled;
assert.notSameValue(onFulfilled, resolveFunction, "p1.then");
}
};
var p2 = {
then: function(onFulfilled, onRejected) {
callCount2 += 1;
assert.notSameValue(onFulfilled, resolveFunction, "p2.then");
assert.notSameValue(onFulfilled, p1OnFulfilled, "p1.onFulfilled != p2.onFulfilled");
}
};
Promise.all.call(Constructor, [p1, p2]);
assert.sameValue(callCount1, 1, "p1.then call count");
assert.sameValue(callCount2, 1, "p2.then call count");
// Copyright (C) 2015 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
es6id: 25.4.4.1.1
description: >
Cannot tamper remainingElementsCount when Promise.all resolve element function is called twice in a row.
info: >
Runtime Semantics: PerformPromiseAll( iteratorRecord, constructor, resultCapability)
...
4. Let remainingElementsCount be a new Record { [[value]]: 1 }.
...
6.d ...
ii. Set remainingElementsCount.[[value]] to remainingElementsCount.[[value]] − 1.
iii. If remainingElementsCount.[[value]] is 0,
1. Let valuesArray be CreateArrayFromList(values).
2. Let resolveResult be Call(resultCapability.[[Resolve]], undefined, «valuesArray»).
3. ReturnIfAbrupt(resolveResult).
...
25.4.4.1.2 Promise.all Resolve Element Functions
1. Let alreadyCalled be the value of F's [[AlreadyCalled]] internal slot.
2. If alreadyCalled.[[value]] is true, return undefined.
3. Set alreadyCalled.[[value]] to true.
...
---*/
var callCount = 0;
function Constructor(executor) {
function resolve(values) {
callCount += 1;
assert(Array.isArray(values), "values is array");
assert.sameValue(values.length, 3, "values length");
assert.sameValue(values[0], "p1-fulfill", "values[0]");
assert.sameValue(values[1], "p2-fulfill", "values[1]");
assert.sameValue(values[2], "p3-fulfill", "values[2]");
}
executor(resolve, $ERROR);
}
Constructor.resolve = function(v) { return v; };
var p1OnFulfilled;
var p1 = {
then: function(onFulfilled, onRejected) {
p1OnFulfilled = onFulfilled;
}
};
var p2 = {
then: function(onFulfilled, onRejected) {
onFulfilled("p2-fulfill");
onFulfilled("p2-fulfill-unexpected");
}
};
var p3 = {
then: function(onFulfilled, onRejected) {
onFulfilled("p3-fulfill");
}
};
assert.sameValue(callCount, 0, "callCount before call to all()");
Promise.all.call(Constructor, [p1, p2, p3]);
assert.sameValue(callCount, 0, "callCount after call to all()");
p1OnFulfilled("p1-fulfill");
assert.sameValue(callCount, 1, "callCount after resolving p1");
// Copyright (C) 2015 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
es6id: 25.4.4.1.1
description: >
Cannot tamper remainingElementsCount when two Promise.all resolve element functions are called in succession.
info: >
Runtime Semantics: PerformPromiseAll( iteratorRecord, constructor, resultCapability)
...
4. Let remainingElementsCount be a new Record { [[value]]: 1 }.
...
6.d ...
ii. Set remainingElementsCount.[[value]] to remainingElementsCount.[[value]] − 1.
iii. If remainingElementsCount.[[value]] is 0,
1. Let valuesArray be CreateArrayFromList(values).
2. Let resolveResult be Call(resultCapability.[[Resolve]], undefined, «valuesArray»).
3. ReturnIfAbrupt(resolveResult).
...
25.4.4.1.2 Promise.all Resolve Element Functions
1. Let alreadyCalled be the value of F's [[AlreadyCalled]] internal slot.
2. If alreadyCalled.[[value]] is true, return undefined.
3. Set alreadyCalled.[[value]] to true.
...
---*/
var callCount = 0;
function Constructor(executor) {
function resolve(values) {
callCount += 1;
assert(Array.isArray(values), "values is array");
assert.sameValue(values.length, 3, "values length");
assert.sameValue(values[0], "p1-fulfill", "values[0]");
assert.sameValue(values[1], "p2-fulfill", "values[1]");
assert.sameValue(values[2], "p3-fulfill", "values[2]");
}
executor(resolve, $ERROR);
}
Constructor.resolve = function(v) { return v; };
var p1OnFulfilled;
var p1 = {
then: function(onFulfilled, onRejected) {
p1OnFulfilled = onFulfilled;
}
};
var p2 = {
then: function(onFulfilled, onRejected) {
p1OnFulfilled("p1-fulfill");
onFulfilled("p2-fulfill");
}
};
var p3 = {
then: function(onFulfilled, onRejected) {
onFulfilled("p3-fulfill");
}
};
assert.sameValue(callCount, 0, "callCount before call to all()");
Promise.all.call(Constructor, [p1, p2, p3]);
assert.sameValue(callCount, 1, "callCount after call to all()");
// Copyright (C) 2015 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
es6id: 25.4.4.1.1
description: >
Cannot tamper remainingElementsCount when Promise.all resolve element function is called multiple times.
info: >
Runtime Semantics: PerformPromiseAll( iteratorRecord, constructor, resultCapability)
...
4. Let remainingElementsCount be a new Record { [[value]]: 1 }.
...
6.d ...
ii. Set remainingElementsCount.[[value]] to remainingElementsCount.[[value]] − 1.
iii. If remainingElementsCount.[[value]] is 0,
1. Let valuesArray be CreateArrayFromList(values).
2. Let resolveResult be Call(resultCapability.[[Resolve]], undefined, «valuesArray»).
3. ReturnIfAbrupt(resolveResult).
...
25.4.4.1.2 Promise.all Resolve Element Functions
1. Let alreadyCalled be the value of F's [[AlreadyCalled]] internal slot.
2. If alreadyCalled.[[value]] is true, return undefined.
3. Set alreadyCalled.[[value]] to true.
...
---*/
var callCount = 0;
function Constructor(executor) {
function resolve(values) {
callCount += 1;
assert(Array.isArray(values, "values is array"));
assert.sameValue(values.length, 3, "values length");
assert.sameValue(values[0], "p1-fulfill", "values[0]");
assert.sameValue(values[1], "p2-fulfill", "values[1]");
assert.sameValue(values[2], "p3-fulfill", "values[2]");
}
executor(resolve, $ERROR);
}
Constructor.resolve = function(v) { return v; };
var p1OnFulfilled, p2OnFulfilled, p3OnFulfilled;
var p1 = {
then: function(onFulfilled, onRejected) {
p1OnFulfilled = onFulfilled;
}
};
var p2 = {
then: function(onFulfilled, onRejected) {
p2OnFulfilled = onFulfilled;
}
};
var p3 = {
then: function(onFulfilled, onRejected) {
p3OnFulfilled = onFulfilled;
}
};
assert.sameValue(callCount, 0, "callCount before call to all()");
Promise.all.call(Constructor, [p1, p2, p3]);
assert.sameValue(callCount, 0, "callCount after call to all()");
p1OnFulfilled("p1-fulfill");
p1OnFulfilled("p1-fulfill-unexpected-1");
p1OnFulfilled("p1-fulfill-unexpected-2");
assert.sameValue(callCount, 0, "callCount after resolving p1");
p2OnFulfilled("p2-fulfill");
p3OnFulfilled("p3-fulfill");
assert.sameValue(callCount, 1, "callCount after resolving all elements");
// Copyright (C) 2015 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
es6id: 25.4.4.1.1
description: >
Each Promise.all element is called with the same reject function.
info: >
Runtime Semantics: PerformPromiseAll( iteratorRecord, constructor, resultCapability)
...
r. Let result be Invoke(nextPromise, "then", «resolveElement, resultCapability.[[Reject]]»).
...
---*/
function rejectFunction() { }
function Constructor(executor) {
executor($ERROR, rejectFunction);
}
Constructor.resolve = function(v) { return v; };
var callCount1 = 0, callCount2 = 0;
var p1 = {
then: function(onFulfilled, onRejected) {
callCount1 += 1;
assert.sameValue(onRejected, rejectFunction, "p1.then");
}
};
var p2 = {
then: function(onFulfilled, onRejected) {
callCount2 += 1;
assert.sameValue(onRejected, rejectFunction, "p2.then");
}
};
Promise.all.call(Constructor, [p1, p2]);
assert.sameValue(callCount1, 1, "p1.then call count");
assert.sameValue(callCount2, 1, "p2.then call count");
// Copyright (C) 2015 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
es6id: 25.4.3.1
description: >
Already resolved promise is not rejected when executor throws an exception.
info: >
Promise ( executor )
...
8. Let resolvingFunctions be CreateResolvingFunctions(promise).
9. Let completion be Call(executor, undefined, «resolvingFunctions.[[Resolve]], resolvingFunctions.[[Reject]]»).
10. If completion is an abrupt completion, then
a. Let status be Call(resolvingFunctions.[[Reject]], undefined, «completion.[[value]]»).
b. ReturnIfAbrupt(status).
...
---*/
var thenable = {
then: function(resolve) {
resolve();
}
};
function executor(resolve, reject) {
resolve(thenable);
throw new Error("ignored exception");
}
new Promise(executor).then($DONE, $DONE);
// Copyright (C) 2015 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
es6id: 25.4.2.2
description: >
Already resolved promise is not rejected when then() function throws an exception.
info: >
PromiseResolveThenableJob ( promiseToResolve, thenable, then )
1. Let resolvingFunctions be CreateResolvingFunctions(promiseToResolve).
2. Let thenCallResult be Call(then, thenable, «resolvingFunctions.[[Resolve]], resolvingFunctions.[[Reject]]»).
3. If thenCallResult is an abrupt completion,
a. Let status be Call(resolvingFunctions.[[Reject]], undefined, «thenCallResult.[[value]]»)
b. NextJob Completion(status).
...
---*/
var thenable = {
then: function(resolve) {
resolve();
}
};
var thenableWithError = {
then: function(resolve) {
resolve(thenable);
throw new Error("ignored exception");
}
};
function executor(resolve, reject) {
resolve(thenableWithError);
}
new Promise(executor).then($DONE, $DONE);
// Copyright (C) 2015 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
es6id: 25.4.5.3
description: >
Throws a TypeError if capabilities executor already called with non-undefined values.
info: >
Promise.prototype.then ( onFulfilled , onRejected )
...
5. Let promiseCapability be NewPromiseCapability(C).
6. ReturnIfAbrupt(promiseCapability).
...
25.4.1.5.1 GetCapabilitiesExecutor Functions
...
3. If promiseCapability.[[Resolve]] is not undefined, throw a TypeError exception.
4. If promiseCapability.[[Reject]] is not undefined, throw a TypeError exception.
5. Set promiseCapability.[[Resolve]] to resolve.
6. Set promiseCapability.[[Reject]] to reject.
...
---*/
var constructorFunction;
var promise = new class extends Promise {
constructor(executor) {
if (constructorFunction) {
constructorFunction(executor);
return {};
}
return super(executor);
}
}(function(){});
var checkPoint = "";
constructorFunction = function(executor) {
checkPoint += "a";
executor();
checkPoint += "b";
executor(function(){}, function(){});
checkPoint += "c";
};
promise.then();
assert.sameValue(checkPoint, "abc", "executor initially called with no arguments");
var checkPoint = "";
constructorFunction = function(executor) {
checkPoint += "a";
executor(undefined, undefined);
checkPoint += "b";
executor(function(){}, function(){});
checkPoint += "c";
};
promise.then();
assert.sameValue(checkPoint, "abc", "executor initially called with (undefined, undefined)");
var checkPoint = "";
assert.throws(TypeError, function() {
constructorFunction = function(executor) {
checkPoint += "a";
executor(undefined, function(){});
checkPoint += "b";
executor(function(){}, function(){});
checkPoint += "c";
};
promise.then();
}, "executor initially called with (undefined, function)");
assert.sameValue(checkPoint, "ab", "executor initially called with (undefined, function)");
var checkPoint = "";
assert.throws(TypeError, function() {
constructorFunction = function(executor) {
checkPoint += "a";
executor(function(){}, undefined);
checkPoint += "b";
executor(function(){}, function(){});
checkPoint += "c";
};
promise.then();
}, "executor initially called with (function, undefined)");
assert.sameValue(checkPoint, "ab", "executor initially called with (function, undefined)");
var checkPoint = "";
assert.throws(TypeError, function() {
constructorFunction = function(executor) {
checkPoint += "a";
executor("invalid value", 123);
checkPoint += "b";
executor(function(){}, function(){});
checkPoint += "c";
};
promise.then();
}, "executor initially called with (String, Number)");
assert.sameValue(checkPoint, "ab", "executor initially called with (String, Number)");
// Copyright (C) 2015 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
es6id: 25.4.5.3
description: >
Throws a TypeError if either resolve or reject capability is not callable.
info: >
Promise.prototype.then ( onFulfilled , onRejected )
...
5. Let promiseCapability be NewPromiseCapability(C).
6. ReturnIfAbrupt(promiseCapability).
...
25.4.1.5 NewPromiseCapability ( C )
...
4. Let executor be a new built-in function object as defined in GetCapabilitiesExecutor Functions (25.4.1.5.1).
5. Set the [[Capability]] internal slot of executor to promiseCapability.
6. Let promise be Construct(C, «executor»).
7. ReturnIfAbrupt(promise).
8. If IsCallable(promiseCapability.[[Resolve]]) is false, throw a TypeError exception.
9. If IsCallable(promiseCapability.[[Reject]]) is false, throw a TypeError exception.
...
---*/
var constructorFunction;
var promise = new class extends Promise {
constructor(executor) {
if (constructorFunction) {
constructorFunction(executor);
return {};
}
return super(executor);
}
}(function(){});
var checkPoint = "";
assert.throws(TypeError, function() {
constructorFunction = function(executor) {
checkPoint += "a";
};
promise.then();
}, "executor not called at all");
assert.sameValue(checkPoint, "a", "executor not called at all");
var checkPoint = "";
assert.throws(TypeError, function() {
constructorFunction = function(executor) {
checkPoint += "a";
executor();
checkPoint += "b";
};
promise.then();
}, "executor called with no arguments");
assert.sameValue(checkPoint, "ab", "executor called with no arguments");
var checkPoint = "";
assert.throws(TypeError, function() {
constructorFunction = function(executor) {
checkPoint += "a";
executor(undefined, undefined);
checkPoint += "b";
};
promise.then();
}, "executor called with (undefined, undefined)");
assert.sameValue(checkPoint, "ab", "executor called with (undefined, undefined)");
var checkPoint = "";
assert.throws(TypeError, function() {
constructorFunction = function(executor) {
checkPoint += "a";
executor(undefined, function(){});
checkPoint += "b";
};
promise.then();
}, "executor called with (undefined, function)");
assert.sameValue(checkPoint, "ab", "executor called with (undefined, function)");
var checkPoint = "";
assert.throws(TypeError, function() {
constructorFunction = function(executor) {
checkPoint += "a";
executor(function(){}, undefined);
checkPoint += "b";
};
promise.then();
}, "executor called with (function, undefined)");
assert.sameValue(checkPoint, "ab", "executor called with (function, undefined)");
var checkPoint = "";
assert.throws(TypeError, function() {
constructorFunction = function(executor) {
checkPoint += "a";
executor(123, "invalid value");
checkPoint += "b";
};
promise.then();
}, "executor called with (Number, String)");
assert.sameValue(checkPoint, "ab", "executor called with (Number, String)");
// Copyright (C) 2015 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
es6id: 25.4.5.3
description: >
Throws a TypeError if `this` is not a Promise object.
info: >
Promise.prototype.then ( onFulfilled , onRejected )
1. Let promise be the this value.
2. If IsPromise(promise) is false, throw a TypeError exception.
...
---*/
var object = {
get constructor() {
$ERROR("get constructor called");
}
};
assert.throws(TypeError, function() {
Promise.prototype.then.call(object);
});
// Copyright (C) 2015 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
es6id: 25.4.5.3
description: >
Promise reaction jobs do not check for cyclic resolutions.
info: >
Promise.prototype.then ( onFulfilled , onRejected )
...
5. Let resultCapability be NewPromiseCapability(C).
6. ReturnIfAbrupt(resultCapability).
7. Return PerformPromiseThen(promise, onFulfilled, onRejected, resultCapability).
25.4.5.3.1 PerformPromiseThen ( promise, onFulfilled, onRejected, resultCapability )
...
3. If IsCallable(onFulfilled) is false, then
a. Let onFulfilled be "Identity".
4. If IsCallable(onRejected) is false, then
a. Let onRejected be "Thrower".
5. Let fulfillReaction be the PromiseReaction { [[Capabilities]]: resultCapability, [[Handler]]: onFulfilled }.
6. Let rejectReaction be the PromiseReaction { [[Capabilities]]: resultCapability, [[Handler]]: onRejected}.
...
8. Else if the value of promise's [[PromiseState]] internal slot is "fulfilled",
a. Let value be the value of promise's [[PromiseResult]] internal slot.
b. Perform EnqueueJob("PromiseJobs", PromiseReactionJob, «fulfillReaction, value»).
...
25.4.2.1 PromiseReactionJob ( reaction, argument )
...
4. If handler is "Identity", let handlerResult be NormalCompletion(argument).
...
8. Let status be Call(promiseCapability.[[Resolve]], undefined, «handlerResult.[[value]]»).
9. NextJob Completion(status).
---*/
var createBadPromise = false;
var object = {};
class P extends Promise {
constructor(executor) {
if (createBadPromise) {
executor(
function(v) {
assert.sameValue(v, object);
$DONE();
},
function(e) {
$DONE(e);
}
);
return object;
}
return super(executor);
}
}
var p = P.resolve(object);
createBadPromise = true;
var q = p.then();
createBadPromise = false;
assert.sameValue(q, object, "then() returns object");
// Copyright (C) 2015 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
es6id: 25.4.4.3
description: >
Throws a TypeError if capabilities executor already called with non-undefined values.
info: >
Promise.race ( iterable )
...
6. Let promiseCapability be NewPromiseCapability(C).
7. ReturnIfAbrupt(promiseCapability).
...
25.4.1.5.1 GetCapabilitiesExecutor Functions
...
3. If promiseCapability.[[Resolve]] is not undefined, throw a TypeError exception.
4. If promiseCapability.[[Reject]] is not undefined, throw a TypeError exception.
5. Set promiseCapability.[[Resolve]] to resolve.
6. Set promiseCapability.[[Reject]] to reject.
...
---*/
var checkPoint = "";
Promise.race.call(function(executor) {
checkPoint += "a";
executor();
checkPoint += "b";
executor(function(){}, function(){});
checkPoint += "c";
}, []);
assert.sameValue(checkPoint, "abc", "executor initially called with no arguments");
var checkPoint = "";
Promise.race.call(function(executor) {
checkPoint += "a";
executor(undefined, undefined);
checkPoint += "b";
executor(function(){}, function(){});
checkPoint += "c";
}, []);
assert.sameValue(checkPoint, "abc", "executor initially called with (undefined, undefined)");
var checkPoint = "";
assert.throws(TypeError, function() {
Promise.race.call(function(executor) {
checkPoint += "a";
executor(undefined, function(){});
checkPoint += "b";
executor(function(){}, function(){});
checkPoint += "c";
}, []);
}, "executor initially called with (undefined, function)");
assert.sameValue(checkPoint, "ab", "executor initially called with (undefined, function)");
var checkPoint = "";
assert.throws(TypeError, function() {
Promise.race.call(function(executor) {
checkPoint += "a";
executor(function(){}, undefined);
checkPoint += "b";
executor(function(){}, function(){});
checkPoint += "c";
}, []);
}, "executor initially called with (function, undefined)");
assert.sameValue(checkPoint, "ab", "executor initially called with (function, undefined)");
var checkPoint = "";
assert.throws(TypeError, function() {
Promise.race.call(function(executor) {
checkPoint += "a";
executor("invalid value", 123);
checkPoint += "b";
executor(function(){}, function(){});
checkPoint += "c";
}, []);
}, "executor initially called with (String, Number)");
assert.sameValue(checkPoint, "ab", "executor initially called with (String, Number)");
// Copyright (C) 2015 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
es6id: 25.4.4.3
description: >
Throws a TypeError if either resolve or reject capability is not callable.
info: >
Promise.race ( iterable )
...
6. Let promiseCapability be NewPromiseCapability(C).
7. ReturnIfAbrupt(promiseCapability).
...
25.4.1.5 NewPromiseCapability ( C )
...
4. Let executor be a new built-in function object as defined in GetCapabilitiesExecutor Functions (25.4.1.5.1).
5. Set the [[Capability]] internal slot of executor to promiseCapability.
6. Let promise be Construct(C, «executor»).
7. ReturnIfAbrupt(promise).
8. If IsCallable(promiseCapability.[[Resolve]]) is false, throw a TypeError exception.
9. If IsCallable(promiseCapability.[[Reject]]) is false, throw a TypeError exception.
...
---*/
var checkPoint = "";
assert.throws(TypeError, function() {
Promise.race.call(function(executor) {
checkPoint += "a";
}, []);
}, "executor not called at all");
assert.sameValue(checkPoint, "a", "executor not called at all");
var checkPoint = "";
assert.throws(TypeError, function() {
Promise.race.call(function(executor) {
checkPoint += "a";
executor();
checkPoint += "b";
}, []);
}, "executor called with no arguments");
assert.sameValue(checkPoint, "ab", "executor called with no arguments");
var checkPoint = "";
assert.throws(TypeError, function() {
Promise.race.call(function(executor) {
checkPoint += "a";
executor(undefined, undefined);
checkPoint += "b";
}, []);
}, "executor called with (undefined, undefined)");
assert.sameValue(checkPoint, "ab", "executor called with (undefined, undefined)");
var checkPoint = "";
assert.throws(TypeError, function() {
Promise.race.call(function(executor) {
checkPoint += "a";
executor(undefined, function(){});
checkPoint += "b";
}, []);
}, "executor called with (undefined, function)");
assert.sameValue(checkPoint, "ab", "executor called with (undefined, function)");
var checkPoint = "";
assert.throws(TypeError, function() {
Promise.race.call(function(executor) {
checkPoint += "a";
executor(function(){}, undefined);
checkPoint += "b";
}, []);
}, "executor called with (function, undefined)");
assert.sameValue(checkPoint, "ab", "executor called with (function, undefined)");
var checkPoint = "";
assert.throws(TypeError, function() {
Promise.race.call(function(executor) {
checkPoint += "a";
executor(123, "invalid value");
checkPoint += "b";
}, []);
}, "executor called with (Number, String)");
assert.sameValue(checkPoint, "ab", "executor called with (Number, String)");
// Copyright (C) 2015 André Bargull. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
es6id: 25.4.4.3.1
description: >
Each Promise.race element is called with the same reject function.
info: >
Runtime Semantics: PerformPromiseRace ( iteratorRecord, promiseCapability, C )
...
j. Let result be Invoke(nextPromise, "then", «promiseCapability.[[Resolve]], promiseCapability.[[Reject]]»).
...
---*/
function rejectFunction() { }
function Constructor(executor) {
executor($ERROR, rejectFunction);
}
Constructor.resolve = function(v) { return v; };
var callCount1 = 0, callCount2 = 0;
var p1 = {
then: function(onFulfilled, onRejected) {
callCount1 += 1;
assert.sameValue(onRejected, rejectFunction, "p1.then");
}
};
var p2 = {
then: function(onFulfilled, onRejected) {
callCount2 += 1;
assert.sameValue(onRejected, rejectFunction, "p2.then");
}
};
Promise.race.call(Constructor, [p1, p2]);
assert.sameValue(callCount1, 1, "p1.then call count");
assert.sameValue(callCount2, 1, "p2.then call count");
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment