Skip to content

Commit bcf0e5d

Browse files
BridgeARMylesBorins
authored andcommitted
assert: handle errors properly with deep*Equal
PR-URL: #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 2aec977 commit bcf0e5d

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
@@ -197,6 +197,13 @@ function strictDeepEqual(actual, expected) {
197197
if (!areSimilarRegExps(actual, expected)) {
198198
return false;
199199
}
200+
} else if (actualTag === '[object Error]') {
201+
// Do not compare the stack as it might differ even though the error itself
202+
// is otherwise identical. The non-enumerable name should be identical as
203+
// the prototype is also identical. Otherwise this is caught later on.
204+
if (actual.message !== expected.message) {
205+
return false;
206+
}
200207
} else if (!isFloatTypedArrayTag(actualTag) && ArrayBuffer.isView(actual)) {
201208
if (!areSimilarTypedArrays(actual, expected)) {
202209
return false;
@@ -228,6 +235,10 @@ function looseDeepEqual(actual, expected) {
228235
if (util.isRegExp(actual) && util.isRegExp(expected)) {
229236
return areSimilarRegExps(actual, expected);
230237
}
238+
if (actual instanceof Error && expected instanceof Error) {
239+
if (actual.message !== expected.message || actual.name !== expected.name)
240+
return false;
241+
}
231242
const actualTag = objectToString(actual);
232243
const expectedTag = objectToString(expected);
233244
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

@@ -407,4 +407,16 @@ assertOnlyDeepEqual(
407407
assertDeepAndStrictEqual([1, , , 3], [1, , , 3]);
408408
assertOnlyDeepEqual([1, , , 3], [1, , , 3, , , ]);
409409

410+
// Handle different error messages
411+
{
412+
const err1 = new Error('foo1');
413+
const err2 = new Error('foo2');
414+
const err3 = new TypeError('foo1');
415+
assertNotDeepOrStrict(err1, err2, assert.AssertionError);
416+
assertNotDeepOrStrict(err1, err3, assert.AssertionError);
417+
// TODO: evaluate if this should throw or not. The same applies for RegExp
418+
// Date and any object that has the same keys but not the same prototype.
419+
assertOnlyDeepEqual(err1, {}, assert.AssertionError);
420+
}
421+
410422
/* eslint-enable */

0 commit comments

Comments
 (0)