Skip to content

Commit e13d1df

Browse files
geekcjihrig
authored andcommitted
assert: support custom errors
This commit adds special handling of Error instances when passed as the message argument to assert functions. With this commit, if an Error is passed as the message, then that Error is thrown instead of an AssertionError. PR-URL: #15304 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Ruben Bridgewater <[email protected]>
1 parent a10856a commit e13d1df

File tree

4 files changed

+93
-18
lines changed

4 files changed

+93
-18
lines changed

doc/api/assert.md

+41-18
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,9 @@ assert.deepEqual(obj1, obj4);
101101

102102
If the values are not equal, an `AssertionError` is thrown with a `message`
103103
property set equal to the value of the `message` parameter. If the `message`
104-
parameter is undefined, a default error message is assigned.
104+
parameter is undefined, a default error message is assigned. If the `message`
105+
parameter is an instance of an `Error` then it will be thrown instead of the
106+
`AssertionError`.
105107

106108
## assert.deepStrictEqual(actual, expected[, message])
107109
<!-- YAML
@@ -176,7 +178,9 @@ assert.deepStrictEqual(NaN, NaN);
176178

177179
If the values are not equal, an `AssertionError` is thrown with a `message`
178180
property set equal to the value of the `message` parameter. If the `message`
179-
parameter is undefined, a default error message is assigned.
181+
parameter is undefined, a default error message is assigned. If the `message`
182+
parameter is an instance of an `Error` then it will be thrown instead of the
183+
`AssertionError`.
180184

181185
## assert.doesNotThrow(block[, error][, message])
182186
<!-- YAML
@@ -270,7 +274,9 @@ assert.equal({ a: { b: 1 } }, { a: { b: 1 } });
270274

271275
If the values are not equal, an `AssertionError` is thrown with a `message`
272276
property set equal to the value of the `message` parameter. If the `message`
273-
parameter is undefined, a default error message is assigned.
277+
parameter is undefined, a default error message is assigned. If the `message`
278+
parameter is an instance of an `Error` then it will be thrown instead of the
279+
`AssertionError`.
274280

275281
## assert.fail([message])
276282
## assert.fail(actual, expected[, message[, operator[, stackStartFunction]]])
@@ -284,13 +290,15 @@ added: v0.1.21
284290
* `stackStartFunction` {function} (default: `assert.fail`)
285291

286292
Throws an `AssertionError`. If `message` is falsy, the error message is set as
287-
the values of `actual` and `expected` separated by the provided `operator`.
288-
If just the two `actual` and `expected` arguments are provided, `operator` will
289-
default to `'!='`. If `message` is provided only it will be used as the error
290-
message, the other arguments will be stored as properties on the thrown object.
291-
If `stackStartFunction` is provided, all stack frames above that function will
292-
be removed from stacktrace (see [`Error.captureStackTrace`]). If no arguments
293-
are given, the default message `Failed` will be used.
293+
the values of `actual` and `expected` separated by the provided `operator`. If
294+
the `message` parameter is an instance of an `Error` then it will be thrown
295+
instead of the `AssertionError`. If just the two `actual` and `expected`
296+
arguments are provided, `operator` will default to `'!='`. If `message` is
297+
provided only it will be used as the error message, the other arguments will be
298+
stored as properties on the thrown object. If `stackStartFunction` is provided,
299+
all stack frames above that function will be removed from stacktrace (see
300+
[`Error.captureStackTrace`]). If no arguments are given, the default message
301+
`Failed` will be used.
294302

295303
```js
296304
const assert = require('assert');
@@ -303,6 +311,9 @@ assert.fail(1, 2, 'fail');
303311

304312
assert.fail(1, 2, 'whoops', '>');
305313
// AssertionError [ERR_ASSERTION]: whoops
314+
315+
assert.fail(1, 2, new TypeError('need array'));
316+
// TypeError: need array
306317
```
307318

308319
*Note*: Is the last two cases `actual`, `expected`, and `operator` have no
@@ -414,7 +425,9 @@ assert.notDeepEqual(obj1, obj4);
414425

415426
If the values are deeply equal, an `AssertionError` is thrown with a `message`
416427
property set equal to the value of the `message` parameter. If the `message`
417-
parameter is undefined, a default error message is assigned.
428+
parameter is undefined, a default error message is assigned. If the `message`
429+
parameter is an instance of an `Error` then it will be thrown instead of the
430+
`AssertionError`.
418431

