Skip to content

Commit c7cef58

Browse files
committed
assert: improve assert.throws
This switches the assert.throws output to the one used in strict mode if a error object is used for comparison. From now on it will show the complete difference between two objects instead of only showing the first failing property. It also fixes detecting properties with a undefined value and fails in case the thrown error does not contain the value at all.
1 parent f24d0ec commit c7cef58

File tree

5 files changed

+80
-45
lines changed

5 files changed

+80
-45
lines changed

lib/assert.js

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -365,13 +365,38 @@ assert.notStrictEqual = function notStrictEqual(actual, expected, message) {
365365
}
366366
};
367367

368-
function compareExceptionKey(actual, expected, key, msg) {
369-
if (!isDeepStrictEqual(actual[key], expected[key])) {
368+
class Comparison {
369+
constructor(obj, keys) {
370+
for (const key of keys) {
371+
if (key in obj)
372+
this[key] = obj[key];
373+
}
374+
}
375+
}
376+
377+
function compareExceptionKey(actual, expected, key, message, keys) {
378+
if (!(key in actual) || !isDeepStrictEqual(actual[key], expected[key])) {
379+
if (!message) {
380+
// Create placeholder objects to create a nice output.
381+
const a = new Comparison(actual, keys);
382+
const b = new Comparison(expected, keys);
383+
384+
const tmpLimit = Error.stackTraceLimit;
385+
Error.stackTraceLimit = 0;
386+
const err = new AssertionError({
387+
actual: a,
388+
expected: b,
389+
operator: 'deepStrictEqual',
390+
stackStartFn: assert.throws,
391+
errorDiff: ERR_DIFF_EQUAL
392+
});
393+
Error.stackTraceLimit = tmpLimit;
394+
message = err.message;
395+
}
370396
innerFail({
371-
actual: actual[key],
372-
expected: expected[key],
373-
message: msg || `${key}: expected ${inspect(expected[key])}, ` +
374-
`not ${inspect(actual[key])}`,
397+
actual,
398+
expected,
399+
message,
375400
operator: 'throws',
376401
stackStartFn: assert.throws
377402
});
@@ -388,16 +413,14 @@ function expectedException(actual, expected, msg) {
388413
'expected', ['Function', 'RegExp'], expected
389414
);
390415
}
391-
// The name and message could be non enumerable. Therefore test them
392-
// explicitly.
393-
if ('name' in expected) {
394-
compareExceptionKey(actual, expected, 'name', msg);
395-
}
396-
if ('message' in expected) {
397-
compareExceptionKey(actual, expected, 'message', msg);
416+
const keys = Object.keys(expected);
417+
// Special handle errors to make sure the name and the message are compared
418+
// as well.
419+
if (expected instanceof Error) {
420+
keys.push('name', 'message');
398421
}
399-
for (const key of Object.keys(expected)) {
400-
compareExceptionKey(actual, expected, key, msg);
422+
for (const key of keys) {
423+
compareExceptionKey(actual, expected, key, msg, keys);
401424
}
402425
return true;
403426
}

test/message/assert_throws_stack.out

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@ assert.js:*
22
throw new AssertionError(obj);
33
^
44

5-
AssertionError [ERR_ASSERTION]: bar: expected true, not undefined
5+
AssertionError [ERR_ASSERTION]: Input A expected to deepStrictEqual input B:
6+
+ expected - actual
7+
8+
- Comparison {}
9+
+ Comparison {
10+
+ bar: true
11+
+ }
612
at Object.<anonymous> (*assert_throws_stack.js:*:*)
713
at *
814
at *

test/parallel/test-assert-fail-deprecation.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,7 @@ assert.throws(() => {
3838
assert.fail(typeof 1, 'object', new TypeError('another custom message'));
3939
}, {
4040
name: 'TypeError',
41-
message: 'another custom message',
42-
operator: undefined,
43-
actual: undefined,
44-
expected: undefined,
45-
code: undefined
41+
message: 'another custom message'
4642
});
4743

4844
// No third arg (but a fourth arg)

test/parallel/test-assert-fail.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,5 @@ assert.throws(() => {
3333
assert.fail(new TypeError('custom message'));
3434
}, {
3535
name: 'TypeError',
36-
message: 'custom message',
37-
operator: undefined,
38-
actual: undefined,
39-
expected: undefined
36+
message: 'custom message'
4037
});

test/parallel/test-assert.js

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ const { writeFileSync, unlinkSync } = require('fs');
3434
const { inspect } = require('util');
3535
const a = assert;
3636

37+
const colors = process.stdout.isTTY && process.stdout.getColorDepth() > 1;
38+
const start = 'Input A expected to deepStrictEqual input B:';
39+
const actExp = colors ?
40+
'\u001b[32m+ expected\u001b[39m \u001b[31m- actual\u001b[39m' :
41+
'+ expected - actual';
42+
3743
assert.ok(a.AssertionError.prototype instanceof Error,
3844
'a.AssertionError instanceof Error');
3945

@@ -440,11 +446,6 @@ common.expectsError(
440446
Error.stackTraceLimit = tmpLimit;
441447

442448
// Test error diffs.
443-
const colors = process.stdout.isTTY && process.stdout.getColorDepth() > 1;
444-
const start = 'Input A expected to deepStrictEqual input B:';
445-
const actExp = colors ?
446-
'\u001b[32m+ expected\u001b[39m \u001b[31m- actual\u001b[39m' :
447-
'+ expected - actual';
448449
const plus = colors ? '\u001b[32m+\u001b[39m' : '+';
449450
const minus = colors ? '\u001b[31m-\u001b[39m' : '-';
450451
let message = [
@@ -769,24 +770,32 @@ common.expectsError(
769770
errObj.code = 404;
770771
assert.throws(errFn, errObj);
771772

772-
errObj.code = '404';
773-
common.expectsError(
773+
// Fail in case a expected property is undefined and not existent on the
774+
// error.
775+
errObj.foo = undefined;
776+
assert.throws(
774777
() => assert.throws(errFn, errObj),
775778
{
776779
code: 'ERR_ASSERTION',
777-
type: assert.AssertionError,
778-
message: 'code: expected \'404\', not 404'
780+
name: 'AssertionError [ERR_ASSERTION]',
781+
message: `${start}\n${actExp}\n\n` +
782+
" Comparison {\n name: 'TypeError',\n" +
783+
" message: 'Wrong value',\n- code: 404\n" +
784+
'+ code: 404,\n+ foo: undefined\n }'
779785
}
780786
);
781787

782-
errObj.code = 404;
783-
errObj.foo = 'bar';
784-
common.expectsError(
788+
// Show multiple wrong properties at the same time.
789+
errObj.code = '404';
790+
assert.throws(
785791
() => assert.throws(errFn, errObj),
786792
{
787793
code: 'ERR_ASSERTION',
788-
type: assert.AssertionError,
789-
message: 'foo: expected \'bar\', not undefined'
794+
name: 'AssertionError [ERR_ASSERTION]',
795+
message: `${start}\n${actExp}\n\n` +
796+
" Comparison {\n name: 'TypeError',\n" +
797+
" message: 'Wrong value',\n- code: 404\n" +
798+
"+ code: '404',\n+ foo: undefined\n }"
790799
}
791800
);
792801

@@ -810,20 +819,24 @@ common.expectsError(
810819
);
811820

812821
assert.throws(() => { throw new Error('e'); }, new Error('e'));
813-
common.expectsError(
822+
assert.throws(
814823
() => assert.throws(() => { throw new TypeError('e'); }, new Error('e')),
815824
{
816-
type: assert.AssertionError,
825+
name: 'AssertionError [ERR_ASSERTION]',
817826
code: 'ERR_ASSERTION',
818-
message: "name: expected 'Error', not 'TypeError'"
827+
message: `${start}\n${actExp}\n\n` +
828+
" Comparison {\n- name: 'TypeError',\n+ name: 'Error'," +
829+
"\n message: 'e'\n }"
819830
}
820831
);
821-
common.expectsError(
832+
assert.throws(
822833
() => assert.throws(() => { throw new Error('foo'); }, new Error('')),
823834
{
824-
type: assert.AssertionError,
835+
name: 'AssertionError [ERR_ASSERTION]',
825836
code: 'ERR_ASSERTION',
826-
message: "message: expected '', not 'foo'"
837+
message: `${start}\n${actExp}\n\n` +
838+
" Comparison {\n name: 'Error',\n- message: 'foo'" +
839+
"\n+ message: ''\n }"
827840
}
828841
);
829842

0 commit comments

Comments
 (0)