Skip to content

Commit

Permalink
Promise.prototype.finally: add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ljharb committed Jul 26, 2017
1 parent d7e69e9 commit ed366ef
Show file tree
Hide file tree
Showing 16 changed files with 475 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright (C) 2017 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
author: Jordan Harband
description: Promise.prototype.finally invokes `then` method
esid: sec-promise.prototype.finally
features: [Promise, Promise.prototype.finally]
---*/

var target = new Promise(function () {});
var returnValue = {};
var callCount = 0;
var thisValue = null;
var argCount = null;
var firstArg = null;
var secondArg = null;

target.then = function(a, b) {
callCount += 1;

thisValue = this;
argCount = arguments.length;
firstArg = a;
secondArg = b;

return returnValue;
};

var originalFinallyHandler = function () {};

var result = Promise.prototype.finally.call(target, originalFinallyHandler, 2, 3);

assert.sameValue(callCount, 1, 'Invokes `then` method exactly once');
assert.sameValue(
thisValue,
target,
'Invokes `then` method with the instance as the `this` value'
);
assert.sameValue(argCount, 2, 'Invokes `then` method with exactly two single arguments');
assert.sameValue(
typeof firstArg,
'function',
'Invokes `then` method with a function as the first argument'
);
assert.notSameValue(firstArg, originalFinallyHandler, 'Invokes `then` method with a different fulfillment handler');
assert.sameValue(
typeof secondArg,
'function',
'Invokes `then` method with a function as the second argument'
);
assert.notSameValue(secondArg, originalFinallyHandler, 'Invokes `then` method with a different fulfillment handler');

assert.sameValue(result, returnValue, 'Returns the result of the invocation of `then`');
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (C) 2017 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
author: Jordan Harband
description: Promise.prototype.finally invokes `then` method
esid: sec-promise.prototype.finally
features: [Promise, Promise.prototype.finally]
---*/

var target = new Promise(function () {});
var returnValue = {};
var callCount = 0;
var thisValue = null;
var argCount = null;
var firstArg = null;
var secondArg = null;
var result = null;

target.then = function(a, b) {
callCount += 1;

thisValue = this;
argCount = arguments.length;
firstArg = a;
secondArg = b;

return returnValue;
};

result = Promise.prototype.finally.call(target, 1, 2, 3);

assert.sameValue(callCount, 1, 'Invokes `then` method exactly once');
assert.sameValue(
thisValue,
target,
'Invokes `then` method with the instance as the `this` value'
);
assert.sameValue(argCount, 2, 'Invokes `then` method with exactly two single arguments');
assert.sameValue(
firstArg,
1,
'Invokes `then` method with the provided non-callable first argument'
);
assert.sameValue(
secondArg,
1,
'Invokes `then` method with the provided non-callable first argument'
);
assert.sameValue(result, returnValue, 'Returns the result of the invocation of `then`');
20 changes: 20 additions & 0 deletions test/built-ins/Promise/prototype/finally/is-a-function.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright (C) 2017 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
author: Jordan Harband
description: Promise.prototype.finally is a function
esid: sec-promise.prototype.finally
features: [Promise.prototype.finally]
---*/

assert.sameValue(
Promise.prototype.finally instanceof Function,
true,
'Expected Promise.prototype.finally to be instanceof Function'
);

assert.sameValue(
typeof Promise.prototype.finally,
'function',
'Expected Promise.prototype.finally to be a function'
);
16 changes: 16 additions & 0 deletions test/built-ins/Promise/prototype/finally/is-a-method.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (C) 2017 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
author: Jordan Harband
description: finally is a method on a Promise
esid: sec-promise.prototype.finally
features: [Promise.resolve, Promise.prototype.finally]
---*/

var p = Promise.resolve(3);

