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') {