diff --git a/docs/api/assert/rejects.md b/docs/api/assert/rejects.md
index bd8834538..ae056f3da 100644
--- a/docs/api/assert/rejects.md
+++ b/docs/api/assert/rejects.md
@@ -11,7 +11,8 @@ version_added: "2.5.0"
---
`rejects( promise, message = "" )`
-`rejects( promise, expectedMatcher, message = "" )`
+`rejects( promise, expectedMatcher, message = "" )`
+`rejectionValue = await rejects( promise, message = "" )`
Test if the provided promise rejects, and optionally compare the rejection value.
@@ -34,6 +35,10 @@ The `expectedMatcher` argument can be:
Note: in order to avoid confusion between the `message` and the `expectedMatcher`, the `expectedMatcher` **can not** be a string.
+`assert.rejects()` returns a promise which is resolved with the rejection value from the provided
+promise. This can be used instead of `expectedMatcher` to assert other facts about the expected
+failure.
+
## See also
* Use [`assert.throws()`](./throws.md) for synchronous errors.
@@ -62,7 +67,7 @@ QUnit.test('example', async function (assert) {
### Example: Matcher argument
```js
-QUnit.test('rejects example', function (assert) {
+QUnit.test('rejects example', async function (assert) {
// simple check
assert.rejects(Promise.reject('some error'));
@@ -113,6 +118,13 @@ QUnit.test('rejects example', function (assert) {
return err.toString() === 'some error';
}
);
+
+ // custom validation using return value
+ const err = await assert.rejects(
+ Promise.reject(new CustomError('some error'))
+ );
+ assert.true(err instanceof CustomError);
+ assert.strictEqual(err.toString(), 'some error');
});
```
@@ -181,17 +193,12 @@ QUnit.test('BAD example', function (assert) {
});
```
-If you want to perform additional assertions after a failure, consider performing these directly in your test function, after `assert.rejects()`:
+If you want to perform additional assertions after a failure, consider performing these directly in your test function, after `await assert.rejects()`:
```js
QUnit.test('example', async function (assert) {
const p = feedMe();
- await assert.rejects(p, RangeError);
-
- try {
- await p;
- } catch (e) {
- assert.deepEqual(e.somedata, { foo: 'bar' });
- }
+ const e = await assert.rejects(p, RangeError);
+ assert.deepEqual(e.somedata, { foo: 'bar' });
});
```
diff --git a/docs/api/assert/throws.md b/docs/api/assert/throws.md
index a1eed5bb9..bd4530214 100644
--- a/docs/api/assert/throws.md
+++ b/docs/api/assert/throws.md
@@ -12,7 +12,8 @@ version_added: "1.0.0"
---
`throws( blockFn, message = "" )`
-`throws( blockFn, expectedMatcher, message = "" )`
+`throws( blockFn, expectedMatcher, message = "" )`
+`thrownValue = throws( blockFn, message = "" )`
Test if a callback throws an exception, and optionally compare the thrown error.
@@ -31,6 +32,10 @@ The `expectedMatcher` argument can be:
* A RegExp that matches (or partially matches) the string representation.
* A callback with your own custom validation, that returns `true` or `false`.
+`assert.throws()` returns the value which was thrown from the provided
+function. This can be used instead of `expectedMatcher` to assert other facts about the expected
+failure.
+
If you need to comply with classic ES3 syntax, such as in early versions of Closure Compiler, you can use `assert.raises()`, which is an alias for `assert.throws()`. It has the same signature and behaviour.
## Changelog @@ -110,5 +115,12 @@ QUnit.test('throws example', function (assert) { return err.toString() === 'some error'; } ); + + // custom validation using return value + const err = assert.throws(function () { + throw new CustomError('some error'); + }); + assert.true(err instanceof CustomError); + assert.strictEqual(err.toString(), 'some error'); }); ``` diff --git a/src/core/assert.js b/src/core/assert.js index 65bc75222..5361c9f30 100644 --- a/src/core/assert.js +++ b/src/core/assert.js @@ -308,6 +308,8 @@ class Assert { expected, message }); + + return actual; } rejects (promise, expected, message) { @@ -355,6 +357,8 @@ class Assert { message }); done(); + + return actual; } ); } diff --git a/test/main/assert.js b/test/main/assert.js index d28ff5f65..5a66f1cef 100644 --- a/test/main/assert.js +++ b/test/main/assert.js @@ -10,14 +10,20 @@ function buildMockPromise (settledValue, shouldFulfill) { var thenable = { then: function (fulfilledCallback, rejectedCallback) { + var resolve = function () {}; defer(function () { - return shouldFulfill + resolve(shouldFulfill ? fulfilledCallback.call(thenable, settledValue) - : rejectedCallback.call(thenable, settledValue); + : rejectedCallback.call(thenable, settledValue)); }); // returning another thenable for easy confirmation of return value - return buildMockPromise('final promise', true); + // (very incomplete implementation, this is enough for the one test that needs it) + return { + then: function (fulfilledCallback) { + resolve = fulfilledCallback; + } + }; } }; return thenable; @@ -567,6 +573,18 @@ QUnit.test('throws', function (assert) { /^Error: Invalid expected value type \(array\) provided to assert\.throws\.$/, 'throws errors when provided an array' ); + + // return value tests + var returnValue = assert.throws( + function () { + throw 'my error'; + } + ); + assert.strictEqual( + returnValue, + 'my error', + 'throws returns the error value' + ); }); QUnit.test('raises', function (assert) { @@ -582,16 +600,6 @@ QUnit.test('rejects', function (assert) { return this.message; }; - var rejectsReturnValue = assert.rejects( - buildMockPromise('my error') - ); - - assert.equal( - typeof rejectsReturnValue.then, - 'function', - 'rejects returns a thennable' - ); - assert.rejects( buildMockPromise('my error'), "simple string rejection, no 'expected' value given" @@ -743,12 +751,30 @@ QUnit.test('rejects', function (assert) { 'rejects errors when provided a string' ); - // should return a thenable + // return value tests + var done = assert.async(); var returnValue = assert.rejects( - buildMockPromise(undefined) + buildMockPromise('my error') ); - assert.strictEqual(typeof returnValue, 'object'); - assert.strictEqual(typeof returnValue.then, 'function'); + assert.strictEqual( + typeof returnValue.then, + 'function', + 'rejects returns a thenable' + ); + returnValue.then(function (error) { + assert.strictEqual( + error, + 'my error', + 'returned thenable resolves with the rejection value' + ); + done(); + }, function () { + assert.ok( + false, + 'returned thenable does not reject' + ); + done(); + }); }); if (typeof window !== 'undefined') {