diff --git a/src/extension-test/unit/test-runner-test.ts b/src/extension-test/unit/test-runner-test.ts index 714649f90..3c7a6018b 100644 --- a/src/extension-test/unit/test-runner-test.ts +++ b/src/extension-test/unit/test-runner-test.ts @@ -167,4 +167,35 @@ orange` apple` ); }); + + it('can produce detailed messages with diffs', () => { + expect( + cider.detailedMessage({ + type: 'fail', + ns: 'core', + context: 'ctx', + index: 2, + expected: '{:key1 "value1", :key2 "value2"}', + actual: '{:key1 "wrongValue", :key2 "value2"}', + var: 'test', + file: 'core.clj', + line: 10, + message: 'Values do not match', + diffs: [ + [ + '{:key1 "wrongValue", :key2 "value2"}', + ['{:key1 "value1", :key2 "value2"}', '{:key1 "wrongValue"}'], + ], + ], + }) + ).toBe(`; FAIL in core/test (core.clj:10): +; ctx: Values do not match +; expected: +{:key1 "value1", :key2 "value2"} +; actual: +{:key1 "wrongValue", :key2 "value2"} +; diff: +- {:key1 "value1", :key2 "value2"} ++ {:key1 "wrongValue"}`); + }); }); diff --git a/src/nrepl/cider.ts b/src/nrepl/cider.ts index 5c0e23a0c..ad2617fdd 100644 --- a/src/nrepl/cider.ts +++ b/src/nrepl/cider.ts @@ -1,3 +1,4 @@ +import { diff } from 'semver'; // https://github.com/clojure-emacs/cider-nrepl/blob/a740583c3aa8b582f3097611787a276775131d32/src/cider/nrepl/middleware/test.clj#L45 export interface TestSummary { ns: number; @@ -142,6 +143,31 @@ export function lineInformation(result: TestResult): string { return ` (${result.file}:${result.line})`; } +function getDiffMessages(result: TestResult): string[] { + const diffs = result.diffs; + const messages: string[] = []; + + if (diffs && Array.isArray(diffs)) { + diffs.forEach((diffPair: [string, [string, string]]) => { + if (Array.isArray(diffPair) && diffPair.length === 2) { + const [_, [removed, added]] = diffPair; + + if (removed || added) { + messages.push('; diff:'); + messages.push(removed ? `- ${removed.trim()}` : ''); + if (added) { + messages.push(`+ ${added.trim()}`); + } + } + } else { + console.warn('Invalid diff pair format:', diffPair); + } + }); + } + + return messages; +} + // Return a detailed message about why a test failed. // If the test passed, return the empty string. // The message contains "comment" lines that are prepended with ; @@ -167,12 +193,18 @@ export function detailedMessage(result: TestResult): string | undefined { if (message) { messages.push(`; ${message}`); } + if (result.expected) { messages.push(`; expected:\n${result.expected}`); } if (result.actual) { messages.push(`; actual:\n${result.actual}`); } + + const diffMessages = getDiffMessages(result); + if (diffMessages.length > 0) { + messages.push(...diffMessages); + } } return messages.length > 0 ? messages.join('\n') : undefined; } diff --git a/src/testRunner.ts b/src/testRunner.ts index a929ca1b9..c02a337fe 100644 --- a/src/testRunner.ts +++ b/src/testRunner.ts @@ -139,6 +139,7 @@ async function onTestResult( run.errored(assertion, new vscode.TestMessage(cider.shortMessage(result))); break; case 'fail': + run.failed(assertion, new vscode.TestMessage(cider.detailedMessage(result))); default: run.failed(assertion, new vscode.TestMessage(cider.shortMessage(result))); break;