From 0518b9edf33bfffac53ac5f706694a205ff754a2 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Tue, 3 Jul 2018 02:06:57 +0200 Subject: [PATCH] assert: multiple improvements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1) Switched + / - and red / green in diffs. It seems like that style is more natural to most people. 2) Short primitives do not use the diff anymore. Especially short numbers can be read well like 1 !== 2. Cases that can not be displayed like that (e.g., -0 and +0) use the regular diff output. 3) Improved error descriptions. It was not always clear what the messages stood for. That should now be resolved. 4) Added a position indicator for single lines in case a tty is used and the line is shorter than the visual columns. 5) Color detection is now done by checking stderr instead of stdout. PR-URL: https://github.com/nodejs/node/pull/21628 Reviewed-By: Michaƫl Zasso Reviewed-By: Matteo Collina Reviewed-By: Anna Henningsen Reviewed-By: James M Snell Reviewed-By: Vse Mozhet Byt --- doc/api/assert.md | 100 +++++++++-------- lib/internal/assert.js | 134 ++++++++++++++-------- test/message/assert_throws_stack.out | 12 +- test/message/core_line_numbers.out | 2 +- test/message/error_exit.out | 7 +- test/parallel/test-assert-checktag.js | 8 +- test/parallel/test-assert-deep.js | 70 ++++++------ test/parallel/test-assert.js | 154 ++++++++++++++------------ test/parallel/test-internal-errors.js | 4 +- test/pseudo-tty/test-assert-colors.js | 8 +- 10 files changed, 281 insertions(+), 218 deletions(-) diff --git a/doc/api/assert.md b/doc/api/assert.md index baa7c2f8aa0..96800217f68 100644 --- a/doc/api/assert.md +++ b/doc/api/assert.md @@ -108,15 +108,15 @@ Example error diff: const assert = require('assert').strict; assert.deepEqual([[[1, 2, 3]], 4, 5], [[[1, 2, '3']], 4, 5]); -// AssertionError: Input A expected to strictly deep-equal input B: -// + expected - actual ... Lines skipped +// AssertionError: Expected inputs to be strictly deep-equal: +// + actual - expected ... Lines skipped // // [ // [ // ... // 2, -// - 3 -// + '3' +// + 3 +// - '3' // ], // ... // 5 @@ -315,11 +315,12 @@ const assert = require('assert').strict; // This fails because 1 !== '1'. assert.deepStrictEqual({ a: 1 }, { a: '1' }); -// AssertionError: Input A expected to strictly deep-equal input B: -// + expected - actual +// AssertionError: Expected inputs to be strictly deep-equal: +// + actual - expected +// // { -// - a: 1 -// + a: '1' +// + a: 1 +// - a: '1' // } // The following objects don't have own properties @@ -330,27 +331,30 @@ Object.setPrototypeOf(fakeDate, Date.prototype); // Different [[Prototype]]: assert.deepStrictEqual(object, fakeDate); -// AssertionError: Input A expected to strictly deep-equal input B: -// + expected - actual -// - {} -// + Date {} +// AssertionError: Expected inputs to be strictly deep-equal: +// + actual - expected +// +// + {} +// - Date {} // Different type tags: assert.deepStrictEqual(date, fakeDate); -// AssertionError: Input A expected to strictly deep-equal input B: -// + expected - actual -// - 2018-04-26T00:49:08.604Z -// + Date {} +// AssertionError: Expected inputs to be strictly deep-equal: +// + actual - expected +// +// + 2018-04-26T00:49:08.604Z +// - Date {} assert.deepStrictEqual(NaN, NaN); // OK, because of the SameValue comparison // Different unwrapped numbers: assert.deepStrictEqual(new Number(1), new Number(2)); -// AssertionError: Input A expected to strictly deep-equal input B: -// + expected - actual -// - [Number: 1] -// + [Number: 2] +// AssertionError: Expected inputs to be strictly deep-equal: +// + actual - expected +// +// + [Number: 1] +// - [Number: 2] assert.deepStrictEqual(new String('foo'), Object('foo')); // OK because the object and the string are identical when unwrapped. @@ -360,17 +364,20 @@ assert.deepStrictEqual(-0, -0); // Different zeros using the SameValue Comparison: assert.deepStrictEqual(0, -0); -// AssertionError: Input A expected to strictly deep-equal input B: -// + expected - actual -// - 0 -// + -0 +// AssertionError: Expected inputs to be strictly deep-equal: +// + actual - expected +// +// + 0 +// - -0 const symbol1 = Symbol(); const symbol2 = Symbol(); assert.deepStrictEqual({ [symbol1]: 1 }, { [symbol1]: 1 }); // OK, because it is the same symbol on both objects. + assert.deepStrictEqual({ [symbol1]: 1 }, { [symbol2]: 1 }); -// AssertionError [ERR_ASSERTION]: Input objects not identical: +// AssertionError [ERR_ASSERTION]: Inputs identical but not reference equal: +// // { // [Symbol()]: 1 // } @@ -385,12 +392,13 @@ assert.deepStrictEqual(weakMap1, weakMap2); // Fails because weakMap3 has a property that weakMap1 does not contain: assert.deepStrictEqual(weakMap1, weakMap3); -// AssertionError: Input A expected to strictly deep-equal input B: -// + expected - actual +// AssertionError: Expected inputs to be strictly deep-equal: +// + actual - expected +// // WeakMap { -// - [items unknown] -// + [items unknown], -// + unequal: true +// + [items unknown] +// - [items unknown], +// - unequal: true // } ``` @@ -875,7 +883,9 @@ assert.notStrictEqual(1, 2); // OK assert.notStrictEqual(1, 1); -// AssertionError [ERR_ASSERTION]: Identical input passed to notStrictEqual: 1 +// AssertionError [ERR_ASSERTION]: Expected "actual" to be strictly unequal to: +// +// 1 assert.notStrictEqual(1, '1'); // OK @@ -1031,19 +1041,20 @@ determined by the [SameValue Comparison][]. const assert = require('assert').strict; assert.strictEqual(1, 2); -// AssertionError [ERR_ASSERTION]: Input A expected to strictly equal input B: -// + expected - actual -// - 1 -// + 2 +// AssertionError [ERR_ASSERTION]: Expected inputs to be strictly equal: +// +// 1 !== 2 assert.strictEqual(1, 1); // OK -assert.strictEqual(1, '1'); -// AssertionError [ERR_ASSERTION]: Input A expected to strictly equal input B: -// + expected - actual -// - 1 -// + '1' +assert.strictEqual('Hello foobar', 'Hello World!'); +// AssertionError [ERR_ASSERTION]: Expected inputs to be strictly equal: +// + actual - expected +// +// + 'Hello foobar' +// - 'Hello World!' +// ^ ``` If the values are not strictly equal, an `AssertionError` is thrown with a @@ -1211,9 +1222,8 @@ function notThrowing() {} assert.throws(throwingFirst, 'Second'); // In the next example the message has no benefit over the message from the // error and since it is not clear if the user intended to actually match -// against the error message, Node.js thrown an `ERR_AMBIGUOUS_ARGUMENT` error. +// against the error message, Node.js throws an `ERR_AMBIGUOUS_ARGUMENT` error. assert.throws(throwingSecond, 'Second'); -// Throws an error: // TypeError [ERR_AMBIGUOUS_ARGUMENT] // The string is only used (as message) in case the function does not throw: @@ -1221,10 +1231,12 @@ assert.throws(notThrowing, 'Second'); // AssertionError [ERR_ASSERTION]: Missing expected exception: Second // If it was intended to match for the error message do this instead: +// It does not throw because the error messages match. assert.throws(throwingSecond, /Second$/); -// Does not throw because the error messages match. + +// If the error message does not match, the error from within the function is +// not caught. assert.throws(throwingFirst, /Second$/); -// Throws an error: // Error: First // at throwingFirst (repl:2:9) ``` diff --git a/lib/internal/assert.js b/lib/internal/assert.js index 74f7e3f7c05..894b36d17fa 100644 --- a/lib/internal/assert.js +++ b/lib/internal/assert.js @@ -10,13 +10,18 @@ let green = ''; let red = ''; let white = ''; -const READABLE_OPERATOR = { - deepStrictEqual: 'Input A expected to strictly deep-equal input B', - notDeepStrictEqual: 'Input A expected to strictly not deep-equal input B', - strictEqual: 'Input A expected to strictly equal input B', - notStrictEqual: 'Input A expected to strictly not equal input B' +const kReadableOperator = { + deepStrictEqual: 'Expected inputs to be strictly deep-equal:', + notDeepStrictEqual: 'Expected "actual" not to be strictly deep-equal to:', + strictEqual: 'Expected inputs to be strictly equal:', + notStrictEqual: 'Expected "actual" to be strictly unequal to:', + notIdentical: 'Inputs identical but not reference equal:', }; +// Comparing short primitives should just show === / !== instead of using the +// diff. +const kMaxShortLength = 10; + function copyError(source) { const keys = Object.keys(source); const target = Object.create(Object.getPrototypeOf(source)); @@ -49,22 +54,59 @@ function inspectValue(val) { } function createErrDiff(actual, expected, operator) { - var other = ''; - var res = ''; - var lastPos = 0; - var end = ''; - var skipped = false; + let other = ''; + let res = ''; + let lastPos = 0; + let end = ''; + let skipped = false; const actualLines = inspectValue(actual); const expectedLines = inspectValue(expected); - const msg = READABLE_OPERATOR[operator] + - `:\n${green}+ expected${white} ${red}- actual${white}`; + const msg = kReadableOperator[operator] + + `\n${green}+ actual${white} ${red}- expected${white}`; const skippedMsg = ` ${blue}...${white} Lines skipped`; + let i = 0; + let indicator = ''; + + // If "actual" and "expected" fit on a single line and they are not strictly + // equal, check further special handling. + if (actualLines.length === 1 && expectedLines.length === 1 && + actualLines[0] !== expectedLines[0]) { + const inputLength = actualLines[0].length + expectedLines[0].length; + // If the character length of "actual" and "expected" together is less than + // kMaxShortLength and if neither is an object and at least one of them is + // not `zero`, use the strict equal comparison to visualize the output. + if (inputLength <= kMaxShortLength) { + if ((typeof actual !== 'object' || actual === null) && + (typeof expected !== 'object' || expected === null) && + (actual !== 0 || expected !== 0)) { // -0 === +0 + return `${kReadableOperator[operator]}\n\n` + + `${actualLines[0]} !== ${expectedLines[0]}\n`; + } + } else { + // If the stderr is a tty and the input length is lower than the current + // columns per line, add a mismatch indicator below the output. If it is + // not a tty, use a default value of 80 characters. + const maxLength = process.stderr.isTTY ? process.stderr.columns : 80; + if (inputLength < maxLength) { + while (actualLines[0][i] === expectedLines[0][i]) { + i++; + } + // Ignore the first characters. + if (i > 2) { + // Add position indicator for the first mismatch in case it is a + // single line and the input length is less than the column length. + indicator = `\n ${' '.repeat(i)}^`; + i = 0; + } + } + } + } + // Remove all ending lines that match (this optimizes the output for // readability by reducing the number of total changed lines). - var a = actualLines[actualLines.length - 1]; - var b = expectedLines[expectedLines.length - 1]; - var i = 0; + let a = actualLines[actualLines.length - 1]; + let b = expectedLines[expectedLines.length - 1]; while (a === b) { if (i++ < 2) { end = `\n ${a}${end}`; @@ -78,6 +120,26 @@ function createErrDiff(actual, expected, operator) { a = actualLines[actualLines.length - 1]; b = expectedLines[expectedLines.length - 1]; } + + const maxLines = Math.max(actualLines.length, expectedLines.length); + // Strict equal with identical objects that are not identical by reference. + // E.g., assert.deepStrictEqual({ a: Symbol() }, { a: Symbol() }) + if (maxLines === 0) { + // We have to get the result again. The lines were all removed before. + const actualLines = inspectValue(actual); + + // Only remove lines in case it makes sense to collapse those. + // TODO: Accept env to always show the full error. + if (actualLines.length > 30) { + actualLines[26] = `${blue}...${white}`; + while (actualLines.length > 27) { + actualLines.pop(); + } + } + + return `${kReadableOperator.notIdentical}\n\n${actualLines.join('\n')}\n`; + } + if (i > 3) { end = `\n${blue}...${white}${end}`; skipped = true; @@ -87,9 +149,7 @@ function createErrDiff(actual, expected, operator) { other = ''; } - const maxLines = Math.max(actualLines.length, expectedLines.length); - var printedLines = 0; - var identical = 0; + let printedLines = 0; for (i = 0; i < maxLines; i++) { // Only extra expected lines exist const cur = i - lastPos; @@ -106,7 +166,7 @@ function createErrDiff(actual, expected, operator) { printedLines++; } lastPos = i; - other += `\n${green}+${white} ${expectedLines[i]}`; + other += `\n${red}-${white} ${expectedLines[i]}`; printedLines++; // Only extra actual lines exist } else if (expectedLines.length < i + 1) { @@ -122,7 +182,7 @@ function createErrDiff(actual, expected, operator) { printedLines++; } lastPos = i; - res += `\n${red}-${white} ${actualLines[i]}`; + res += `\n${green}+${white} ${actualLines[i]}`; printedLines++; // Lines diverge } else if (actualLines[i] !== expectedLines[i]) { @@ -138,8 +198,8 @@ function createErrDiff(actual, expected, operator) { printedLines++; } lastPos = i; - res += `\n${red}-${white} ${actualLines[i]}`; - other += `\n${green}+${white} ${expectedLines[i]}`; + res += `\n${green}+${white} ${actualLines[i]}`; + other += `\n${red}-${white} ${expectedLines[i]}`; printedLines += 2; // Lines are identical } else { @@ -149,7 +209,6 @@ function createErrDiff(actual, expected, operator) { res += `\n ${actualLines[i]}`; printedLines++; } - identical++; } // Inspected object to big (Show ~20 rows max) if (printedLines > 20 && i < maxLines - 2) { @@ -158,28 +217,7 @@ function createErrDiff(actual, expected, operator) { } } - // Strict equal with identical objects that are not identical by reference. - if (identical === maxLines) { - // E.g., assert.deepStrictEqual(Symbol(), Symbol()) - const base = operator === 'strictEqual' ? - 'Input objects identical but not reference equal:' : - 'Input objects not identical:'; - - // We have to get the result again. The lines were all removed before. - const actualLines = inspectValue(actual); - - // Only remove lines in case it makes sense to collapse those. - // TODO: Accept env to always show the full error. - if (actualLines.length > 30) { - actualLines[26] = `${blue}...${white}`; - while (actualLines.length > 27) { - actualLines.pop(); - } - } - - return `${base}\n\n${actualLines.join('\n')}\n`; - } - return `${msg}${skipped ? skippedMsg : ''}\n${res}${other}${end}`; + return `${msg}${skipped ? skippedMsg : ''}\n${res}${other}${end}${indicator}`; } class AssertionError extends Error { @@ -198,10 +236,10 @@ class AssertionError extends Error { if (message != null) { super(String(message)); } else { - if (process.stdout.isTTY) { + if (process.stderr.isTTY) { // Reset on each call to make sure we handle dynamically set environment // variables correct. - if (process.stdout.getColorDepth() !== 1) { + if (process.stderr.getColorDepth() !== 1) { blue = '\u001b[34m'; green = '\u001b[32m'; white = '\u001b[39m'; @@ -231,7 +269,7 @@ class AssertionError extends Error { // In case the objects are equal but the operator requires unequal, show // the first object and say A equals B const res = inspectValue(actual); - const base = `Identical input passed to ${operator}:`; + const base = kReadableOperator[operator]; // Only remove lines in case it makes sense to collapse those. // TODO: Accept env to always show the full error. diff --git a/test/message/assert_throws_stack.out b/test/message/assert_throws_stack.out index 3d5f4de4cf2..3013dbc0286 100644 --- a/test/message/assert_throws_stack.out +++ b/test/message/assert_throws_stack.out @@ -2,13 +2,13 @@ assert.js:* throw err; ^ -AssertionError [ERR_ASSERTION]: Input A expected to strictly deep-equal input B: -+ expected - actual +AssertionError [ERR_ASSERTION]: Expected inputs to be strictly deep-equal: ++ actual - expected -- Comparison {} -+ Comparison { -+ bar: true -+ } ++ Comparison {} +- Comparison { +- bar: true +- } at Object. (*assert_throws_stack.js:*:*) at * at * diff --git a/test/message/core_line_numbers.out b/test/message/core_line_numbers.out index b50e1678f49..fc647e41b92 100644 --- a/test/message/core_line_numbers.out +++ b/test/message/core_line_numbers.out @@ -3,7 +3,7 @@ punycode.js:42 ^ RangeError: Invalid input - at error (punycode.js:42:*) + at error (punycode.js:42:8) at Object.decode (punycode.js:*:*) at Object. (*test*message*core_line_numbers.js:*:*) at Module._compile (internal/modules/cjs/loader.js:*:*) diff --git a/test/message/error_exit.out b/test/message/error_exit.out index 1935c18979e..cc1edf46cb0 100644 --- a/test/message/error_exit.out +++ b/test/message/error_exit.out @@ -3,11 +3,10 @@ assert.js:* throw new AssertionError(obj); ^ -AssertionError [ERR_ASSERTION]: Input A expected to strictly equal input B: -+ expected - actual +AssertionError [ERR_ASSERTION]: Expected inputs to be strictly equal: + +1 !== 2 -- 1 -+ 2 at Object. (*test*message*error_exit.js:*:*) at Module._compile (internal/modules/cjs/loader.js:*:*) at Object.Module._extensions..js (internal/modules/cjs/loader.js:*:*) diff --git a/test/parallel/test-assert-checktag.js b/test/parallel/test-assert-checktag.js index 70a67e15d3f..754e5649145 100644 --- a/test/parallel/test-assert-checktag.js +++ b/test/parallel/test-assert-checktag.js @@ -26,15 +26,15 @@ if (process.stdout.isTTY) assert.throws( () => assert.deepStrictEqual(date, fake), { - message: 'Input A expected to strictly deep-equal input B:\n' + - '+ expected - actual\n\n- 2016-01-01T00:00:00.000Z\n+ Date {}' + message: 'Expected inputs to be strictly deep-equal:\n' + + '+ actual - expected\n\n+ 2016-01-01T00:00:00.000Z\n- Date {}' } ); assert.throws( () => assert.deepStrictEqual(fake, date), { - message: 'Input A expected to strictly deep-equal input B:\n' + - '+ expected - actual\n\n- Date {}\n+ 2016-01-01T00:00:00.000Z' + message: 'Expected inputs to be strictly deep-equal:\n' + + '+ actual - expected\n\n+ Date {}\n- 2016-01-01T00:00:00.000Z' } ); } diff --git a/test/parallel/test-assert-deep.js b/test/parallel/test-assert-deep.js index 538f4bef49d..4536b6d535f 100644 --- a/test/parallel/test-assert-deep.js +++ b/test/parallel/test-assert-deep.js @@ -4,8 +4,8 @@ const common = require('../common'); const assert = require('assert'); const util = require('util'); const { AssertionError } = assert; -const defaultMsgStart = 'Input A expected to strictly deep-equal input B:\n' + - '+ expected - actual'; +const defaultMsgStart = 'Expected inputs to be strictly deep-equal:\n'; +const defaultMsgStartFull = `${defaultMsgStart}+ actual - expected`; // Disable colored output to prevent color codes from breaking assertion // message comparisons. This should only be an issue when process.stdout @@ -44,9 +44,9 @@ assert.throws( () => assert.deepStrictEqual(arr, buf), { code: 'ERR_ASSERTION', - message: `${defaultMsgStart} ... Lines skipped\n\n` + - '- Uint8Array [\n' + - '+ Buffer [Uint8Array] [\n 120,\n...\n 10\n ]' + message: `${defaultMsgStartFull} ... Lines skipped\n\n` + + '+ Uint8Array [\n' + + '- Buffer [Uint8Array] [\n 120,\n...\n 10\n ]' } ); assert.deepEqual(arr, buf); @@ -59,9 +59,9 @@ assert.deepEqual(arr, buf); () => assert.deepStrictEqual(buf2, buf), { code: 'ERR_ASSERTION', - message: `${defaultMsgStart}\n\n` + + message: `${defaultMsgStartFull}\n\n` + ' Buffer [Uint8Array] [\n 120,\n 121,\n 122,\n' + - '- 10,\n- prop: 1\n+ 10\n ]' + '+ 10,\n+ prop: 1\n- 10\n ]' } ); assert.deepEqual(buf2, buf); @@ -74,9 +74,9 @@ assert.deepEqual(arr, buf); () => assert.deepStrictEqual(arr, arr2), { code: 'ERR_ASSERTION', - message: `${defaultMsgStart}\n\n` + + message: `${defaultMsgStartFull}\n\n` + ' Uint8Array [\n 120,\n 121,\n 122,\n' + - '- 10\n+ 10,\n+ prop: 5\n ]' + '+ 10\n- 10,\n- prop: 5\n ]' } ); assert.deepEqual(arr, arr2); @@ -101,18 +101,18 @@ assert.throws( () => assert.deepStrictEqual(date, date2), { code: 'ERR_ASSERTION', - message: `${defaultMsgStart}\n\n` + - '- 2016-01-01T00:00:00.000Z\n+ 2016-01-01T00:00:00.000Z {\n' + - "+ '0': '1'\n+ }" + message: `${defaultMsgStartFull}\n\n` + + '+ 2016-01-01T00:00:00.000Z\n- 2016-01-01T00:00:00.000Z {\n' + + "- '0': '1'\n- }" } ); assert.throws( () => assert.deepStrictEqual(date2, date), { code: 'ERR_ASSERTION', - message: `${defaultMsgStart}\n\n` + - '- 2016-01-01T00:00:00.000Z {\n' + - "- '0': '1'\n- }\n+ 2016-01-01T00:00:00.000Z" + message: `${defaultMsgStartFull}\n\n` + + '+ 2016-01-01T00:00:00.000Z {\n' + + "+ '0': '1'\n+ }\n- 2016-01-01T00:00:00.000Z" } ); @@ -133,8 +133,8 @@ assert.throws( () => assert.deepStrictEqual(re1, re2), { code: 'ERR_ASSERTION', - message: `${defaultMsgStart}\n\n` + - "- /test/\n+ /test/ {\n+ '0': '1'\n+ }" + message: `${defaultMsgStartFull}\n\n` + + "+ /test/\n- /test/ {\n- '0': '1'\n- }" } ); @@ -498,8 +498,8 @@ assertOnlyDeepEqual( () => assert.deepStrictEqual(map1, map2), { code: 'ERR_ASSERTION', - message: `${defaultMsgStart}\n\n` + - " Map {\n- 1 => 1\n+ 1 => '1'\n }" + message: `${defaultMsgStartFull}\n\n` + + " Map {\n+ 1 => 1\n- 1 => '1'\n }" } ); } @@ -750,7 +750,7 @@ assert.throws( () => assert.notDeepStrictEqual(new Date(2000, 3, 14), new Date(2000, 3, 14)), { name: 'AssertionError [ERR_ASSERTION]', - message: 'Identical input passed to notDeepStrictEqual: ' + + message: 'Expected "actual" not to be strictly deep-equal to: ' + util.inspect(new Date(2000, 3, 14)) } ); @@ -767,35 +767,35 @@ assert.throws( { code: 'ERR_ASSERTION', name: 'AssertionError [ERR_ASSERTION]', - message: `${defaultMsgStart}\n\n- /ab/\n+ /a/` + message: `${defaultMsgStartFull}\n\n+ /ab/\n- /a/` }); assert.throws( () => assert.deepStrictEqual(/a/g, /a/), { code: 'ERR_ASSERTION', name: 'AssertionError [ERR_ASSERTION]', - message: `${defaultMsgStart}\n\n- /a/g\n+ /a/` + message: `${defaultMsgStartFull}\n\n+ /a/g\n- /a/` }); assert.throws( () => assert.deepStrictEqual(/a/i, /a/), { code: 'ERR_ASSERTION', name: 'AssertionError [ERR_ASSERTION]', - message: `${defaultMsgStart}\n\n- /a/i\n+ /a/` + message: `${defaultMsgStartFull}\n\n+ /a/i\n- /a/` }); assert.throws( () => assert.deepStrictEqual(/a/m, /a/), { code: 'ERR_ASSERTION', name: 'AssertionError [ERR_ASSERTION]', - message: `${defaultMsgStart}\n\n- /a/m\n+ /a/` + message: `${defaultMsgStartFull}\n\n+ /a/m\n- /a/` }); assert.throws( () => assert.deepStrictEqual(/a/igm, /a/im), { code: 'ERR_ASSERTION', name: 'AssertionError [ERR_ASSERTION]', - message: `${defaultMsgStart}\n\n- /a/gim\n+ /a/im` + message: `${defaultMsgStartFull}\n\n+ /a/gim\n- /a/im\n ^` }); { @@ -806,12 +806,12 @@ assert.throws( assert.throws( () => assert.deepStrictEqual(4, '4'), - { message: `${defaultMsgStart}\n\n- 4\n+ '4'` } + { message: `${defaultMsgStart}\n4 !== '4'\n` } ); assert.throws( () => assert.deepStrictEqual(true, 1), - { message: `${defaultMsgStart}\n\n- true\n+ 1` } + { message: `${defaultMsgStart}\ntrue !== 1\n` } ); // Having the same number of owned properties && the same set of keys. @@ -821,21 +821,23 @@ assert.throws(() => assert.deepStrictEqual([4], ['4']), { code: 'ERR_ASSERTION', name: 'AssertionError [ERR_ASSERTION]', - message: `${defaultMsgStart}\n\n [\n- 4\n+ '4'\n ]` + message: `${defaultMsgStartFull}\n\n [\n+ 4\n- '4'\n ]` }); assert.throws( () => assert.deepStrictEqual({ a: 4 }, { a: 4, b: true }), { code: 'ERR_ASSERTION', name: 'AssertionError [ERR_ASSERTION]', - message: `${defaultMsgStart}\n\n {\n- a: 4\n+ a: 4,\n+ b: true\n }` + message: `${defaultMsgStartFull}\n\n ` + + '{\n+ a: 4\n- a: 4,\n- b: true\n }' }); assert.throws( () => assert.deepStrictEqual(['a'], { 0: 'a' }), { code: 'ERR_ASSERTION', name: 'AssertionError [ERR_ASSERTION]', - message: `${defaultMsgStart}\n\n- [\n- 'a'\n- ]\n+ {\n+ '0': 'a'\n+ }` + message: `${defaultMsgStartFull}\n\n` + + "+ [\n+ 'a'\n+ ]\n- {\n- '0': 'a'\n- }" }); /* eslint-enable */ @@ -906,8 +908,8 @@ assert.throws(() => assert.deepStrictEqual(new Boolean(true), {}), assert.throws( () => assert.deepStrictEqual(a, b), { - message: `${defaultMsgStart}\n\n` + - ' [TypeError: foo] {\n- foo: \'bar\'\n+ foo: \'baz\'\n }' + message: `${defaultMsgStartFull}\n\n` + + ' [TypeError: foo] {\n+ foo: \'bar\'\n- foo: \'baz\'\n }' } ); } @@ -922,8 +924,8 @@ assert.throws(() => assert.deepStrictEqual(new Boolean(true), {}), util.inspect.defaultOptions = { showProxy: true }; assert.throws( () => assert.deepStrictEqual(arrProxy, [1, 2, 3]), - { message: `${defaultMsgStart}\n\n` + - ' [\n 1,\n- 2\n+ 2,\n+ 3\n ]' } + { message: `${defaultMsgStartFull}\n\n` + + ' [\n 1,\n+ 2\n- 2,\n- 3\n ]' } ); util.inspect.defaultOptions = tmp; } diff --git a/test/parallel/test-assert.js b/test/parallel/test-assert.js index bc96dc57bcd..6aecfc0fe6b 100644 --- a/test/parallel/test-assert.js +++ b/test/parallel/test-assert.js @@ -34,8 +34,9 @@ const a = assert; if (process.stdout.isTTY) process.env.NODE_DISABLE_COLORS = '1'; -const start = 'Input A expected to strictly deep-equal input B:'; -const actExp = '+ expected - actual'; +const strictEqualMessageStart = 'Expected inputs to be strictly equal:\n'; +const start = 'Expected inputs to be strictly deep-equal:'; +const actExp = '+ actual - expected'; assert.ok(a.AssertionError.prototype instanceof Error, 'a.AssertionError instanceof Error'); @@ -70,7 +71,7 @@ assert.throws(() => a.strictEqual(null, undefined), assert.throws( () => a.notStrictEqual(2, 2), { - message: 'Identical input passed to notStrictEqual: 2', + message: 'Expected "actual" to be strictly unequal to: 2', name: 'AssertionError [ERR_ASSERTION]' } ); @@ -78,7 +79,8 @@ assert.throws( assert.throws( () => a.notStrictEqual('a '.repeat(30), 'a '.repeat(30)), { - message: `Identical input passed to notStrictEqual: '${'a '.repeat(30)}'`, + message: 'Expected "actual" to be strictly unequal to: ' + + `'${'a '.repeat(30)}'`, name: 'AssertionError [ERR_ASSERTION]' } ); @@ -254,42 +256,48 @@ a.throws(() => thrower(TypeError), (err) => { const circular = { y: 1 }; circular.x = circular; -function testAssertionMessage(actual, expected) { +function testAssertionMessage(actual, expected, msg) { try { assert.strictEqual(actual, ''); } catch (e) { assert.strictEqual( e.message, - 'Input A expected to strictly equal input B:\n+ expected - actual\n\n' + - `- ${expected}\n+ ''` + msg || strictEqualMessageStart + + `+ actual - expected\n\n+ ${expected}\n- ''` ); assert.ok(e.generatedMessage, 'Message not marked as generated'); } } -testAssertionMessage(undefined, 'undefined'); -testAssertionMessage(null, 'null'); -testAssertionMessage(true, 'true'); -testAssertionMessage(false, 'false'); -testAssertionMessage(0, '0'); -testAssertionMessage(100, '100'); -testAssertionMessage(NaN, 'NaN'); -testAssertionMessage(Infinity, 'Infinity'); -testAssertionMessage(-Infinity, '-Infinity'); -testAssertionMessage('', '""'); -testAssertionMessage('foo', '\'foo\''); +function testShortAssertionMessage(actual, expected) { + testAssertionMessage(actual, expected, strictEqualMessageStart + + `\n${inspect(actual)} !== ''\n`); +} + +testShortAssertionMessage(null, 'null'); +testShortAssertionMessage(true, 'true'); +testShortAssertionMessage(false, 'false'); +testShortAssertionMessage(100, '100'); +testShortAssertionMessage(NaN, 'NaN'); +testShortAssertionMessage(Infinity, 'Infinity'); +testShortAssertionMessage('', '""'); +testShortAssertionMessage('foo', '\'foo\''); +testShortAssertionMessage(0, '0'); +testShortAssertionMessage(Symbol(), 'Symbol()'); testAssertionMessage([], '[]'); -testAssertionMessage([1, 2, 3], '[\n- 1,\n- 2,\n- 3\n- ]'); testAssertionMessage(/a/, '/a/'); testAssertionMessage(/abc/gim, '/abc/gim'); +testAssertionMessage({}, '{}'); +testAssertionMessage(undefined, 'undefined'); +testAssertionMessage(-Infinity, '-Infinity'); +testAssertionMessage([1, 2, 3], '[\n+ 1,\n+ 2,\n+ 3\n+ ]'); testAssertionMessage(function f() {}, '[Function: f]'); testAssertionMessage(function() {}, '[Function]'); -testAssertionMessage({}, '{}'); -testAssertionMessage(circular, '{\n- y: 1,\n- x: [Circular]\n- }'); +testAssertionMessage(circular, '{\n+ y: 1,\n+ x: [Circular]\n+ }'); testAssertionMessage({ a: undefined, b: null }, - '{\n- a: undefined,\n- b: null\n- }'); + '{\n+ a: undefined,\n+ b: null\n+ }'); testAssertionMessage({ a: NaN, b: Infinity, c: -Infinity }, - '{\n- a: NaN,\n- b: Infinity,\n- c: -Infinity\n- }'); + '{\n+ a: NaN,\n+ b: Infinity,\n+ c: -Infinity\n+ }'); // https://github.com/nodejs/node-v0.x-archive/issues/5292 try { @@ -297,8 +305,7 @@ try { } catch (e) { assert.strictEqual( e.message, - 'Input A expected to strictly equal input B:\n' + - '+ expected - actual\n\n- 1\n+ 2' + `${strictEqualMessageStart}\n1 !== 2\n` ); assert.ok(e.generatedMessage, 'Message not marked as generated'); } @@ -384,8 +391,8 @@ assert.throws(() => { assert.strictEqual('A'.repeat(1000), ''); }, { code: 'ERR_ASSERTION', - message: 'Input A expected to strictly equal input B:\n' + - `+ expected - actual\n\n- '${'A'.repeat(1000)}'\n+ ''` + message: `${strictEqualMessageStart}+ actual - expected\n\n` + + `+ '${'A'.repeat(1000)}'\n- ''` }); { @@ -408,8 +415,9 @@ assert.throws( { code: 'ERR_ASSERTION', name: 'AssertionError [ERR_ASSERTION]', - message: 'Input A expected to strictly equal input B:\n' + - '+ expected - actual\n\n- [Error: foo]\n+ [Error: foobar]' + message: strictEqualMessageStart + + '+ actual - expected\n\n' + + '+ [Error: foo]\n- [Error: foobar]\n ^' } ); @@ -433,7 +441,8 @@ assert.throws( () => assert(...[]), { message: 'No value argument passed to `assert.ok()`', - name: 'AssertionError [ERR_ASSERTION]' + name: 'AssertionError [ERR_ASSERTION]', + generatedMessage: true } ); assert.throws( @@ -471,8 +480,8 @@ assert.throws( ' [', '...', ' 2,', - '- 3', - "+ '3'", + '+ 3', + "- '3'", ' ]', '...', ' 5', @@ -489,7 +498,7 @@ assert.throws( ' 1,', '...', ' 0,', - '+ 1,', + '- 1,', ' 1,', '...', ' 1', @@ -509,7 +518,7 @@ assert.throws( ' 1,', '...', ' 0,', - '- 1,', + '+ 1,', ' 1,', '...', ' 1', @@ -527,12 +536,12 @@ assert.throws( '', ' [', ' 1,', - '- 2,', - '+ 1,', + '+ 2,', + '- 1,', ' 1,', ' 1,', ' 0,', - '- 1,', + '+ 1,', ' 1', ' ]' ].join('\n'); @@ -546,12 +555,12 @@ assert.throws( start, actExp, '', - '- [', - '- 1,', - '- 2,', - '- 1', - '- ]', - '+ undefined', + '+ [', + '+ 1,', + '+ 2,', + '+ 1', + '+ ]', + '- undefined', ].join('\n'); assert.throws( () => assert.deepEqual([1, 2, 1]), @@ -562,7 +571,7 @@ assert.throws( actExp, '', ' [', - '- 1,', + '+ 1,', ' 2,', ' 1', ' ]' @@ -575,9 +584,9 @@ assert.throws( `${actExp} ... Lines skipped\n` + '\n' + ' [\n' + - '- 1,\n'.repeat(10) + + '+ 1,\n'.repeat(10) + '...\n' + - '+ 2,\n'.repeat(10) + + '- 2,\n'.repeat(10) + '...'; assert.throws( () => assert.deepEqual(Array(12).fill(1), Array(12).fill(2)), @@ -591,21 +600,24 @@ assert.throws( message: `${start}\n` + `${actExp}\n` + '\n' + - '- {}\n' + - '+ {\n' + - "+ loop: 'forever',\n" + - '+ [Symbol(util.inspect.custom)]: [Function]\n' + - '+ }' + '+ {}\n' + + '- {\n' + + "- loop: 'forever',\n" + + '- [Symbol(util.inspect.custom)]: [Function]\n' + + '- }' }); // notDeepEqual tests - message = 'Identical input passed to notDeepStrictEqual:\n\n[\n 1\n]\n'; assert.throws( () => assert.notDeepEqual([1], [1]), - { message }); + { + message: 'Expected "actual" not to be strictly deep-equal to:\n\n' + + '[\n 1\n]\n' + } + ); - message = 'Identical input passed to notDeepStrictEqual:' + - `\n\n[${'\n 1,'.repeat(25)}\n...\n`; + message = 'Expected "actual" not to be strictly deep-equal to:' + + `\n\n[${'\n 1,'.repeat(25)}\n...\n`; const data = Array(31).fill(1); assert.throws( () => assert.notDeepEqual(data, data), @@ -874,8 +886,8 @@ common.expectsError( name: 'AssertionError [ERR_ASSERTION]', message: `${start}\n${actExp}\n\n` + " Comparison {\n name: 'TypeError',\n" + - " message: 'Wrong value',\n- code: 404\n" + - '+ code: 404,\n+ foo: undefined\n }' + " message: 'Wrong value',\n+ code: 404\n" + + '- code: 404,\n- foo: undefined\n }' } ); @@ -888,8 +900,8 @@ common.expectsError( name: 'AssertionError [ERR_ASSERTION]', message: `${start}\n${actExp}\n\n` + " Comparison {\n name: 'TypeError',\n" + - " message: 'Wrong value',\n- code: 404\n" + - "+ code: '404',\n+ foo: undefined\n }" + " message: 'Wrong value',\n+ code: 404\n" + + "- code: '404',\n- foo: undefined\n }" } ); @@ -919,7 +931,7 @@ common.expectsError( name: 'AssertionError [ERR_ASSERTION]', code: 'ERR_ASSERTION', message: `${start}\n${actExp}\n\n` + - " Comparison {\n- name: 'TypeError',\n+ name: 'Error'," + + " Comparison {\n+ name: 'TypeError',\n- name: 'Error'," + "\n message: 'e'\n }" } ); @@ -930,8 +942,8 @@ common.expectsError( code: 'ERR_ASSERTION', generatedMessage: true, message: `${start}\n${actExp}\n\n` + - " Comparison {\n name: 'Error',\n- message: 'foo'" + - "\n+ message: ''\n }" + " Comparison {\n name: 'Error',\n+ message: 'foo'" + + "\n- message: ''\n }" } ); @@ -988,7 +1000,7 @@ assert.throws(() => { throw null; }, 'foo'); assert.throws( () => assert.strictEqual([], []), { - message: 'Input objects identical but not reference equal:\n\n[]\n' + message: 'Inputs identical but not reference equal:\n\n[]\n' } ); @@ -997,8 +1009,8 @@ assert.throws( assert.throws( () => assert.strictEqual(args, { 0: 'a' }), { - message: 'Input A expected to strictly equal input B:\n+ expected' + - " - actual\n\n- [Arguments] {\n+ {\n '0': 'a'\n }" + message: `${strictEqualMessageStart}+ actual - expected\n\n` + + "+ [Arguments] {\n- {\n '0': 'a'\n }" } ); } @@ -1022,8 +1034,8 @@ assert.throws( { message: `${start}\n${actExp}\n\n` + ' Comparison {\n' + - "- message: 'foobar',\n" + - '+ message: /fooa/,\n' + + "+ message: 'foobar',\n" + + '- message: /fooa/,\n' + " name: 'TypeError'\n" + ' }' } @@ -1043,10 +1055,10 @@ assert.throws( expected, generatedMessage: true, message: `${start}\n${actExp}\n\n` + - '- null\n' + - '+ {\n' + - "+ message: 'foo'\n" + - '+ }' + '+ null\n' + + '- {\n' + + "- message: 'foo'\n" + + '- }' } ); diff --git a/test/parallel/test-internal-errors.js b/test/parallel/test-internal-errors.js index b5e08911b82..6e648aeae72 100644 --- a/test/parallel/test-internal-errors.js +++ b/test/parallel/test-internal-errors.js @@ -77,7 +77,7 @@ common.expectsError(() => { }, { code: 'TEST_ERROR_1', type: RangeError }); }, { code: 'ERR_ASSERTION', - message: /- type: \[Function: TypeError]\n\+ type: \[Function: RangeError]/ + message: /\+ type: \[Function: TypeError]\n- type: \[Function: RangeError]/ }); common.expectsError(() => { @@ -89,7 +89,7 @@ common.expectsError(() => { }, { code: 'ERR_ASSERTION', type: assert.AssertionError, - message: /- message: 'Error for testing purposes: a'\n\+ message: \/\^Error/ + message: /\+ message: 'Error for testing purposes: a'\n- message: \/\^Error/ }); // Test ERR_INVALID_FD_TYPE diff --git a/test/pseudo-tty/test-assert-colors.js b/test/pseudo-tty/test-assert-colors.js index 75d3af55796..cd855dc06ea 100644 --- a/test/pseudo-tty/test-assert-colors.js +++ b/test/pseudo-tty/test-assert-colors.js @@ -7,12 +7,12 @@ try { process.env.COLORTERM = '1'; assert.deepStrictEqual([1, 2, 2, 2], [2, 2, 2, 2]); } catch (err) { - const expected = 'Input A expected to strictly deep-equal input B:\n' + - '\u001b[32m+ expected\u001b[39m \u001b[31m- actual\u001b[39m' + + const expected = 'Expected inputs to be strictly deep-equal:\n' + + '\u001b[32m+ actual\u001b[39m \u001b[31m- expected\u001b[39m' + ' \u001b[34m...\u001b[39m Lines skipped\n\n' + ' [\n' + - '\u001b[31m-\u001b[39m 1,\n' + - '\u001b[32m+\u001b[39m 2,\n' + + '\u001b[32m+\u001b[39m 1,\n' + + '\u001b[31m-\u001b[39m 2,\n' + ' 2,\n' + '\u001b[34m...\u001b[39m\n' + ' 2\n' +