Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit f2af930

Browse filesBrowse files
BridgeARMylesBorins
authored andcommitted
assert: .throws accept objects
From now on it is possible to use a validation object in throws instead of the other possibilites. Backport-PR-URL: #23223 PR-URL: #17584 Refs: #17557 Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Ron Korving <ron@ronkorving.nl> Reviewed-By: Yuta Hiroto <hello@about-hiroppy.com>
1 parent 147aeed commit f2af930
Copy full SHA for f2af930

File tree

Expand file treeCollapse file tree

3 files changed

+138
-17
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

3 files changed

+138
-17
lines changed
Open diff view settings
Collapse file

‎doc/api/assert.md‎

Copy file name to clipboardExpand all lines: doc/api/assert.md
+23-3Lines changed: 23 additions & 3 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -635,18 +635,21 @@ If the values are not strictly equal, an `AssertionError` is thrown with a
635635
<!-- YAML
636636
added: v0.1.21
637637
changes:
638+
- version: REPLACEME
639+
pr-url: https://github.com/nodejs/node/pull/REPLACEME
640+
description: The `error` parameter can now be an object as well.
638641
- version: v4.2.0
639642
pr-url: https://github.com/nodejs/node/pull/3276
640643
description: The `error` parameter can now be an arrow function.
641644
-->
642645
* `block` {Function}
643-
* `error` {RegExp|Function}
646+
* `error` {RegExp|Function|object}
644647
* `message` {any}
645648

646649
Expects the function `block` to throw an error.
647650

648-
If specified, `error` can be a constructor, [`RegExp`][], or validation
649-
function.
651+
If specified, `error` can be a constructor, [`RegExp`][], a validation
652+
function, or an object where each property will be tested for.
650653

