Skip to content

Commit 70dcacd

Browse files
committed
assert: deprecate assert.fail partially
Using `assert.fail()` with more than one argument is not intuitive to use and has no benefit over using a message on its own. Therefore this introduces a runtime deprecation in case it is used in that way. PR-URL: #18418 Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Anatoli Papirovski <apapirovski@mac.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
1 parent 89dd21a commit 70dcacd

File tree

5 files changed

+142
-88
lines changed

5 files changed

+142
-88
lines changed

doc/api/assert.md

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -415,30 +415,64 @@ parameter is an instance of an [`Error`][] then it will be thrown instead of the
415415
`AssertionError`.
416416

417417
## assert.fail([message])
418+
<!-- YAML
419+
added: v0.1.21
420+
-->
421+
* `message` {any} **Default:** `'Failed'`
422+
423+
Throws an `AssertionError` with the provided error message or a default error
424+
message. If the `message` parameter is an instance of an [`Error`][] then it
425+
will be thrown instead of the `AssertionError`.
426+
427+
```js
428+
const assert = require('assert').strict;
429+
430+
assert.fail();
431+
// AssertionError [ERR_ASSERTION]: Failed
432+
433+
assert.fail('boom');
434+
// AssertionError [ERR_ASSERTION]: boom
435+
436+
assert.fail(new TypeError('need array'));
437+
// TypeError: need array
438+
```
439+
440+
Using `assert.fail()` with more than two arguments is possible but deprecated.
441+
See below for further details.
442+
418443
## assert.fail(actual, expected[, message[, operator[, stackStartFunction]]])
419444
<!-- YAML
420445
added: v0.1.21
446+
changes:
447+
- version: REPLACEME
448+
pr-url: https://github.com/nodejs/node/pull/REPLACEME
449+
description: Calling `assert.fail` with more than one argument is deprecated
450+
and emits a warning.
421451
-->
422452
* `actual` {any}
423453
* `expected` {any}
424-
* `message` {any} **Default:** `'Failed'`
454+
* `message` {any}
425455
* `operator` {string} **Default:** '!='
426456
* `stackStartFunction` {Function} **Default:** `assert.fail`
427457

428-
Throws an `AssertionError`. If `message` is falsy, the error message is set as
429-
the values of `actual` and `expected` separated by the provided `operator`. If
430-
the `message` parameter is an instance of an [`Error`][] then it will be thrown
431-
instead of the `AssertionError`. If just the two `actual` and `expected`
432-
arguments are provided, `operator` will default to `'!='`. If `message` is
433-
provided only it will be used as the error message, the other arguments will be
434-
stored as properties on the thrown object. If `stackStartFunction` is provided,
435-
all stack frames above that function will be removed from stacktrace (see
436-
[`Error.captureStackTrace`]). If no arguments are given, the default message
437-
`Failed` will be used.
458+
> Stability: 0 - Deprecated: Use `assert.fail([message])` or other assert
459+
> functions instead.
460+
461+
If `message` is falsy, the error message is set as the values of `actual` and
462+
`expected` separated by the provided `operator`. If just the two `actual` and
463+
`expected` arguments are provided, `operator` will default to `'!='`. If
464+
`message` is provided as third argument it will be used as the error message and
465+
the other arguments will be stored as properties on the thrown object. If
466+
`stackStartFunction` is provided, all stack frames above that function will be
467+
removed from stacktrace (see [`Error.captureStackTrace`]). If no arguments are
468+
given, the default message `Failed` will be used.
438469

439470
```js
440471
const assert = require('assert').strict;
441472

473+
assert.fail('a', 'b');
474+
// AssertionError [ERR_ASSERTION]: 'a' != 'b'
475+
442476
assert.fail(1, 2, undefined, '>');
443477
// AssertionError [ERR_ASSERTION]: 1 > 2
444478

@@ -452,21 +486,11 @@ assert.fail(1, 2, new TypeError('need array'));
452486
// TypeError: need array
453487
```
454488

