Skip to content

Commit 3db0829

Browse files
committed
assert: show diff when doing partial comparisons
1 parent 80c0055 commit 3db0829

File tree

6 files changed

+116
-10
lines changed

6 files changed

+116
-10
lines changed

lib/assert.js

+3-4
Original file line numberDiff line numberDiff line change
@@ -604,10 +604,9 @@ function compareBranch(
604604
// Check if all expected keys and values match
605605
for (let i = 0; i < keysExpected.length; i++) {
606606
const key = keysExpected[i];
607-
assert(
608-
ReflectHas(actual, key),
609-
new AssertionError({ message: `Expected key ${String(key)} not found in actual object` }),
610-
);
607+
if (!ReflectHas(actual, key)) {
608+
return false;
609+
}
611610
if (!compareBranch(actual[key], expected[key], comparedObjects)) {
612611
return false;
613612
}

lib/internal/assert/assertion_error.js

+10-3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const { myersDiff, printMyersDiff, printSimpleMyersDiff } = require('internal/as
2626

2727
const kReadableOperator = {
2828
deepStrictEqual: 'Expected values to be strictly deep-equal:',
29+
partialDeepStrictEqual: 'Expected values to be partially and strictly deep-equal:',
2930
strictEqual: 'Expected values to be strictly equal:',
3031
strictEqualObject: 'Expected "actual" to be reference-equal to "expected":',
3132
deepEqual: 'Expected values to be loosely deep-equal:',
@@ -41,6 +42,8 @@ const kReadableOperator = {
4142
const kMaxShortStringLength = 12;
4243
const kMaxLongStringLength = 512;
4344

45+
const kMethodsWithCustomMessageDiff = ['deepStrictEqual', 'strictEqual', 'partialDeepStrictEqual'];
46+
4447
function copyError(source) {
4548
const target = ObjectAssign(
4649
{ __proto__: ObjectGetPrototypeOf(source) },
@@ -210,9 +213,13 @@ function createErrDiff(actual, expected, operator, customMessage) {
210213
const checkCommaDisparity = actual != null && typeof actual === 'object';
211214
const diff = myersDiff(inspectedSplitActual, inspectedSplitExpected, checkCommaDisparity);
212215

213-
const myersDiffMessage = printMyersDiff(diff);
216+
const myersDiffMessage = printMyersDiff(diff, operator);
214217
message = myersDiffMessage.message;
215218

219+
if (operator === 'partialDeepStrictEqual') {
220+
header = `${colors.gray}${colors.hasColors ? '' : '+ '}actual${colors.white} ${colors.red}- expected${colors.white}`;
221+
}
222+
216223
if (myersDiffMessage.skipped) {
217224
skipped = true;
218225
}
@@ -255,7 +262,7 @@ class AssertionError extends Error {
255262
if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = 0;
256263

257264
if (message != null) {
258-
if (operator === 'deepStrictEqual' || operator === 'strictEqual') {
265+
if (kMethodsWithCustomMessageDiff.includes(operator)) {
259266
super(createErrDiff(actual, expected, operator, message));
260267
} else {
261268
super(String(message));
@@ -275,7 +282,7 @@ class AssertionError extends Error {
275282
expected = copyError(expected);
276283
}
277284

278-
if (operator === 'deepStrictEqual' || operator === 'strictEqual') {
285+
if (kMethodsWithCustomMessageDiff.includes(operator)) {
279286
super(createErrDiff(actual, expected, operator, message));
280287
} else if (operator === 'notDeepStrictEqual' ||
281288
operator === 'notStrictEqual') {

lib/internal/assert/myers_diff.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ function printSimpleMyersDiff(diff) {
122122
return `\n${message}`;
123123
}
124124

125-
function printMyersDiff(diff, simple = false) {
125+
function printMyersDiff(diff, operator) {
126126
let message = '';
127127
let skipped = false;
128128
let nopCount = 0;
@@ -148,7 +148,11 @@ function printMyersDiff(diff, simple = false) {
148148
}
149149

150150
if (type === 'insert') {
151-
message += `${colors.green}+${colors.white} ${value}\n`;
151+
if (operator === 'partialDeepStrictEqual') {
152+
message += `${colors.gray}${colors.hasColors ? ' ' : '+'} ${value}${colors.white}\n`;
153+
} else {
154+
message += `${colors.green}+${colors.white} ${value}\n`;
155+
}
152156
} else if (type === 'delete') {
153157
message += `${colors.red}-${colors.white} ${value}\n`;
154158
} else if (type === 'nop') {

test/parallel/test-assert.js

+11
Original file line numberDiff line numberDiff line change
@@ -1351,6 +1351,17 @@ test('Additional assert', () => {
13511351
}
13521352
);
13531353

1354+
assert.throws(
1355+
() => {
1356+
assert.partialDeepStrictEqual({ a: true }, { a: false }, 'custom message');
1357+
},
1358+
{
1359+
code: 'ERR_ASSERTION',
1360+
name: 'AssertionError',
1361+
message: 'custom message\n+ actual - expected\n\n {\n+ a: true\n- a: false\n }\n'
1362+
}
1363+
);
1364+
13541365
{
13551366
let threw = false;
13561367
try {

test/pseudo-tty/test-assert-colors.js

+63-1
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@
22
require('../common');
33
const assert = require('assert').strict;
44

5-
assert.throws(() => {
5+
function setup() {
66
process.env.FORCE_COLOR = '1';
77
delete process.env.NODE_DISABLE_COLORS;
88
delete process.env.NO_COLOR;
9+
}
10+
11+
assert.throws(() => {
12+
setup();
913
assert.deepStrictEqual([1, 2, 2, 2, 2], [2, 2, 2, 2, 2]);
1014
}, (err) => {
1115
const expected = 'Expected values to be strictly deep-equal:\n' +
@@ -19,6 +23,64 @@ assert.throws(() => {
1923
'\x1B[39m 2,\n' +
2024
'\x1B[31m-\x1B[39m 2\n' +
2125
'\x1B[39m ]\n';
26+
2227
assert.strictEqual(err.message, expected);
2328
return true;
2429
});
30+
31+
{
32+
// TODO(puskin94): remove the emitWarning override once the partialDeepStrictEqual method is not experimental anymore
33+
// Suppress warnings, necessary otherwise the tools/pseudo-tty.py runner will fail
34+
const originalEmitWarning = process.emitWarning;
35+
process.emitWarning = () => {};
36+
37+
assert.throws(() => {
38+
setup();
39+
assert.partialDeepStrictEqual([1, 2, 3, 5], [4, 5]);
40+
}, (err) => {
41+
const expected = 'Expected values to be partially and strictly deep-equal:\n' +
42+
'\x1B[90mactual\x1B[39m \x1B[31m- expected\x1B[39m\n' +
43+
'\n' +
44+
'\x1B[39m [\n' +
45+
'\x1B[90m 1,\x1B[39m\n' +
46+
'\x1B[90m 2,\x1B[39m\n' +
47+
'\x1B[90m 3,\x1B[39m\n' +
48+
'\x1B[31m-\x1B[39m 4,\n' +
49+
'\x1B[39m 5\n' +
50+
'\x1B[39m ]\n';
51+
52+
assert.strictEqual(err.message, expected);
53+
return true;
54+
});
55+
56+
process.emitWarning = originalEmitWarning; // Restore original process.emitWarning
57+
}
58+
59+
{
60+
// TODO(puskin94): remove the emitWarning override once the partialDeepStrictEqual method is not experimental anymore
61+
// Suppress warnings, necessary otherwise the tools/pseudo-tty.py runner will fail
62+
const originalEmitWarning = process.emitWarning;
63+
process.emitWarning = () => {};
64+
65+
assert.throws(() => {
66+
setup();
67+
assert.partialDeepStrictEqual({ a: 1, b: 2, c: 3, d: 5 }, { z: 4, b: 5 });
68+
}, (err) => {
69+
const expected = 'Expected values to be partially and strictly deep-equal:\n' +
70+
'\x1B[90mactual\x1B[39m \x1B[31m- expected\x1B[39m\n' +
71+
'\n' +
72+
'\x1B[39m {\n' +
73+
'\x1B[90m a: 1,\x1B[39m\n' +
74+
'\x1B[90m b: 2,\x1B[39m\n' +
75+
'\x1B[90m c: 3,\x1B[39m\n' +
76+
'\x1B[90m d: 5\x1B[39m\n' +
77+
'\x1B[31m-\x1B[39m b: 5,\n' +
78+
'\x1B[31m-\x1B[39m z: 4\n' +
79+
'\x1B[39m }\n';
80+
81+
assert.strictEqual(err.message, expected);
82+
return true;
83+
});
84+
85+
process.emitWarning = originalEmitWarning; // Restore original process.emitWarning
86+
}

test/pseudo-tty/test-assert-no-color.js

+23
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,26 @@ assert.throws(
1717
'- foo: \'bar\'\n' +
1818
'- }\n',
1919
});
20+
21+
{
22+
// TODO(puskin94): remove the emitWarning override once the partialDeepStrictEqual method is not experimental anymore
23+
// Suppress warnings, necessary otherwise the tools/pseudo-tty.py runner will fail
24+
const originalEmitWarning = process.emitWarning;
25+
process.emitWarning = () => {};
26+
27+
assert.throws(
28+
() => {
29+
assert.partialDeepStrictEqual({}, { foo: 'bar' });
30+
},
31+
{
32+
message: 'Expected values to be partially and strictly deep-equal:\n' +
33+
'+ actual - expected\n' +
34+
'\n' +
35+
'+ {}\n' +
36+
'- {\n' +
37+
"- foo: 'bar'\n" +
38+
'- }\n',
39+
});
40+
41+
process.emitWarning = originalEmitWarning; // Restore original process.emitWarning
42+
}

0 commit comments

Comments
 (0)