419432
## assert.notDeepStrictEqual(actual, expected[, message])
420433
<!-- YAML
@@ -455,9 +468,11 @@ assert.notDeepStrictEqual({ a: 1 }, { a: '1' });
455468
// OK
456469
```
457470

458-
If the values are deeply and strictly equal, an `AssertionError` is thrown
459-
with a `message` property set equal to the value of the `message` parameter. If
460-
the `message` parameter is undefined, a default error message is assigned.
471+
If the values are deeply and strictly equal, an `AssertionError` is thrown with
472+
a `message` property set equal to the value of the `message` parameter. If the
473+
`message` parameter is undefined, a default error message is assigned. If the
474+
`message` parameter is an instance of an `Error` then it will be thrown instead
475+
of the `AssertionError`.
461476

462477
## assert.notEqual(actual, expected[, message])
463478
<!-- YAML
@@ -485,7 +500,9 @@ assert.notEqual(1, '1');
485500

486501
If the values are equal, an `AssertionError` is thrown with a `message`
487502
property set equal to the value of the `message` parameter. If the `message`
488-
parameter is undefined, a default error message is assigned.
503+
parameter is undefined, a default error message is assigned. If the `message`
504+
parameter is an instance of an `Error` then it will be thrown instead of the
505+
`AssertionError`.
489506

490507
## assert.notStrictEqual(actual, expected[, message])
491508
<!-- YAML
@@ -513,7 +530,9 @@ assert.notStrictEqual(1, '1');
513530

514531
If the values are strictly equal, an `AssertionError` is thrown with a
515532
`message` property set equal to the value of the `message` parameter. If the
516-
`message` parameter is undefined, a default error message is assigned.
533+
`message` parameter is undefined, a default error message is assigned. If the
534+
`message` parameter is an instance of an `Error` then it will be thrown instead
535+
of the `AssertionError`.
517536

518537
## assert.ok(value[, message])
519538
<!-- YAML
@@ -527,7 +546,9 @@ Tests if `value` is truthy. It is equivalent to
527546

528547
If `value` is not truthy, an `AssertionError` is thrown with a `message`
529548
property set equal to the value of the `message` parameter. If the `message`
530-
parameter is `undefined`, a default error message is assigned.
549+
parameter is `undefined`, a default error message is assigned. If the `message`
550+
parameter is an instance of an `Error` then it will be thrown instead of the
551+
`AssertionError`.
531552

532553
```js
533554
const assert = require('assert');
@@ -570,7 +591,9 @@ assert.strictEqual(1, '1');
570591

571592
If the values are not strictly equal, an `AssertionError` is thrown with a
572593
`message` property set equal to the value of the `message` parameter. If the
573-
`message` parameter is undefined, a default error message is assigned.
594+
`message` parameter is undefined, a default error message is assigned. If the
595+
`message` parameter is an instance of an `Error` then it will be thrown instead
596+
of the `AssertionError`.
574597

575598
## assert.throws(block[, error][, message])
576599
<!-- YAML

lib/assert.js

+2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ const assert = module.exports = ok;
3838
// display purposes.
3939

4040
function innerFail(actual, expected, message, operator, stackStartFunction) {
41+
if (message instanceof Error) throw message;
42+
4143
throw new errors.AssertionError({
4244
message,
4345
actual,

test/parallel/test-assert-fail.js

+22
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,17 @@ common.expectsError(() => {
2828
expected: undefined
2929
});
3030

31+
// One arg = Error
32+
common.expectsError(() => {
33+
assert.fail(new TypeError('custom message'));
34+
}, {
35+
type: TypeError,
36+
message: 'custom message',
37+
operator: undefined,
38+
actual: undefined,
39+
expected: undefined
40+
});
41+
3142
// Two args only, operator defaults to '!='
3243
common.expectsError(() => {
3344
assert.fail('first', 'second');
@@ -52,6 +63,17 @@ common.expectsError(() => {
5263
expected: 'ignored'
5364
});
5465

66+
// Three args with custom Error
67+
common.expectsError(() => {
68+
assert.fail(typeof 1, 'object', new TypeError('another custom message'));
69+
}, {
70+
type: TypeError,
71+
message: 'another custom message',
72+
operator: undefined,
73+
actual: 'number',
74+
expected: 'object'
75+
});
76+
5577
// No third arg (but a fourth arg)
5678
common.expectsError(() => {
5779
assert.fail('first', 'second', undefined, 'operator');

test/parallel/test-assert.js

+28
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,34 @@ try {
645645
'Message incorrectly marked as generated');
646646
}
647647

648+
{
649+
let threw = false;
650+
const rangeError = new RangeError('my range');
651+
652+
// verify custom errors
653+
try {
654+
assert.strictEqual(1, 2, rangeError);
655+
} catch (e) {
656+
assert.strictEqual(e, rangeError);
657+
threw = true;
658+
assert.ok(e instanceof RangeError, 'Incorrect error type thrown');
659+
}
660+
assert.ok(threw);
661+
threw = false;
662+
663+
// verify AssertionError is the result from doesNotThrow with custom Error
664+
try {
665+
assert.doesNotThrow(() => {
666+
throw new TypeError('wrong type');
667+
}, TypeError, rangeError);
668+
} catch (e) {
669+
threw = true;
670+
assert.ok(e.message.includes(rangeError.message));
671+
assert.ok(e instanceof assert.AssertionError);
672+
}
673+
assert.ok(threw);
674+
}
675+
648676
{
649677
// Verify that throws() and doesNotThrow() throw on non-function block
650678
function typeName(value) {

0 commit comments

Comments
 (0)