From f1357866039d2c712a056035002aa9dee5d7d2e8 Mon Sep 17 00:00:00 2001 From: geek <wpreul@gmail.com> Date: Sat, 9 Sep 2017 20:36:47 -0500 Subject: [PATCH] assert: support custom errors --- doc/api/assert.md | 59 +++++++++++++++++++++---------- lib/assert.js | 2 ++ test/parallel/test-assert-fail.js | 22 ++++++++++++ test/parallel/test-assert.js | 28 +++++++++++++++ 4 files changed, 93 insertions(+), 18 deletions(-) diff --git a/doc/api/assert.md b/doc/api/assert.md index 254d4faf98bfbf..50bc22e0b66714 100644 --- a/doc/api/assert.md +++ b/doc/api/assert.md @@ -101,7 +101,9 @@ assert.deepEqual(obj1, obj4); If the values are not equal, an `AssertionError` is thrown with a `message` property set equal to the value of the `message` parameter. If the `message` -parameter is undefined, a default error message is assigned. +parameter is undefined, a default error message is assigned. If the `message` +parameter is an instance of an `Error` then it will be thrown instead of the +`AssertionError`. ## assert.deepStrictEqual(actual, expected[, message]) <!-- YAML @@ -174,7 +176,9 @@ assert.deepStrictEqual(NaN, NaN); If the values are not equal, an `AssertionError` is thrown with a `message` property set equal to the value of the `message` parameter. If the `message` -parameter is undefined, a default error message is assigned. +parameter is undefined, a default error message is assigned. If the `message` +parameter is an instance of an `Error` then it will be thrown instead of the +`AssertionError`. ## assert.doesNotThrow(block[, error][, message]) <!-- YAML @@ -268,7 +272,9 @@ assert.equal({ a: { b: 1 } }, { a: { b: 1 } }); If the values are not equal, an `AssertionError` is thrown with a `message` property set equal to the value of the `message` parameter. If the `message` -parameter is undefined, a default error message is assigned. +parameter is undefined, a default error message is assigned. If the `message` +parameter is an instance of an `Error` then it will be thrown instead of the +`AssertionError`. ## assert.fail([message]) ## assert.fail(actual, expected[, message[, operator[, stackStartFunction]]]) @@ -282,13 +288,15 @@ added: v0.1.21 * `stackStartFunction` {function} (default: `assert.fail`) Throws an `AssertionError`. If `message` is falsy, the error message is set as -the values of `actual` and `expected` separated by the provided `operator`. -If just the two `actual` and `expected` arguments are provided, `operator` will -default to `'!='`. If `message` is provided only it will be used as the error -message, the other arguments will be stored as properties on the thrown object. -If `stackStartFunction` is provided, all stack frames above that function will -be removed from stacktrace (see [`Error.captureStackTrace`]). If no arguments -are given, the default message `Failed` will be used. +the values of `actual` and `expected` separated by the provided `operator`. If +the `message` parameter is an instance of an `Error` then it will be thrown +instead of the `AssertionError`. If just the two `actual` and `expected` +arguments are provided, `operator` will default to `'!='`. If `message` is +provided only it will be used as the error message, the other arguments will be +stored as properties on the thrown object. If `stackStartFunction` is provided, +all stack frames above that function will be removed from stacktrace (see +[`Error.captureStackTrace`]). If no arguments are given, the default message +`Failed` will be used. ```js const assert = require('assert'); @@ -301,6 +309,9 @@ assert.fail(1, 2, 'fail'); assert.fail(1, 2, 'whoops', '>'); // AssertionError [ERR_ASSERTION]: whoops + +assert.fail(1, 2, new TypeError('need array')); +// TypeError: need array ``` *Note*: Is the last two cases `actual`, `expected`, and `operator` have no @@ -412,7 +423,9 @@ assert.notDeepEqual(obj1, obj4); If the values are deeply equal, an `AssertionError` is thrown with a `message` property set equal to the value of the `message` parameter. If the `message` -parameter is undefined, a default error message is assigned. +parameter is undefined, a default error message is assigned. If the `message` +parameter is an instance of an `Error` then it will be thrown instead of the +`AssertionError`. ## assert.notDeepStrictEqual(actual, expected[, message]) <!-- YAML @@ -453,9 +466,11 @@ assert.notDeepStrictEqual({ a: 1 }, { a: '1' }); // OK ``` -If the values are deeply and strictly equal, an `AssertionError` is thrown -with a `message` property set equal to the value of the `message` parameter. If -the `message` parameter is undefined, a default error message is assigned. +If the values are deeply and strictly equal, an `AssertionError` is thrown with +a `message` property set equal to the value of the `message` parameter. If the +`message` parameter is undefined, a default error message is assigned. If the +`message` parameter is an instance of an `Error` then it will be thrown instead +of the `AssertionError`. ## assert.notEqual(actual, expected[, message]) <!-- YAML @@ -483,7 +498,9 @@ assert.notEqual(1, '1'); If the values are equal, an `AssertionError` is thrown with a `message` property set equal to the value of the `message` parameter. If the `message` -parameter is undefined, a default error message is assigned. +parameter is undefined, a default error message is assigned. If the `message` +parameter is an instance of an `Error` then it will be thrown instead of the +`AssertionError`. ## assert.notStrictEqual(actual, expected[, message]) <!-- YAML @@ -511,7 +528,9 @@ assert.notStrictEqual(1, '1'); If the values are strictly equal, an `AssertionError` is thrown with a `message` property set equal to the value of the `message` parameter. If the -`message` parameter is undefined, a default error message is assigned. +`message` parameter is undefined, a default error message is assigned. If the +`message` parameter is an instance of an `Error` then it will be thrown instead +of the `AssertionError`. ## assert.ok(value[, message]) <!-- YAML @@ -525,7 +544,9 @@ Tests if `value` is truthy. It is equivalent to If `value` is not truthy, an `AssertionError` is thrown with a `message` property set equal to the value of the `message` parameter. If the `message` -parameter is `undefined`, a default error message is assigned. +parameter is `undefined`, a default error message is assigned. If the `message` +parameter is an instance of an `Error` then it will be thrown instead of the +`AssertionError`. ```js const assert = require('assert'); @@ -568,7 +589,9 @@ assert.strictEqual(1, '1'); If the values are not strictly equal, an `AssertionError` is thrown with a `message` property set equal to the value of the `message` parameter. If the -`message` parameter is undefined, a default error message is assigned. +`message` parameter is undefined, a default error message is assigned. If the +`message` parameter is an instance of an `Error` then it will be thrown instead +of the `AssertionError`. ## assert.throws(block[, error][, message]) <!-- YAML diff --git a/lib/assert.js b/lib/assert.js index 2c52fcc19996f9..6cbebcc4d87ed5 100644 --- a/lib/assert.js +++ b/lib/assert.js @@ -38,6 +38,8 @@ const assert = module.exports = ok; // display purposes. function innerFail(actual, expected, message, operator, stackStartFunction) { + if (message instanceof Error) throw message; + throw new errors.AssertionError({ message, actual, diff --git a/test/parallel/test-assert-fail.js b/test/parallel/test-assert-fail.js index efa48cc215cfdb..14d28e5cd0045f 100644 --- a/test/parallel/test-assert-fail.js +++ b/test/parallel/test-assert-fail.js @@ -28,6 +28,17 @@ common.expectsError(() => { expected: undefined }); +// One arg = Error +common.expectsError(() => { + assert.fail(new TypeError('custom message')); +}, { + type: TypeError, + message: 'custom message', + operator: undefined, + actual: undefined, + expected: undefined +}); + // Two args only, operator defaults to '!=' common.expectsError(() => { assert.fail('first', 'second'); @@ -52,6 +63,17 @@ common.expectsError(() => { expected: 'ignored' }); +// Three args with custom Error +common.expectsError(() => { + assert.fail(typeof 1, 'object', new TypeError('another custom message')); +}, { + type: TypeError, + message: 'another custom message', + operator: undefined, + actual: 'number', + expected: 'object' +}); + // No third arg (but a fourth arg) common.expectsError(() => { assert.fail('first', 'second', undefined, 'operator'); diff --git a/test/parallel/test-assert.js b/test/parallel/test-assert.js index 30e80274890ce6..d4cd52c37c3839 100644 --- a/test/parallel/test-assert.js +++ b/test/parallel/test-assert.js @@ -645,6 +645,34 @@ try { 'Message incorrectly marked as generated'); } +{ + let threw = false; + const rangeError = new RangeError('my range'); + + // verify custom errors + try { + assert.strictEqual(1, 2, rangeError); + } catch (e) { + assert.strictEqual(e, rangeError); + threw = true; + assert.ok(e instanceof RangeError, 'Incorrect error type thrown'); + } + assert.ok(threw); + threw = false; + + // verify AssertionError is the result from doesNotThrow with custom Error + try { + assert.doesNotThrow(() => { + throw new TypeError('wrong type'); + }, TypeError, rangeError); + } catch (e) { + threw = true; + assert.ok(e.message.includes(rangeError.message)); + assert.ok(e instanceof assert.AssertionError); + } + assert.ok(threw); +} + { // Verify that throws() and doesNotThrow() throw on non-function block function typeName(value) {