assert.sameValue(
p.finally,
Promise.prototype.finally,
'Expected the `finally` method on a Promise to be `Promise.prototype.finally`'
);
27 changes: 27 additions & 0 deletions test/built-ins/Promise/prototype/finally/length.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (C) 2017 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
author: Jordan Harband
description: Promise.prototype.finally `length` property
esid: sec-promise.prototype.finally
info: >
ES6 Section 17:
Every built-in Function object, including constructors, has a length
property whose value is an integer. Unless otherwise specified, this value
is equal to the largest number of named arguments shown in the subclause
headings for the function description, including optional parameters.
[...]
Unless otherwise specified, the length property of a built-in Function
object has the attributes { [[Writable]]: false, [[Enumerable]]: false,
[[Configurable]]: true }.
includes: [propertyHelper.js]
features: [Promise.prototype.finally, Function.prototype.length]
---*/

assert.sameValue(Promise.prototype.finally.length, 1);

verifyNotEnumerable(Promise.prototype.finally, 'length');
verifyNotWritable(Promise.prototype.finally, 'length');
verifyConfigurable(Promise.prototype.finally, 'length');
28 changes: 28 additions & 0 deletions test/built-ins/Promise/prototype/finally/name.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (C) 2017 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
author: Jordan Harband
description: Promise.prototype.finally `name` property
esid: sec-promise.prototype.finally
info: >
ES6 Section 17:
Every built-in Function object, including constructors, that is not
identified as an anonymous function has a name property whose value is a
String. Unless otherwise specified, this value is the name that is given to
the function in this specification.
[...]
Unless otherwise specified, the name property of a built-in Function
object, if it exists, has the attributes { [[Writable]]: false,
[[Enumerable]]: false, [[Configurable]]: true }.
includes: [propertyHelper.js]
features: [Promise.prototype.finally, Function.prototype.name]
---*/

assert.sameValue(Promise.prototype.finally.name, 'finally');

verifyNotEnumerable(Promise.prototype.finally, 'name');
verifyNotWritable(Promise.prototype.finally, 'name');
verifyConfigurable(Promise.prototype.finally, 'name');
19 changes: 19 additions & 0 deletions test/built-ins/Promise/prototype/finally/prop-desc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (C) 2017 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
author: Jordan Harband
description: Promise.prototype.finally property descriptor
esid: sec-promise.prototype.finally
info: >
Every other data property described in clauses 18 through 26 and in Annex
B.2 has the attributes { [[Writable]]: true, [[Enumerable]]: false,
[[Configurable]]: true } unless otherwise specified.
includes: [propertyHelper.js]
features: [Promise.prototype.finally]
---*/

assert.sameValue(typeof Promise.prototype.finally, 'function');

verifyNotEnumerable(Promise.prototype, 'finally');
verifyWritable(Promise.prototype, 'finally');
verifyConfigurable(Promise.prototype, 'finally');
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (C) 2017 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
author: Jordan Harband
description: finally observably calls .then
esid: sec-promise.prototype.finally
features: [Promise.resolve, Promise.reject, Promise.prototype.finally]
flags: [async]
---*/

var initialThenCount = 0;
var noReason = {};
var no = Promise.reject(noReason);
no.then = function () {
initialThenCount += 1;
return Promise.prototype.then.apply(this, arguments);
};

var onFinallyThenCount = 0;
var yesValue = {};
var yes = Promise.resolve(yesValue);
yes.then = function () {
onFinallyThenCount += 1;
return Promise.prototype.then.apply(this, arguments);
};

var finallyCalled = false;
var catchCalled = false;

no.catch(function (e) {
assert.sameValue(e, noReason);
throw e;
}).finally(function () {
finallyCalled = true;
return yes;
}).catch(function (e) {
catchCalled = true;
assert.sameValue(e, noReason);
}).then(function () {
assert.sameValue(finallyCalled, true, 'initial finally was called');
assert.sameValue(initialThenCount, 1, 'initial finally invokes .then once');

assert.sameValue(catchCalled, true, 'catch was called');
assert.sameValue(onFinallyThenCount, 1, 'onFinally return promise has .then invoked once');
$DONE();
}).catch($ERROR);
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (C) 2017 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
author: Jordan Harband
description: finally on a rejected promise can not convert to a fulfillment
esid: sec-promise.prototype.finally
features: [Promise, Promise.reject, Promise.prototype.finally]
flags: [async]
---*/

