Update rfcs/async-helpers to reflect the pre-final comment consensus API for asyncTest and assert.throwsAsync

This commit is contained in:
Cam Tenny 2022-12-30 17:32:56 -08:00 committed by Philip Chimento
parent a776c8a948
commit edd1e6d25f
1 changed files with 18 additions and 18 deletions

View File

@ -96,43 +96,43 @@ Each one would be accompanied by tests in the `test/harness/` folder to verify t
Including `asyncHelpers.js` in the frontmatter defines a function `asyncTest` in the global namespace. Including `asyncHelpers.js` in the frontmatter defines a function `asyncTest` in the global namespace.
- _testFunc_: a function, representing the test body, that takes no arguments and returns a promise. - _testFunc_: a function, representing the test body, that takes no arguments and returns a promise.
- Returns: a promise that always fulfills with `undefined`. - Returns: `undefined`.
Including `asyncHelpers.js` in the frontmatter defines a new `asyncTest` property on the global object. Including `asyncHelpers.js` in the frontmatter defines a new `asyncTest` property on the global object.
The `asyncTest` function awaits the result of _testFunc_. The `asyncTest` function calls _testFunc_ to obtain a result. If this produces a synchronous error, `$DONE` is called with the error. Otherwise, it awaits the result of _testFunc_.
If _testFunc_'s promise is fulfilled, the fulfillment value is discarded, and `$DONE` is called with no argument. If _testFunc_'s thenable is fulfilled, the fulfillment value is discarded, and `$DONE` is called with no argument.
If _testFunc_'s promise rejects, `$DONE` is called with the rejection value as its argument. If _testFunc_'s thenable rejects, `$DONE` is called with the rejection value as its argument.
When the promise returned by `asyncTest` is fulfilled, then the test body has finished executing, the test has either passed or failed, and `$DONE` has been called exactly once with the appropriate argument. When `asyncTest` has returned, then the promisef representing the test body has been created, the test will either pass or fail, and `$DONE` will be called exactly once with the appropriate argument.
Before `asyncTest` does anything, it checks whether there is a `$DONE` property on the global object. Before `asyncTest` does anything, it checks whether there is a `$DONE` property on the global object.
If there isn't, it throws an exception synchronously. If there isn't, it throws an exception synchronously.
(The purpose of this is to catch an async test that mistakenly omits the `async` flag. (The purpose of this is to catch an async test that mistakenly omits the `async` flag.
For this reason, it's worth departing from the convention that results from a function must be always synchronous or always asynchronous ("summoning Zalgo"); in this case the runtime will be treating the test file as a synchronous test.) For this reason, it's worth departing from the convention that results from a function must be always synchronous or always asynchronous ("summoning Zalgo"); in this case the runtime will be treating the test file as a synchronous test.)
### assert.throwsAsync(_expectedErrorConstructor_, _funcOrPromise_[, _message_]) ### assert.throwsAsync(_expectedErrorConstructor_, _func_[, _message_])
- _expectedErrorConstructor_: an error constructor, such as `TypeError`. - _expectedErrorConstructor_: an error constructor, such as `TypeError`.
- _funcOrPromise_: a function that returns a promise, or a promise. - _func_: a function that returns a thenable.
- _message_ (optional): a string with explanation that will be printed on failure. - _message_ (optional): a string with explanation that will be printed on failure.
- Returns: a promise (the "returned promise".) - Returns: a thenable (the "returned promise".)
Including `asyncHelpers.js` in the frontmatter defines a new `throwsAsync` property on the `assert` object. Including `asyncHelpers.js` in the frontmatter defines a new `throwsAsync` property on the `assert` object.
If _funcOrPromise_ is a function, it is first executed in order to obtain a promise (the "inner promise".) If _func_ is a function, it is first executed in order to obtain a thenable (the "inner thenable".).
This way, it's possible to write assertions about an async function just as easily as about a promise, without having to either wrap the promise in an async function or replace the async function with an async IIFE.
*[IIFE]: immediately-invoked function expression
The returned promise rejects with a Test262Error with an appropriate message, in the following cases: The returned promise rejects with a Test262Error with an appropriate message, in the following cases:
- _funcOrPromise_ is a function, and didn't return a promise (a thenable?) when executed. - _func_ is not a function.
- The inner promise is fulfilled. - _func_ is a function, and synchronously threw an error when obtaining the inner thenable.
- The inner promise rejects with a primitive value. - _func_ is a function, and didn't return a thenable when executed.
- The inner promise rejects with an object whose `constructor` property is not the same value as _expectedErrorConstructor_. - The inner thenable throws a synchronous error when invoking `.then`
- The inner thenable is fulfilled.
- The inner thenable rejects with a primitive value.
- The inner thenable rejects with an object whose `constructor` property is not the same value as _expectedErrorConstructor_.
Just as in `assert.throws()`, the Test262Error's message takes into account the case where the inner promise's rejection value is an Error constructor with the same name as _expectedErrorConstructor_ but is not the same value, which can happen when the constructor comes from a different global. Just as in `assert.throws()`, the Test262Error's message takes into account the case where the inner thenable's rejection value is an Error constructor with the same name as _expectedErrorConstructor_ but is not the same value, which can happen when the constructor comes from a different global.
If the inner promise rejects with the appropriate type of error object (constructor is the same value as _expectedErrorConstructor_), the returned promise is fulfilled with `undefined`, so that the resolution value can be passed to `$DONE`. If the inner thenable rejects with the appropriate type of error object (constructor is the same value as _expectedErrorConstructor_), the returned thenable is fulfilled with `undefined`, so that the resolution value can be passed to `$DONE`.
Although `assert.throwsAsync()` is designed to be used with await-style async programming, it can also be used with promise-style, postfixing it with `.then($DONE, $DONE)`. Although `assert.throwsAsync()` is designed to be used with await-style async programming, it can also be used with promise-style, postfixing it with `.then($DONE, $DONE)`.
Chaining returned promises from `assert.throwsAsync()` works as might be expected: if any of them reject, the rejection value is passed directly to `$DONE()` and the subsequent calls are not made. Chaining returned promises from `assert.throwsAsync()` works as might be expected: if any of them reject, the rejection value is passed directly to `$DONE()` and the subsequent calls are not made.