From fb473f69d35ab8fb7d044ea5090eaa0e8494d616 Mon Sep 17 00:00:00 2001 From: Mohamed Shams El-Deen Date: Tue, 11 Aug 2026 15:49:41 +0300 Subject: [PATCH 1/2] assert: truncate long strings in diffs to improve DX --- lib/internal/assert/assertion_error.js | 45 ++++++++++++++++++-------- lib/internal/assert/myers_diff.js | 28 ++++++++++++++-- 2 files changed, 56 insertions(+), 17 deletions(-) diff --git a/lib/internal/assert/assertion_error.js b/lib/internal/assert/assertion_error.js index 5dbf1e7a3413..d7897bd1bc50 100644 --- a/lib/internal/assert/assertion_error.js +++ b/lib/internal/assert/assertion_error.js @@ -125,30 +125,47 @@ function getColoredMyersDiff(actual, expected) { function getStackedDiff(actual, expected) { const isStringComparison = typeof actual === 'string' && typeof expected === 'string'; - let message = `\n${colors.green}+${colors.white} ${actual}\n${colors.red}- ${colors.white}${expected}`; - const stringsLen = actual.length + expected.length; - const maxTerminalLength = process.stderr.isTTY ? process.stderr.columns : 80; - const showIndicator = isStringComparison && (stringsLen <= maxTerminalLength); - - if (showIndicator) { - let indicatorIdx = -1; + let displayActual = actual; + let displayExpected = expected; + let displayIndicatorIdx = -1; + if (isStringComparison) { for (let i = 0; i < actual.length; i++) { if (actual[i] !== expected[i]) { - // Skip the indicator for the first 2 characters because the diff is immediately apparent - // It is 3 instead of 2 to account for the quotes - if (i >= 3) { - indicatorIdx = i; - } + displayIndicatorIdx = i; break; } } + + if (displayIndicatorIdx === -1 && actual.length !== expected.length) { + displayIndicatorIdx = actual.length; + } + + if (displayIndicatorIdx !== -1) { + const contextLength = 15; + + if (displayIndicatorIdx > contextLength + 3) { + const sliceStart = displayIndicatorIdx - contextLength; + displayActual = `...${StringPrototypeSlice(actual, sliceStart)}`; + displayExpected = `...${StringPrototypeSlice(expected, sliceStart)}`; + displayIndicatorIdx = contextLength + 3; + } - if (indicatorIdx !== -1) { - message += `\n${StringPrototypeRepeat(' ', indicatorIdx + 2)}^`; + if (displayActual.length > displayIndicatorIdx + contextLength + 3) { + displayActual = `${StringPrototypeSlice(displayActual, 0, displayIndicatorIdx + contextLength)}...`; + } + if (displayExpected.length > displayIndicatorIdx + contextLength + 3) { + displayExpected = `${StringPrototypeSlice(displayExpected, 0, displayIndicatorIdx + contextLength)}...`; + } } } + let message = `\n${colors.green}+${colors.white} ${displayActual}\n${colors.red}- ${colors.white}${displayExpected}`; + + if (isStringComparison && displayIndicatorIdx >= 3) { + message += `\n${StringPrototypeRepeat(' ', displayIndicatorIdx + 2)}^`; + } + return { message }; } diff --git a/lib/internal/assert/myers_diff.js b/lib/internal/assert/myers_diff.js index ee6359042e31..37f5021fd588 100644 --- a/lib/internal/assert/myers_diff.js +++ b/lib/internal/assert/myers_diff.js @@ -4,6 +4,7 @@ const { ArrayPrototypePush, Int32Array, StringPrototypeEndsWith, + StringPrototypeSlice, } = primordials; const { @@ -125,19 +126,40 @@ function backtrack(trace, actual, expected, checkCommaDisparity) { } function printSimpleMyersDiff(diff) { - let message = ''; - + const grouped = []; for (let diffIdx = diff.length - 1; diffIdx >= 0; diffIdx--) { const { 0: operation, 1: value } = diff[diffIdx]; + if (grouped.length > 0 && grouped[grouped.length - 1][0] === operation) { + grouped[grouped.length - 1][1] += value; + } else { + ArrayPrototypePush(grouped, [operation, value]); + } + } + + let message = ''; + const contextLength = 10; + + for (let i = 0; i < grouped.length; i++) { + const { 0: operation, 1: value } = grouped[i]; let color = colors.white; + let displayVal = value; if (operation === kOperations.INSERT) { color = colors.green; } else if (operation === kOperations.DELETE) { color = colors.red; + } else if (operation === kOperations.NOP) { + const startContext = i > 0 ? contextLength : 0; + const endContext = i < grouped.length - 1 ? contextLength : 0; + + if (value.length > startContext + endContext + 3) { + displayVal = (startContext ? StringPrototypeSlice(value, 0, startContext) : '') + + `${colors.blue}...${colors.white}` + + (endContext ? StringPrototypeSlice(value, -endContext) : ''); + } } - message += `${color}${value}${colors.white}`; + message += `${color}${displayVal}${colors.white}`; } return `\n${message}`; From 43703d6ede531622dd1715d5d247c6c34df6f8d6 Mon Sep 17 00:00:00 2001 From: Mohamed Shams El-Deen Date: Tue, 11 Aug 2026 22:12:11 +0300 Subject: [PATCH 2/2] test: update assert expectations for truncated diffs --- test/fixtures/test-runner/output/assertion-color-tty.snapshot | 2 +- test/parallel/test-assert-class.js | 4 ++-- test/parallel/test-assert.js | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/fixtures/test-runner/output/assertion-color-tty.snapshot b/test/fixtures/test-runner/output/assertion-color-tty.snapshot index 1489619e4e7c..3e61f10cc2f7 100644 --- a/test/fixtures/test-runner/output/assertion-color-tty.snapshot +++ b/test/fixtures/test-runner/output/assertion-color-tty.snapshot @@ -15,7 +15,7 @@ test at test/fixtures/test-runner/output/assertion-color-tty.mjs:4:1 [AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: [32mactual[39m [31mexpected[39m - [39m'[39m[32m![39m[39mH[39m[39me[39m[39ml[39m[39ml[39m[39mo[39m[39m [39m[39mW[39m[39mo[39m[39mr[39m[39ml[39m[39md[39m[31m![39m[39m'[39m + [39m'[39m[32m![39m[39mHello World[39m[31m![39m[39m'[39m ] { generatedMessage: [33mtrue[39m, code: [32m'ERR_ASSERTION'[39m, diff --git a/test/parallel/test-assert-class.js b/test/parallel/test-assert-class.js index cccc7a2f36ff..ba25a0526522 100644 --- a/test/parallel/test-assert-class.js +++ b/test/parallel/test-assert-class.js @@ -187,7 +187,7 @@ test('Assert class non strict with full diff', () => { assertInstance.strictEqual( err.message, `Expected values to be strictly equal:\n+ actual - expected\n\n` + - `+ '${longStringOfAs}'\n- '${longStringOfBs}'\n` + `+ '${'A'.repeat(15)}...\n- '${'B'.repeat(15)}...\n` ); assertInstance.ok( inspect(err).includes(`actual: '${longLinesOfAsWithEllipsis}'`) @@ -341,7 +341,7 @@ test('Assert class non strict with simple diff', () => { assertInstance.strictEqual( err.message, `Expected values to be strictly equal:\n+ actual - expected\n\n` + - `+ '${longStringOfAs}'\n- '${longStringOfBs}'\n` + `+ '${'A'.repeat(15)}...\n- '${'B'.repeat(15)}...\n` ); assertInstance.ok( inspect(err).includes(`actual: '${longLinesOfAsWithEllipsis}'`) diff --git a/test/parallel/test-assert.js b/test/parallel/test-assert.js index d443bd54464f..43eae3fade2b 100644 --- a/test/parallel/test-assert.js +++ b/test/parallel/test-assert.js @@ -379,7 +379,7 @@ test('Test assertion messages', () => { testAssertionMessage(/a/, '/a/'); testAssertionMessage(/abc/gim, '/abc/gim'); testLongAssertionMessage(function f() {}, '[Function: f]'); - testLongAssertionMessage(function() {}, '[Function (anonymous)]'); + testLongAssertionMessage(function() {}, '[Function (anon...'); assert.throws( () => assert.strictEqual([1, 2, 3], ''), @@ -536,7 +536,7 @@ test('Long values should be truncated for display', () => { assert.strictEqual(err.code, 'ERR_ASSERTION'); assert.strictEqual(err.message, `${strictEqualMessageStart}+ actual - expected\n\n` + - `+ '${'A'.repeat(1000)}'\n- ''\n`); + `+ '${'A'.repeat(15)}...\n- ''\n`); assert.strictEqual(err.actual.length, 1000); assert.ok(inspect(err).includes(`actual: '${'A'.repeat(488)}...'`)); return true;