455-
*Note*: In the last two cases `actual`, `expected`, and `operator` have no
489+
In the last three cases `actual`, `expected`, and `operator` have no
456490
influence on the error message.
457491

458-
```js
459-
assert.fail();
460-
// AssertionError [ERR_ASSERTION]: Failed
461-
462-
assert.fail('boom');
463-
// AssertionError [ERR_ASSERTION]: boom
464-
465-
assert.fail('a', 'b');
466-
// AssertionError [ERR_ASSERTION]: 'a' != 'b'
467-
```
468-
469492
Example use of `stackStartFunction` for truncating the exception's stacktrace:
493+
470494
```js
471495
function suppressFrame() {
472496
assert.fail('a', 'b', undefined, '!==', suppressFrame);

doc/api/deprecations.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -847,6 +847,15 @@ Type: Documentation-only
847847
The [`crypto.fips`][] property is deprecated. Please use `crypto.setFips()`
848848
and `crypto.getFips()` instead.
849849
850+
<a id="DEP0XX"></a>
851+
### DEP0XXX: Using `assert.fail()` with more than one argument.
852+
853+
Type: Runtime
854+
855+
Using `assert.fail()` with more than one argument has no benefit over writing an
856+
individual error message. Either use `assert.fail()` with one argument or switch
857+
to one of the other assert methods.
858+
850859
[`--pending-deprecation`]: cli.html#cli_pending_deprecation
851860
[`Buffer.allocUnsafeSlow(size)`]: buffer.html#buffer_class_method_buffer_allocunsafeslow_size
852861
[`Buffer.from(array)`]: buffer.html#buffer_class_method_buffer_from_array

lib/assert.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ const ERR_DIFF_DEACTIVATED = 0;
5252
const ERR_DIFF_NOT_EQUAL = 1;
5353
const ERR_DIFF_EQUAL = 2;
5454

55+
let warned = false;
56+
5557
// The assert module provides functions that throw
5658
// AssertionError's when particular conditions are not met. The
5759
// assert module must conform to the following interface.
@@ -80,8 +82,18 @@ function fail(actual, expected, message, operator, stackStartFn) {
8082
} else if (argsLen === 1) {
8183
message = actual;
8284
actual = undefined;
83-
} else if (argsLen === 2) {
84-
operator = '!=';
85+
} else {
86+
if (warned === false) {
87+
warned = true;
88+
process.emitWarning(
89+
'assert.fail() with more than one argument is deprecated. ' +
90+
'Please use assert.strictEqual() instead or only pass a message.',
91+
'DeprecationWarning',
92+
'DEP00XXX'
93+
);
94+
}
95+
if (argsLen === 2)
96+
operator = '!=';
8597
}
8698

8799
innerFail({
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const assert = require('assert');
5+
6+
common.expectWarning(
7+
'DeprecationWarning',
8+
'assert.fail() with more than one argument is deprecated. ' +
9+
'Please use assert.strictEqual() instead or only pass a message.'
10+
);
11+
12+
// Two args only, operator defaults to '!='
13+
assert.throws(() => {
14+
assert.fail('first', 'second');
15+
}, {
16+
code: 'ERR_ASSERTION',
17+
name: 'AssertionError [ERR_ASSERTION]',
18+
message: '\'first\' != \'second\'',
19+
operator: '!=',
20+
actual: 'first',
21+
expected: 'second'
22+
});
23+
24+
// Three args
25+
assert.throws(() => {
26+
assert.fail('ignored', 'ignored', 'another custom message');
27+
}, {
28+
code: 'ERR_ASSERTION',
29+
name: 'AssertionError [ERR_ASSERTION]',
30+
message: 'another custom message',
31+
operator: undefined,
32+
actual: 'ignored',
33+
expected: 'ignored'
34+
});
35+
36+
// Three args with custom Error
37+
assert.throws(() => {
38+
assert.fail(typeof 1, 'object', new TypeError('another custom message'));
39+
}, {
40+
name: 'TypeError',
41+
message: 'another custom message',
42+
operator: undefined,
43+
actual: undefined,
44+
expected: undefined,
45+
code: undefined
46+
});
47+
48+
// No third arg (but a fourth arg)
49+
assert.throws(() => {
50+
assert.fail('first', 'second', undefined, 'operator');
51+
}, {
52+
code: 'ERR_ASSERTION',
53+
name: 'AssertionError [ERR_ASSERTION]',
54+
message: '\'first\' operator \'second\'',
55+
operator: 'operator',
56+
actual: 'first',
57+
expected: 'second'
58+
});
59+
60+
// The stackFrameFunction should exclude the foo frame
61+
assert.throws(
62+
function foo() { assert.fail('first', 'second', 'message', '!==', foo); },
63+
(err) => !/^\s*at\sfoo\b/m.test(err.stack)
64+
);

test/parallel/test-assert-fail.js

Lines changed: 8 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,95 +1,40 @@
11
'use strict';
22

3-
/* eslint-disable prefer-common-expectserror */
4-
5-
const common = require('../common');
3+
require('../common');
64
const assert = require('assert');
75

86
// No args
97
assert.throws(
108
() => { assert.fail(); },
11-
common.expectsError({
9+
{
1210
code: 'ERR_ASSERTION',
13-
type: assert.AssertionError,
11+
name: 'AssertionError [ERR_ASSERTION]',
1412
message: 'Failed',
1513
operator: undefined,
1614
actual: undefined,
1715
expected: undefined
18-
})
16+
}
1917
);
2018

2119
// One arg = message
22-
common.expectsError(() => {
20+
assert.throws(() => {
2321
assert.fail('custom message');
2422
}, {
2523
code: 'ERR_ASSERTION',
26-
type: assert.AssertionError,
24+
name: 'AssertionError [ERR_ASSERTION]',
2725
message: 'custom message',
2826
operator: undefined,
2927
actual: undefined,
3028
expected: undefined
3129
});
3230

3331
// One arg = Error
34-
common.expectsError(() => {
32+
assert.throws(() => {
3533
assert.fail(new TypeError('custom message'));
3634
}, {
37-
type: TypeError,
35+
name: 'TypeError',
3836
message: 'custom message',
3937
operator: undefined,
4038
actual: undefined,
4139
expected: undefined
4240
});
43-
44-
// Two args only, operator defaults to '!='
45-
common.expectsError(() => {
46-
assert.fail('first', 'second');
47-
}, {
48-
code: 'ERR_ASSERTION',
49-
type: assert.AssertionError,
50-
message: '\'first\' != \'second\'',
51-
operator: '!=',
52-
actual: 'first',
53-
expected: 'second'
54-
});
55-
56-
// Three args
57-
common.expectsError(() => {
58-
assert.fail('ignored', 'ignored', 'another custom message');
59-
}, {
60-
code: 'ERR_ASSERTION',
61-
type: assert.AssertionError,
62-
message: 'another custom message',
63-
operator: undefined,
64-
actual: 'ignored',
65-
expected: 'ignored'
66-
});
67-
68-
// Three args with custom Error
69-
common.expectsError(() => {
70-
assert.fail(typeof 1, 'object', new TypeError('another custom message'));
71-
}, {
72-
type: TypeError,
73-
message: 'another custom message',
74-
operator: undefined,
75-
actual: 'number',
76-
expected: 'object'
77-
});
78-
79-
// No third arg (but a fourth arg)
80-
common.expectsError(() => {
81-
assert.fail('first', 'second', undefined, 'operator');
82-
}, {
83-
code: 'ERR_ASSERTION',
84-
type: assert.AssertionError,
85-
message: '\'first\' operator \'second\'',
86-
operator: 'operator',
87-
actual: 'first',
88-
expected: 'second'
89-
});
90-
91-
// The stackFrameFunction should exclude the foo frame
92-
assert.throws(
93-
function foo() { assert.fail('first', 'second', 'message', '!==', foo); },
94-
(err) => !/^\s*at\sfoo\b/m.test(err.stack)
95-
);

0 commit comments

Comments
 (0)