From 7589f421ca6a382d0a09baa2504badc2fb40493d Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Tue, 3 Jul 2018 02:06:57 +0200 Subject: [PATCH 1/6] assert: multiple improvements 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. --- lib/internal/assert.js | 84 ++++++++++----- 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 | 146 ++++++++++++++------------ test/parallel/test-internal-errors.js | 4 +- test/pseudo-tty/test-assert-colors.js | 8 +- 9 files changed, 187 insertions(+), 154 deletions(-) diff --git a/lib/internal/assert.js b/lib/internal/assert.js index 74f7e3f7c053c4..57fd5f6e20081e 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 input to be strictly deep-equal', + notDeepStrictEqual: 'Expected "actual" not to be strictly deep-equal', + strictEqual: 'Expected input to be strictly equal', + notStrictEqual: 'Expected "actual" to be strictly unequal', + notIdentical: 'Input 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,46 @@ 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 (actualLines.length === 1 && expectedLines.length === 1) { + const inputLength = actualLines[0].length + expectedLines[0].length; + 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 (process.stdout.isTTY && + inputLength < process.stdout.columns && + actualLines[0] !== expectedLines[0]) { + while (actualLines[0][i] === expectedLines[0][i]) { + i++; + } + // 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}`; @@ -88,8 +117,8 @@ function createErrDiff(actual, expected, operator) { } const maxLines = Math.max(actualLines.length, expectedLines.length); - var printedLines = 0; - var identical = 0; + let printedLines = 0; + let identical = 0; for (i = 0; i < maxLines; i++) { // Only extra expected lines exist const cur = i - lastPos; @@ -106,7 +135,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 +151,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 +167,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 { @@ -159,12 +188,8 @@ function createErrDiff(actual, expected, operator) { } // Strict equal with identical objects that are not identical by reference. + // E.g., assert.deepStrictEqual({ a: Symbol() }, { a: Symbol() }) 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); @@ -177,9 +202,10 @@ function createErrDiff(actual, expected, operator) { } } - return `${base}\n\n${actualLines.join('\n')}\n`; + return `${kReadableOperator.notIdentical}\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 { @@ -231,7 +257,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 3d5f4de4cf26a6..66e5f239afa125 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 input 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 b50e1678f49fb7..fc647e41b92d6b 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 1935c18979e45c..64965603e2d4f6 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 input 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 70a67e15d3f5f8..0eacf3363a1b01 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 input 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 input 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 538f4bef49d8c6..1bb96c91a5b2ac 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 input 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 ' + 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` }); { @@ -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 bc96dc57bcd5c0..44edb7ab6ed260 100644 --- a/test/parallel/test-assert.js +++ b/test/parallel/test-assert.js @@ -34,8 +34,8 @@ 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 start = 'Expected input to be strictly deep-equal:'; +const actExp = '+ actual - expected'; assert.ok(a.AssertionError.prototype instanceof Error, 'a.AssertionError instanceof Error'); @@ -70,7 +70,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 2', name: 'AssertionError [ERR_ASSERTION]' } ); @@ -78,7 +78,7 @@ 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 '${'a '.repeat(30)}'`, name: 'AssertionError [ERR_ASSERTION]' } ); @@ -254,42 +254,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 || 'Expected input to be strictly equal:\n' + + `+ 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, 'Expected input to be strictly equal' + + `:\n\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 +303,7 @@ try { } catch (e) { assert.strictEqual( e.message, - 'Input A expected to strictly equal input B:\n' + - '+ expected - actual\n\n- 1\n+ 2' + 'Expected input to be strictly equal:\n\n1 !== 2\n' ); assert.ok(e.generatedMessage, 'Message not marked as generated'); } @@ -384,8 +389,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: 'Expected input to be strictly equal:\n+ actual - expected\n\n' + + `+ '${'A'.repeat(1000)}'\n- ''` }); { @@ -408,8 +413,8 @@ 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: 'Expected input to be strictly equal:\n' + + '+ actual - expected\n\n+ [Error: foo]\n- [Error: foobar]' } ); @@ -433,7 +438,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 +477,8 @@ assert.throws( ' [', '...', ' 2,', - '- 3', - "+ '3'", + '+ 3', + "- '3'", ' ]', '...', ' 5', @@ -489,7 +495,7 @@ assert.throws( ' 1,', '...', ' 0,', - '+ 1,', + '- 1,', ' 1,', '...', ' 1', @@ -509,7 +515,7 @@ assert.throws( ' 1,', '...', ' 0,', - '- 1,', + '+ 1,', ' 1,', '...', ' 1', @@ -527,12 +533,12 @@ assert.throws( '', ' [', ' 1,', - '- 2,', - '+ 1,', + '+ 2,', + '- 1,', ' 1,', ' 1,', ' 0,', - '- 1,', + '+ 1,', ' 1', ' ]' ].join('\n'); @@ -546,12 +552,12 @@ assert.throws( start, actExp, '', - '- [', - '- 1,', - '- 2,', - '- 1', - '- ]', - '+ undefined', + '+ [', + '+ 1,', + '+ 2,', + '+ 1', + '+ ]', + '- undefined', ].join('\n'); assert.throws( () => assert.deepEqual([1, 2, 1]), @@ -562,7 +568,7 @@ assert.throws( actExp, '', ' [', - '- 1,', + '+ 1,', ' 2,', ' 1', ' ]' @@ -575,9 +581,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 +597,21 @@ 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'; + message = 'Expected "actual" not to be strictly deep-equal\n\n[\n 1\n]\n'; assert.throws( () => assert.notDeepEqual([1], [1]), { message }); - message = 'Identical input passed to notDeepStrictEqual:' + - `\n\n[${'\n 1,'.repeat(25)}\n...\n`; + message = 'Expected "actual" not to be strictly deep-equal' + + `\n\n[${'\n 1,'.repeat(25)}\n...\n`; const data = Array(31).fill(1); assert.throws( () => assert.notDeepEqual(data, data), @@ -874,8 +880,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 +894,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 +925,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 +936,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 +994,7 @@ assert.throws(() => { throw null; }, 'foo'); assert.throws( () => assert.strictEqual([], []), { - message: 'Input objects identical but not reference equal:\n\n[]\n' + message: 'Input identical but not reference equal:\n\n[]\n' } ); @@ -997,8 +1003,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: 'Expected input to be strictly equal:\n+ actual' + + " - expected\n\n+ [Arguments] {\n- {\n '0': 'a'\n }" } ); } @@ -1022,8 +1028,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 +1049,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 b5e08911b8219e..6e648aeae721f0 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 75d3af55796e1b..9e9d10b651a98d 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 input 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' + From 671a3cc2c130d941a9353e359ff6976c47f867be Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Sat, 14 Jul 2018 17:35:12 +0200 Subject: [PATCH 2/6] fixup: address comment --- lib/internal/assert.js | 6 +++--- test/message/assert_throws_stack.out | 2 +- test/message/error_exit.out | 2 +- test/parallel/test-assert-checktag.js | 4 ++-- test/parallel/test-assert-deep.js | 2 +- test/parallel/test-assert.js | 21 +++++++++++---------- test/pseudo-tty/test-assert-colors.js | 2 +- 7 files changed, 20 insertions(+), 19 deletions(-) diff --git a/lib/internal/assert.js b/lib/internal/assert.js index 57fd5f6e20081e..2f7fc737b6fb9f 100644 --- a/lib/internal/assert.js +++ b/lib/internal/assert.js @@ -11,11 +11,11 @@ let red = ''; let white = ''; const kReadableOperator = { - deepStrictEqual: 'Expected input to be strictly deep-equal', + deepStrictEqual: 'Expected inputs to be strictly deep-equal', notDeepStrictEqual: 'Expected "actual" not to be strictly deep-equal', - strictEqual: 'Expected input to be strictly equal', + strictEqual: 'Expected inputs to be strictly equal', notStrictEqual: 'Expected "actual" to be strictly unequal', - notIdentical: 'Input identical but not reference equal:', + notIdentical: 'Inputs identical but not reference equal:', }; // Comparing short primitives should just show === / !== instead of using the diff --git a/test/message/assert_throws_stack.out b/test/message/assert_throws_stack.out index 66e5f239afa125..3013dbc0286bb2 100644 --- a/test/message/assert_throws_stack.out +++ b/test/message/assert_throws_stack.out @@ -2,7 +2,7 @@ assert.js:* throw err; ^ -AssertionError [ERR_ASSERTION]: Expected input to be strictly deep-equal: +AssertionError [ERR_ASSERTION]: Expected inputs to be strictly deep-equal: + actual - expected + Comparison {} diff --git a/test/message/error_exit.out b/test/message/error_exit.out index 64965603e2d4f6..cc1edf46cb0001 100644 --- a/test/message/error_exit.out +++ b/test/message/error_exit.out @@ -3,7 +3,7 @@ assert.js:* throw new AssertionError(obj); ^ -AssertionError [ERR_ASSERTION]: Expected input to be strictly equal: +AssertionError [ERR_ASSERTION]: Expected inputs to be strictly equal: 1 !== 2 diff --git a/test/parallel/test-assert-checktag.js b/test/parallel/test-assert-checktag.js index 0eacf3363a1b01..754e5649145f17 100644 --- a/test/parallel/test-assert-checktag.js +++ b/test/parallel/test-assert-checktag.js @@ -26,14 +26,14 @@ if (process.stdout.isTTY) assert.throws( () => assert.deepStrictEqual(date, fake), { - message: 'Expected input to be strictly deep-equal:\n' + + 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: 'Expected input to be strictly deep-equal:\n' + + 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 1bb96c91a5b2ac..0e09a32817b269 100644 --- a/test/parallel/test-assert-deep.js +++ b/test/parallel/test-assert-deep.js @@ -4,7 +4,7 @@ const common = require('../common'); const assert = require('assert'); const util = require('util'); const { AssertionError } = assert; -const defaultMsgStart = 'Expected input to be strictly deep-equal:\n'; +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 diff --git a/test/parallel/test-assert.js b/test/parallel/test-assert.js index 44edb7ab6ed260..746b16642994f3 100644 --- a/test/parallel/test-assert.js +++ b/test/parallel/test-assert.js @@ -34,7 +34,8 @@ const a = assert; if (process.stdout.isTTY) process.env.NODE_DISABLE_COLORS = '1'; -const start = 'Expected input to be strictly deep-equal:'; +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, @@ -260,7 +261,7 @@ function testAssertionMessage(actual, expected, msg) { } catch (e) { assert.strictEqual( e.message, - msg || 'Expected input to be strictly equal:\n' + + msg || strictEqualMessageStart + `+ actual - expected\n\n+ ${expected}\n- ''` ); assert.ok(e.generatedMessage, 'Message not marked as generated'); @@ -268,8 +269,8 @@ function testAssertionMessage(actual, expected, msg) { } function testShortAssertionMessage(actual, expected) { - testAssertionMessage(actual, expected, 'Expected input to be strictly equal' + - `:\n\n${inspect(actual)} !== ''\n`); + testAssertionMessage(actual, expected, strictEqualMessageStart + + `\n${inspect(actual)} !== ''\n`); } testShortAssertionMessage(null, 'null'); @@ -303,7 +304,7 @@ try { } catch (e) { assert.strictEqual( e.message, - 'Expected input to be strictly equal:\n\n1 !== 2\n' + `${strictEqualMessageStart}\n1 !== 2\n` ); assert.ok(e.generatedMessage, 'Message not marked as generated'); } @@ -389,7 +390,7 @@ assert.throws(() => { assert.strictEqual('A'.repeat(1000), ''); }, { code: 'ERR_ASSERTION', - message: 'Expected input to be strictly equal:\n+ actual - expected\n\n' + + message: `${strictEqualMessageStart}+ actual - expected\n\n` + `+ '${'A'.repeat(1000)}'\n- ''` }); @@ -413,7 +414,7 @@ assert.throws( { code: 'ERR_ASSERTION', name: 'AssertionError [ERR_ASSERTION]', - message: 'Expected input to be strictly equal:\n' + + message: strictEqualMessageStart + '+ actual - expected\n\n+ [Error: foo]\n- [Error: foobar]' } ); @@ -994,7 +995,7 @@ assert.throws(() => { throw null; }, 'foo'); assert.throws( () => assert.strictEqual([], []), { - message: 'Input identical but not reference equal:\n\n[]\n' + message: 'Inputs identical but not reference equal:\n\n[]\n' } ); @@ -1003,8 +1004,8 @@ assert.throws( assert.throws( () => assert.strictEqual(args, { 0: 'a' }), { - message: 'Expected input to be strictly equal:\n+ actual' + - " - expected\n\n+ [Arguments] {\n- {\n '0': 'a'\n }" + message: `${strictEqualMessageStart}+ actual - expected\n\n` + + "+ [Arguments] {\n- {\n '0': 'a'\n }" } ); } diff --git a/test/pseudo-tty/test-assert-colors.js b/test/pseudo-tty/test-assert-colors.js index 9e9d10b651a98d..cd855dc06eac27 100644 --- a/test/pseudo-tty/test-assert-colors.js +++ b/test/pseudo-tty/test-assert-colors.js @@ -7,7 +7,7 @@ try { process.env.COLORTERM = '1'; assert.deepStrictEqual([1, 2, 2, 2], [2, 2, 2, 2]); } catch (err) { - const expected = 'Expected input to be strictly deep-equal:\n' + + 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' + From 511f8a1ebdce9b8c749c81c1625adb2d27501bc3 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Mon, 16 Jul 2018 17:40:48 +0200 Subject: [PATCH 3/6] fixup: address comment --- lib/internal/assert.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/internal/assert.js b/lib/internal/assert.js index 2f7fc737b6fb9f..a032ca2f089902 100644 --- a/lib/internal/assert.js +++ b/lib/internal/assert.js @@ -68,8 +68,14 @@ function createErrDiff(actual, expected, operator) { let i = 0; let indicator = ''; - if (actualLines.length === 1 && expectedLines.length === 1) { + // 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) && @@ -77,9 +83,10 @@ function createErrDiff(actual, expected, operator) { return `${kReadableOperator[operator]}:\n\n` + `${actualLines[0]} !== ${expectedLines[0]}\n`; } + // If the stdout is a tty and the input length is lower than the current + // columns per line, add a mismatch indicator below the output. } else if (process.stdout.isTTY && - inputLength < process.stdout.columns && - actualLines[0] !== expectedLines[0]) { + inputLength < process.stdout.columns) { while (actualLines[0][i] === expectedLines[0][i]) { i++; } From e789901dac70075c8c9a8d8ad136a516e3f76478 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Fri, 27 Jul 2018 13:50:16 +0200 Subject: [PATCH 4/6] fixup --- lib/internal/assert.js | 78 ++++++++++++++++--------------- test/parallel/test-assert-deep.js | 4 +- test/parallel/test-assert.js | 17 ++++--- 3 files changed, 54 insertions(+), 45 deletions(-) diff --git a/lib/internal/assert.js b/lib/internal/assert.js index a032ca2f089902..1d36ec9f2849b9 100644 --- a/lib/internal/assert.js +++ b/lib/internal/assert.js @@ -11,10 +11,10 @@ let red = ''; let white = ''; const kReadableOperator = { - deepStrictEqual: 'Expected inputs to be strictly deep-equal', - notDeepStrictEqual: 'Expected "actual" not to be strictly deep-equal', - strictEqual: 'Expected inputs to be strictly equal', - notStrictEqual: 'Expected "actual" to be strictly unequal', + 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:', }; @@ -62,7 +62,7 @@ function createErrDiff(actual, expected, operator) { const actualLines = inspectValue(actual); const expectedLines = inspectValue(expected); const msg = kReadableOperator[operator] + - `:\n${green}+ actual${white} ${red}- expected${white}`; + `\n${green}+ actual${white} ${red}- expected${white}`; const skippedMsg = ` ${blue}...${white} Lines skipped`; let i = 0; @@ -80,20 +80,25 @@ function createErrDiff(actual, expected, operator) { if ((typeof actual !== 'object' || actual === null) && (typeof expected !== 'object' || expected === null) && (actual !== 0 || expected !== 0)) { // -0 === +0 - return `${kReadableOperator[operator]}:\n\n` + + return `${kReadableOperator[operator]}\n\n` + `${actualLines[0]} !== ${expectedLines[0]}\n`; } - // If the stdout is a tty and the input length is lower than the current - // columns per line, add a mismatch indicator below the output. - } else if (process.stdout.isTTY && - inputLength < process.stdout.columns) { - while (actualLines[0][i] === expectedLines[0][i]) { - i++; + } else { + // If the stdout 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.stdout.isTTY ? process.stdout.columns : 80; + if (inputLength < maxLength) { + while (actualLines[0][i] === expectedLines[0][i]) { + i++; + } + if (i !== 0) { + // 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; + } } - // 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; } } @@ -114,6 +119,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; @@ -123,9 +148,7 @@ function createErrDiff(actual, expected, operator) { other = ''; } - const maxLines = Math.max(actualLines.length, expectedLines.length); let printedLines = 0; - let identical = 0; for (i = 0; i < maxLines; i++) { // Only extra expected lines exist const cur = i - lastPos; @@ -185,7 +208,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) { @@ -194,24 +216,6 @@ function createErrDiff(actual, expected, operator) { } } - // Strict equal with identical objects that are not identical by reference. - // E.g., assert.deepStrictEqual({ a: Symbol() }, { a: Symbol() }) - if (identical === maxLines) { - // 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`; - } - return `${msg}${skipped ? skippedMsg : ''}\n${res}${other}${end}${indicator}`; } diff --git a/test/parallel/test-assert-deep.js b/test/parallel/test-assert-deep.js index 0e09a32817b269..4536b6d535f703 100644 --- a/test/parallel/test-assert-deep.js +++ b/test/parallel/test-assert-deep.js @@ -750,7 +750,7 @@ assert.throws( () => assert.notDeepStrictEqual(new Date(2000, 3, 14), new Date(2000, 3, 14)), { name: 'AssertionError [ERR_ASSERTION]', - message: 'Expected "actual" not to be strictly deep-equal ' + + message: 'Expected "actual" not to be strictly deep-equal to: ' + util.inspect(new Date(2000, 3, 14)) } ); @@ -795,7 +795,7 @@ assert.throws( { code: 'ERR_ASSERTION', name: 'AssertionError [ERR_ASSERTION]', - message: `${defaultMsgStartFull}\n\n+ /a/gim\n- /a/im` + message: `${defaultMsgStartFull}\n\n+ /a/gim\n- /a/im\n ^` }); { diff --git a/test/parallel/test-assert.js b/test/parallel/test-assert.js index 746b16642994f3..6aecfc0fe6bf3f 100644 --- a/test/parallel/test-assert.js +++ b/test/parallel/test-assert.js @@ -71,7 +71,7 @@ assert.throws(() => a.strictEqual(null, undefined), assert.throws( () => a.notStrictEqual(2, 2), { - message: 'Expected "actual" to be strictly unequal 2', + message: 'Expected "actual" to be strictly unequal to: 2', name: 'AssertionError [ERR_ASSERTION]' } ); @@ -79,7 +79,8 @@ assert.throws( assert.throws( () => a.notStrictEqual('a '.repeat(30), 'a '.repeat(30)), { - message: `Expected "actual" to be strictly unequal '${'a '.repeat(30)}'`, + message: 'Expected "actual" to be strictly unequal to: ' + + `'${'a '.repeat(30)}'`, name: 'AssertionError [ERR_ASSERTION]' } ); @@ -415,7 +416,8 @@ assert.throws( code: 'ERR_ASSERTION', name: 'AssertionError [ERR_ASSERTION]', message: strictEqualMessageStart + - '+ actual - expected\n\n+ [Error: foo]\n- [Error: foobar]' + '+ actual - expected\n\n' + + '+ [Error: foo]\n- [Error: foobar]\n ^' } ); @@ -606,12 +608,15 @@ assert.throws( }); // notDeepEqual tests - message = 'Expected "actual" not to be strictly deep-equal\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 = 'Expected "actual" not to be strictly deep-equal' + + 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( From 4587e5d6161be8c5a2967f5acf46bca4c9b4331d Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Fri, 27 Jul 2018 23:58:25 +0200 Subject: [PATCH 5/6] fixup: use stderr instead of stdout --- lib/internal/assert.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/internal/assert.js b/lib/internal/assert.js index 1d36ec9f2849b9..894b36d17fadab 100644 --- a/lib/internal/assert.js +++ b/lib/internal/assert.js @@ -84,15 +84,16 @@ function createErrDiff(actual, expected, operator) { `${actualLines[0]} !== ${expectedLines[0]}\n`; } } else { - // If the stdout is a tty and the input length is lower than the current + // 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.stdout.isTTY ? process.stdout.columns : 80; + const maxLength = process.stderr.isTTY ? process.stderr.columns : 80; if (inputLength < maxLength) { while (actualLines[0][i] === expectedLines[0][i]) { i++; } - if (i !== 0) { + // 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)}^`; @@ -235,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'; From c00e63d9c9617f94035e529bc146fdbc8823efc4 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Sun, 29 Jul 2018 02:25:00 +0200 Subject: [PATCH 6/6] fixup: improve docs --- doc/api/assert.md | 100 ++++++++++++++++++++++++++-------------------- 1 file changed, 56 insertions(+), 44 deletions(-) diff --git a/doc/api/assert.md b/doc/api/assert.md index 57fcc14de2ba90..b08ec102d5f1c9 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) ```