Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 47 additions & 23 deletions doc/api/assert.md
Original file line number Diff line number Diff line change
Expand Up @@ -415,30 +415,64 @@ parameter is an instance of an [`Error`][] then it will be thrown instead of the
`AssertionError`.

## assert.fail([message])
<!-- YAML
added: v0.1.21
-->
* `message` {any} **Default:** `'Failed'`

Throws an `AssertionError` with the provided error message or a default error
message. If the `message` parameter is an instance of an [`Error`][] then it
will be thrown instead of the `AssertionError`.

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

assert.fail();
// AssertionError [ERR_ASSERTION]: Failed

assert.fail('boom');
// AssertionError [ERR_ASSERTION]: boom

assert.fail(new TypeError('need array'));
// TypeError: need array
```

Using `assert.fail()` with more than two arguments is possible but deprecated.
See below for further details.

## assert.fail(actual, expected[, message[, operator[, stackStartFunction]]])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The signature here looks rather confusing, since actual and expected looks required here...maybe create another section with assert.fail(message), and deprecate this signature while referencing the new one?

Copy link
Member

@joyeecheung joyeecheung Jan 29, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, that way we can put a deprecated entry in the YAML so the whole signature would be labeled with deprecated in the TOC.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that it looks confusing. We just never had such a case before but I agree that this is probably the best way to solve this. I will change it shortly.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

<!-- YAML
added: v0.1.21
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/REPLACEME
description: Calling `assert.fail` with more than one argument is deprecated
and emits a warning.
-->
* `actual` {any}
* `expected` {any}
* `message` {any} **Default:** `'Failed'`
* `message` {any}
* `operator` {string} **Default:** '!='
* `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
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.
> Stability: 0 - Deprecated: Use `assert.fail([message])` or other assert
> functions instead.

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 as third argument it will be used as the error message and
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').strict;

assert.fail('a', 'b');
// AssertionError [ERR_ASSERTION]: 'a' != 'b'

assert.fail(1, 2, undefined, '>');
// AssertionError [ERR_ASSERTION]: 1 > 2

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

*Note*: In the last two cases `actual`, `expected`, and `operator` have no
In the last three cases `actual`, `expected`, and `operator` have no
influence on the error message.

```js
assert.fail();
// AssertionError [ERR_ASSERTION]: Failed

assert.fail('boom');
// AssertionError [ERR_ASSERTION]: boom

assert.fail('a', 'b');
// AssertionError [ERR_ASSERTION]: 'a' != 'b'
```

Example use of `stackStartFunction` for truncating the exception's stacktrace:

