Skip to content

Commit 287e1f2

Browse files
BridgeARaddaleax
authored andcommitted
assert: handle errors properly with deep*Equal
PR-URL: nodejs/node#15001 Reviewed-By: Rich Trott <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: Refael Ackermann <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent dfb9e90 commit 287e1f2

File tree

3 files changed

+36
-10
lines changed

3 files changed

+36
-10
lines changed

doc/api/assert.md

+5-2
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,12 @@ Only [enumerable "own" properties][] are considered. The
4747
non-enumerable properties — for such checks, consider using
4848
[`assert.deepStrictEqual()`][] instead. This can lead to some
4949
potentially surprising results. For example, the following example does not
50-
throw an `AssertionError` because the properties on the [`Error`][] object are
50+
throw an `AssertionError` because the properties on the [`RegExp`][] object are
5151
not enumerable:
5252

5353
```js
5454
// WARNING: This does not throw an AssertionError!
55-
assert.deepEqual(Error('a'), Error('b'));
55+
assert.deepEqual(/a/gi, new Date());
5656
```
5757

5858
An exception is made for [`Map`][] and [`Set`][]. Maps and Sets have their
@@ -104,6 +104,9 @@ parameter is undefined, a default error message is assigned.
104104
<!-- YAML
105105
added: v1.2.0
106106
changes:
107+
- version: REPLACEME
108+
pr-url: https://github.com/nodejs/node/pull/12142
109+
description: Error names and messages are now properly compared
107110
- version: v8.0.0
108111
pr-url: https://github.com/nodejs/node/pull/12142
109112
description: Set and Map content is also compared

lib/assert.js

+11
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,13 @@ function strictDeepEqual(actual, expected) {
199199
if (!areSimilarRegExps(actual, expected)) {
200200
return false;
201201
}
202+
} else if (actualTag === '[object Error]') {
203+
// Do not compare the stack as it might differ even though the error itself
204+
// is otherwise identical. The non-enumerable name should be identical as
205+
// the prototype is also identical. Otherwise this is caught later on.
206+
if (actual.message !== expected.message) {
207+
return false;
208+
}
202209
} else if (!isFloatTypedArrayTag(actualTag) && ArrayBuffer.isView(actual)) {
203210
if (!areSimilarTypedArrays(actual, expected)) {
204211
return false;
@@ -230,6 +237,10 @@ function looseDeepEqual(actual, expected) {
230237
if (isRegExp(actual) && isRegExp(expected)) {
231238
return areSimilarRegExps(actual, expected);
232239
}
240+
if (actual instanceof Error && expected instanceof Error) {
241+
if (actual.message !== expected.message || actual.name !== expected.name)
242+
return false;
243+
}
233244
const actualTag = objectToString(actual);
234245
const expectedTag = objectToString(expected);
235246
if (actualTag === expectedTag) {

test/parallel/test-assert-deep.js

+20-8
Original file line numberDiff line numberDiff line change
@@ -129,23 +129,23 @@ function assertDeepAndStrictEqual(a, b) {
129129
assert.deepStrictEqual(b, a);
130130
}
131131

132-
function assertNotDeepOrStrict(a, b) {
133-
assert.throws(() => assert.deepEqual(a, b), re`${a} deepEqual ${b}`);
134-
assert.throws(() => assert.deepStrictEqual(a, b),
132+
function assertNotDeepOrStrict(a, b, err) {
133+
assert.throws(() => assert.deepEqual(a, b), err || re`${a} deepEqual ${b}`);
134+
assert.throws(() => assert.deepStrictEqual(a, b), err ||
135135
re`${a} deepStrictEqual ${b}`);
136136

137-
assert.throws(() => assert.deepEqual(b, a), re`${b} deepEqual ${a}`);
138-
assert.throws(() => assert.deepStrictEqual(b, a),
137+
assert.throws(() => assert.deepEqual(b, a), err || re`${b} deepEqual ${a}`);
138+
assert.throws(() => assert.deepStrictEqual(b, a), err ||
139139
re`${b} deepStrictEqual ${a}`);
140140
}
141141

142-
function assertOnlyDeepEqual(a, b) {
142+
function assertOnlyDeepEqual(a, b, err) {
143143
assert.doesNotThrow(() => assert.deepEqual(a, b));
144-
assert.throws(() => assert.deepStrictEqual(a, b),
144+
assert.throws(() => assert.deepStrictEqual(a, b), err ||
145145
re`${a} deepStrictEqual ${b}`);
146146

147147
assert.doesNotThrow(() => assert.deepEqual(b, a));
148-
assert.throws(() => assert.deepStrictEqual(b, a),
148+
assert.throws(() => assert.deepStrictEqual(b, a), err ||
149149
re`${b} deepStrictEqual ${a}`);
150150
}
151151

@@ -469,4 +469,16 @@ assertOnlyDeepEqual(
469469
assertDeepAndStrictEqual([1, , , 3], [1, , , 3]);
470470
assertOnlyDeepEqual([1, , , 3], [1, , , 3, , , ]);
471471

472+
// Handle different error messages
473+
{
474+
const err1 = new Error('foo1');
475+
const err2 = new Error('foo2');
476+
const err3 = new TypeError('foo1');
477+
assertNotDeepOrStrict(err1, err2, assert.AssertionError);
478+
assertNotDeepOrStrict(err1, err3, assert.AssertionError);
479+
// TODO: evaluate if this should throw or not. The same applies for RegExp
480+
// Date and any object that has the same keys but not the same prototype.
481+
assertOnlyDeepEqual(err1, {}, assert.AssertionError);
482+
}
483+
472484
/* eslint-enable */

0 commit comments

Comments
 (0)