var original = {};
var replacement = {};

var p = Promise.reject(original);

p.finally(function () {
assert.sameValue(arguments.length, 0, 'onFinally receives zero args');
return replacement;
}).then(function () {
$ERROR('promise is rejected pre-finally; onFulfill should not be called');
}).catch(function (reason) {
assert.sameValue(reason, original, 'onFinally can not override the rejection value by returning');
}).then($DONE).catch($ERROR);
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (C) 2017 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
author: Jordan Harband
description: finally on a rejected promise can override the rejection reason
esid: sec-promise.prototype.finally
features: [Promise, Promise.reject, Promise.prototype.finally]
flags: [async]
---*/

var original = {};
var thrown = {};

var p = Promise.reject(original);

p.finally(function () {
assert.sameValue(arguments.length, 0, 'onFinally receives zero args');
throw thrown;
}).then(function () {
$ERROR('promise is rejected; onFulfill should not be called');
}).catch(function (reason) {
assert.sameValue(reason, thrown, 'onFinally can override the rejection reason by throwing');
}).then($DONE).catch($ERROR);
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright (C) 2017 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
author: Jordan Harband
description: finally on a fulfilled promise can not override the resolution value
esid: sec-promise.prototype.finally
features: [Promise, Promise.resolve, Promise.prototype.finally]
flags: [async]
---*/

var obj = {};

var p = Promise.resolve(obj);

p.finally(function () {
assert.sameValue(arguments.length, 0, 'onFinally receives zero args');
return {};
}).then(function (x) {
assert.sameValue(x, obj, 'onFinally can not override the resolution value');
}).then($DONE).catch($ERROR);
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (C) 2017 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
author: Jordan Harband
description: finally observably calls .then
esid: sec-promise.prototype.finally
features: [Promise.resolve, Promise.reject, Promise.prototype.finally]
flags: [async]
---*/

var initialThenCount = 0;
var yesValue = {};
var yes = Promise.resolve(yesValue);
yes.then = function () {
initialThenCount += 1;
return Promise.prototype.then.apply(this, arguments);
};

var onFinallyThenCount = 0;
var noReason = {};
var no = Promise.reject(noReason);
no.then = function () {
onFinallyThenCount += 1;
return Promise.prototype.then.apply(this, arguments);
};

var finallyCalled = false;
var catchCalled = false;

yes.then(function (x) {
assert.sameValue(x, yesValue);
return x;
}).finally(function () {
finallyCalled = true;
return no;
}).catch(function (e) {
catchCalled = true;
assert.sameValue(e, noReason);
}).then(function () {
assert.sameValue(finallyCalled, true, 'initial finally was called');
assert.sameValue(initialThenCount, 1, 'initial finally invokes .then once');

assert.sameValue(catchCalled, true, 'catch was called');
assert.sameValue(onFinallyThenCount, 1, 'onFinally return promise has .then invoked once');
$DONE();
}).catch($ERROR);
17 changes: 17 additions & 0 deletions test/built-ins/Promise/prototype/finally/this-value-non-object.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright (C) 2017 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
author: Jordan Harband
description: >
Promise.prototype.finally called with a non-object-coercible `this` value
esid: sec-promise.prototype.finally
features: [Promise.prototype.finally, Function.prototype.call]
---*/

assert.throws(TypeError, function() {
Promise.prototype.finally.call(undefined);
}, 'undefined');

assert.throws(TypeError, function() {
Promise.prototype.finally.call(null);
}, 'null');
Loading

0 comments on commit ed366ef

Please sign in to comment.