651654
If specified, `message` will be the message provided by the `AssertionError` if
652655
the block fails to throw.
@@ -689,6 +692,23 @@ assert.throws(
689692
);
690693
```
691694

695+
Custom error object / error instance:
696+
697+
```js
698+
assert.throws(
699+
() => {
700+
const err = new TypeError('Wrong value');
701+
err.code = 404;
702+
throw err;
703+
},
704+
{
705+
name: 'TypeError',
706+
message: 'Wrong value'
707+
// Note that only properties on the error object will be tested!
708+
}
709+
);
710+
```
711+
692712
Note that `error` can not be a string. If a string is provided as the second
693713
argument, then `error` is assumed to be omitted and the string will be used for
694714
`message` instead. This can lead to easy-to-miss mistakes. Please read the
Collapse file

‎lib/assert.js‎

Copy file name to clipboardExpand all lines: lib/assert.js
+39-4Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const { isSet, isMap, isDate, isRegExp } = process.binding('util');
2525
const { objectToString } = require('internal/util');
2626
const { isArrayBufferView } = require('internal/util/types');
2727
const errors = require('internal/errors');
28+
const { inspect } = require('util');
2829

2930
// The assert module provides functions that throw
3031
// AssertionError's when particular conditions are not met. The
@@ -660,10 +661,44 @@ assert.notStrictEqual = function notStrictEqual(actual, expected, message) {
660661
}
661662
};
662663

663-
function expectedException(actual, expected) {
664+
function createMsg(msg, key, actual, expected) {
665+
if (msg)
666+
return msg;
667+
return `${key}: expected ${inspect(expected[key])}, ` +
668+
`not ${inspect(actual[key])}`;
669+
}
670+
671+
function expectedException(actual, expected, msg) {
664672
if (typeof expected !== 'function') {
665-
// Should be a RegExp, if not fail hard
666-
return expected.test(actual);
673+
if (expected instanceof RegExp)
674+
return expected.test(actual);
675+
// assert.doesNotThrow does not accept objects.
676+
if (arguments.length === 2) {
677+
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'expected',
678+
['Function', 'RegExp'], expected);
679+
}
680+
// The name and message could be non enumerable. Therefore test them
681+
// explicitly.
682+
if ('name' in expected) {
683+
assert.strictEqual(
684+
actual.name,
685+
expected.name,
686+
createMsg(msg, 'name', actual, expected));
687+
}
688+
if ('message' in expected) {
689+
assert.strictEqual(
690+
actual.message,
691+
expected.message,
692+
createMsg(msg, 'message', actual, expected));
693+
}
694+
const keys = Object.keys(expected);
695+
for (const key of keys) {
696+
assert.deepStrictEqual(
697+
actual[key],
698+
expected[key],
699+
createMsg(msg, key, actual, expected));
700+
}
701+
return true;
667702
}
668703
// Guard instanceof against arrow functions as they don't have a prototype.
669704
if (expected.prototype !== undefined && actual instanceof expected) {
@@ -716,7 +751,7 @@ assert.throws = function throws(block, error, message) {
716751
stackStartFn: throws
717752
});
718753
}
719-
if (error && expectedException(actual, error) === false) {
754+
if (error && expectedException(actual, error, message) === false) {
720755
throw actual;
721756
}
722757
};
Collapse file

‎test/parallel/test-assert.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-assert.js
+76-10Lines changed: 76 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,6 @@ assert.ok(a.AssertionError.prototype instanceof Error,
3636

3737
assert.throws(makeBlock(a, false), a.AssertionError, 'ok(false)');
3838

39-
// Using a object as second arg results in a failure
40-
assert.throws(
41-
() => { assert.throws(() => { throw new Error(); }, { foo: 'bar' }); },
42-
common.expectsError({
43-
type: TypeError,
44-
message: 'expected.test is not a function'
45-
})
46-
);
47-
48-
4939
assert.doesNotThrow(makeBlock(a, true), a.AssertionError, 'ok(true)');
5040

5141
assert.doesNotThrow(makeBlock(a, 'test', 'ok(\'test\')'));
@@ -742,3 +732,79 @@ common.expectsError(
742732
'Received type string'
743733
}
744734
);
735+
736+
{
737+
const errFn = () => {
738+
const err = new TypeError('Wrong value');
739+
err.code = 404;
740+
throw err;
741+
};
742+
const errObj = {
743+
name: 'TypeError',
744+
message: 'Wrong value'
745+
};
746+
assert.throws(errFn, errObj);
747+
748+
errObj.code = 404;
749+
assert.throws(errFn, errObj);
750+
751+
errObj.code = '404';
752+
common.expectsError(
753+
// eslint-disable-next-line no-restricted-syntax
754+
() => assert.throws(errFn, errObj),
755+
{
756+
code: 'ERR_ASSERTION',
757+
type: assert.AssertionError,
758+
message: 'code: expected \'404\', not 404'
759+
}
760+
);
761+
762+
errObj.code = 404;
763+
errObj.foo = 'bar';
764+
common.expectsError(
765+
// eslint-disable-next-line no-restricted-syntax
766+
() => assert.throws(errFn, errObj),
767+
{
768+
code: 'ERR_ASSERTION',
769+
type: assert.AssertionError,
770+
message: 'foo: expected \'bar\', not undefined'
771+
}
772+
);
773+
774+
common.expectsError(
775+
() => assert.throws(() => { throw new Error(); }, { foo: 'bar' }, 'foobar'),
776+
{
777+
type: assert.AssertionError,
778+
code: 'ERR_ASSERTION',
779+
message: 'foobar'
780+
}
781+
);
782+
783+
common.expectsError(
784+
() => assert.doesNotThrow(() => { throw new Error(); }, { foo: 'bar' }),
785+
{
786+
type: TypeError,
787+
code: 'ERR_INVALID_ARG_TYPE',
788+
message: 'The "expected" argument must be one of type Function or ' +
789+
'RegExp. Received type object'
790+
}
791+
);
792+
793+
assert.throws(() => { throw new Error('e'); }, new Error('e'));
794+
common.expectsError(
795+
() => assert.throws(() => { throw new TypeError('e'); }, new Error('e')),
796+
{
797+
type: assert.AssertionError,
798+
code: 'ERR_ASSERTION',
799+
message: "name: expected 'Error', not 'TypeError'"
800+
}
801+
);
802+
common.expectsError(
803+
() => assert.throws(() => { throw new Error('foo'); }, new Error('')),
804+
{
805+
type: assert.AssertionError,
806+
code: 'ERR_ASSERTION',
807+
message: "message: expected '', not 'foo'"
808+
}
809+
);
810+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.