```js
function suppressFrame() {
assert.fail('a', 'b', undefined, '!==', suppressFrame);
Expand Down
9 changes: 9 additions & 0 deletions doc/api/deprecations.md
Original file line number Diff line number Diff line change
Expand Up @@ -847,6 +847,15 @@ Type: Documentation-only
The [`crypto.fips`][] property is deprecated. Please use `crypto.setFips()`
and `crypto.getFips()` instead.

<a id="DEP0XX"></a>
### DEP0XXX: Using `assert.fail()` with more than one argument.

Type: Runtime

Using `assert.fail()` with more than one argument has no benefit over writing an
individual error message. Either use `assert.fail()` with one argument or switch
to one of the other assert methods.

[`--pending-deprecation`]: cli.html#cli_pending_deprecation
[`Buffer.allocUnsafeSlow(size)`]: buffer.html#buffer_class_method_buffer_allocunsafeslow_size
[`Buffer.from(array)`]: buffer.html#buffer_class_method_buffer_from_array
Expand Down
16 changes: 14 additions & 2 deletions lib/assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ const ERR_DIFF_DEACTIVATED = 0;
const ERR_DIFF_NOT_EQUAL = 1;
const ERR_DIFF_EQUAL = 2;

let warned = false;

// The assert module provides functions that throw
// AssertionError's when particular conditions are not met. The
// assert module must conform to the following interface.
Expand Down Expand Up @@ -80,8 +82,18 @@ function fail(actual, expected, message, operator, stackStartFn) {
} else if (argsLen === 1) {
message = actual;
actual = undefined;
} else if (argsLen === 2) {
operator = '!=';
} else {
if (warned === false) {
warned = true;
process.emitWarning(
'assert.fail() with more than one argument is deprecated. ' +
'Please use assert.strictEqual() instead or only pass a message.',
'DeprecationWarning',
'DEP00XXX'
);
}
if (argsLen === 2)
operator = '!=';
}

innerFail({
Expand Down
64 changes: 64 additions & 0 deletions test/parallel/test-assert-fail-deprecation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
'use strict';

const common = require('../common');
const assert = require('assert');

common.expectWarning(
'DeprecationWarning',
'assert.fail() with more than one argument is deprecated. ' +
'Please use assert.strictEqual() instead or only pass a message.'
);

// Two args only, operator defaults to '!='
assert.throws(() => {
assert.fail('first', 'second');
}, {
code: 'ERR_ASSERTION',
name: 'AssertionError [ERR_ASSERTION]',
message: '\'first\' != \'second\'',
operator: '!=',
actual: 'first',
expected: 'second'
});

// Three args
assert.throws(() => {
assert.fail('ignored', 'ignored', 'another custom message');
}, {
code: 'ERR_ASSERTION',
name: 'AssertionError [ERR_ASSERTION]',
message: 'another custom message',
operator: undefined,
actual: 'ignored',
expected: 'ignored'
});

// Three args with custom Error
assert.throws(() => {
assert.fail(typeof 1, 'object', new TypeError('another custom message'));
}, {
name: 'TypeError',
message: 'another custom message',
operator: undefined,
actual: undefined,
expected: undefined,
code: undefined
});

// No third arg (but a fourth arg)
assert.throws(() => {
assert.fail('first', 'second', undefined, 'operator');
}, {
code: 'ERR_ASSERTION',
name: 'AssertionError [ERR_ASSERTION]',
message: '\'first\' operator \'second\'',
operator: 'operator',
actual: 'first',
expected: 'second'
});

// The stackFrameFunction should exclude the foo frame
assert.throws(
function foo() { assert.fail('first', 'second', 'message', '!==', foo); },
(err) => !/^\s*at\sfoo\b/m.test(err.stack)
);
71 changes: 8 additions & 63 deletions test/parallel/test-assert-fail.js
Original file line number Diff line number Diff line change
@@ -1,95 +1,40 @@
'use strict';

/* eslint-disable prefer-common-expectserror */

const common = require('../common');
require('../common');
const assert = require('assert');

// No args
assert.throws(
() => { assert.fail(); },
common.expectsError({
{
code: 'ERR_ASSERTION',
type: assert.AssertionError,
name: 'AssertionError [ERR_ASSERTION]',
message: 'Failed',
operator: undefined,
actual: undefined,
expected: undefined
})
}
);

// One arg = message
common.expectsError(() => {
assert.throws(() => {
assert.fail('custom message');
}, {
code: 'ERR_ASSERTION',
type: assert.AssertionError,
name: 'AssertionError [ERR_ASSERTION]',
message: 'custom message',
operator: undefined,
actual: undefined,
expected: undefined
});

// One arg = Error
common.expectsError(() => {
assert.throws(() => {
assert.fail(new TypeError('custom message'));
}, {
type: TypeError,
name: 'TypeError',
message: 'custom message',
operator: undefined,
actual: undefined,
expected: undefined
});

// Two args only, operator defaults to '!='
common.expectsError(() => {
assert.fail('first', 'second');
}, {
code: 'ERR_ASSERTION',
type: assert.AssertionError,
message: '\'first\' != \'second\'',
operator: '!=',
actual: 'first',
expected: 'second'
});

// Three args
common.expectsError(() => {
assert.fail('ignored', 'ignored', 'another custom message');
}, {
code: 'ERR_ASSERTION',
type: assert.AssertionError,
message: 'another custom message',
operator: undefined,
actual: 'ignored',
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');
}, {
code: 'ERR_ASSERTION',
type: assert.AssertionError,
message: '\'first\' operator \'second\'',
operator: 'operator',
actual: 'first',
expected: 'second'
});

// The stackFrameFunction should exclude the foo frame
assert.throws(
function foo() { assert.fail('first', 'second', 'message', '!==', foo); },
(err) => !/^\s*at\sfoo\b/m.test(err.stack)
);