diff --git a/doc/api/assert.md b/doc/api/assert.md index c2dff91d0391c2..9c5c142a96e937 100644 --- a/doc/api/assert.md +++ b/doc/api/assert.md @@ -47,12 +47,12 @@ Only [enumerable "own" properties][] are considered. The non-enumerable properties — for such checks, consider using [`assert.deepStrictEqual()`][] instead. This can lead to some potentially surprising results. For example, the following example does not -throw an `AssertionError` because the properties on the [`Error`][] object are +throw an `AssertionError` because the properties on the [`RegExp`][] object are not enumerable: ```js // WARNING: This does not throw an AssertionError! -assert.deepEqual(Error('a'), Error('b')); +assert.deepEqual(/a/gi, new Date()); ``` 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. <!-- YAML added: v1.2.0 changes: + - version: REPLACEME + pr-url: https://github.com/nodejs/node/pull/12142 + description: Error names and messages are now properly compared - version: v8.0.0 pr-url: https://github.com/nodejs/node/pull/12142 description: Set and Map content is also compared diff --git a/lib/assert.js b/lib/assert.js index e120a981346640..06b4815ea6cfe6 100644 --- a/lib/assert.js +++ b/lib/assert.js @@ -197,6 +197,13 @@ function strictDeepEqual(actual, expected) { if (!areSimilarRegExps(actual, expected)) { return false; } + } else if (actualTag === '[object Error]') { + // Do not compare the stack as it might differ even though the error itself + // is otherwise identical. The non-enumerable name should be identical as + // the prototype is also identical. Otherwise this is caught later on. + if (actual.message !== expected.message) { + return false; + } } else if (!isFloatTypedArrayTag(actualTag) && ArrayBuffer.isView(actual)) { if (!areSimilarTypedArrays(actual, expected)) { return false; @@ -228,6 +235,10 @@ function looseDeepEqual(actual, expected) { if (util.isRegExp(actual) && util.isRegExp(expected)) { return areSimilarRegExps(actual, expected); } + if (actual instanceof Error && expected instanceof Error) { + if (actual.message !== expected.message || actual.name !== expected.name) + return false; + } const actualTag = objectToString(actual); const expectedTag = objectToString(expected); if (actualTag === expectedTag) { diff --git a/test/parallel/test-assert-deep.js b/test/parallel/test-assert-deep.js index 068950a33d3c39..74c4eb44ffc7b4 100644 --- a/test/parallel/test-assert-deep.js +++ b/test/parallel/test-assert-deep.js @@ -129,23 +129,23 @@ function assertDeepAndStrictEqual(a, b) { assert.deepStrictEqual(b, a); } -function assertNotDeepOrStrict(a, b) { - assert.throws(() => assert.deepEqual(a, b), re`${a} deepEqual ${b}`); - assert.throws(() => assert.deepStrictEqual(a, b), +function assertNotDeepOrStrict(a, b, err) { + assert.throws(() => assert.deepEqual(a, b), err || re`${a} deepEqual ${b}`); + assert.throws(() => assert.deepStrictEqual(a, b), err || re`${a} deepStrictEqual ${b}`); - assert.throws(() => assert.deepEqual(b, a), re`${b} deepEqual ${a}`); - assert.throws(() => assert.deepStrictEqual(b, a), + assert.throws(() => assert.deepEqual(b, a), err || re`${b} deepEqual ${a}`); + assert.throws(() => assert.deepStrictEqual(b, a), err || re`${b} deepStrictEqual ${a}`); } -function assertOnlyDeepEqual(a, b) { +function assertOnlyDeepEqual(a, b, err) { assert.doesNotThrow(() => assert.deepEqual(a, b)); - assert.throws(() => assert.deepStrictEqual(a, b), + assert.throws(() => assert.deepStrictEqual(a, b), err || re`${a} deepStrictEqual ${b}`); assert.doesNotThrow(() => assert.deepEqual(b, a)); - assert.throws(() => assert.deepStrictEqual(b, a), + assert.throws(() => assert.deepStrictEqual(b, a), err || re`${b} deepStrictEqual ${a}`); } @@ -407,4 +407,16 @@ assertOnlyDeepEqual( assertDeepAndStrictEqual([1, , , 3], [1, , , 3]); assertOnlyDeepEqual([1, , , 3], [1, , , 3, , , ]); +// Handle different error messages +{ + const err1 = new Error('foo1'); + const err2 = new Error('foo2'); + const err3 = new TypeError('foo1'); + assertNotDeepOrStrict(err1, err2, assert.AssertionError); + assertNotDeepOrStrict(err1, err3, assert.AssertionError); + // TODO: evaluate if this should throw or not. The same applies for RegExp + // Date and any object that has the same keys but not the same prototype. + assertOnlyDeepEqual(err1, {}, assert.AssertionError); +} + /* eslint-enable */