From 6f5643982fe183a7f9f264467dee0592653ed963 Mon Sep 17 00:00:00 2001 From: Mitchell Wills Date: Wed, 1 Dec 2021 12:05:05 -0800 Subject: [PATCH] fix(adapter): don't duplicate multiline failure messages The current code to handle removing error messages for formatting does not properly handle multiline error messages and results in the message being repeated at the top of the stack trace. The code only searched for the message in the first stack line, which meant it would never be found because the message was multiple lines, which meant that the message would be pre-pended by the message not in stack logic. The existing multiline test actually triggers this behavior, but because it used toMatch it only verified that the message was included, not that it only existed once. --- src/adapter.js | 17 ++++++++++++++--- test/adapter.spec.js | 15 +++++++++++++-- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/adapter.js b/src/adapter.js index 2552c253..c9f7ec7e 100644 --- a/src/adapter.js +++ b/src/adapter.js @@ -82,12 +82,23 @@ function formatFailedStep (step) { // Remove the message prior to processing the stack to prevent issues like // https://github.com/karma-runner/karma-jasmine/issues/79 - var stackframes = step.stack.split('\n') + + // Jasmine filters empty newlines from the stack so remove them from the + // message before searching for it. Also, also remove the trailing newline (if + // present) so that when the message is put back on the top of the stack it + // doesn't introduce an extra newline. + var messageWithoutEmptyLines = step.message.replace(/\n+/g, '\n').replace(/\n$/, '') + var messageStartIndex = step.stack.indexOf(messageWithoutEmptyLines) + var firstNewlineIndex = step.stack.indexOf('\n') var messageOnStack = null - if (stackframes[0].indexOf(step.message) !== -1) { + var stack = step.stack + if (messageStartIndex !== -1 && messageStartIndex < firstNewlineIndex) { // Remove the message if it is in the stack string (eg Chrome) - messageOnStack = stackframes.shift() + messageOnStack = step.stack.substring(0, messageStartIndex + messageWithoutEmptyLines.length) + stack = step.stack.substring(messageStartIndex + messageWithoutEmptyLines.length) } + + var stackframes = stack.split('\n') // Filter frames var relevantStackFrames = getRelevantStackFrom(stackframes) if (messageOnStack) { diff --git a/test/adapter.spec.js b/test/adapter.spec.js index 21063218..801553e1 100644 --- a/test/adapter.spec.js +++ b/test/adapter.spec.js @@ -359,7 +359,7 @@ describe('jasmine adapter', function () { stack: '@file.js:123\n' } - expect(formatFailedStep(step)).toMatch(/^Jasmine fail message/) + expect(formatFailedStep(step)).toBe('Jasmine fail message\n@file.js:123') }) it('should report message if no stack trace', function () { @@ -383,6 +383,7 @@ describe('jasmine adapter', function () { expect(formatFailedStep(step)).toBe('MESSAGE\nsource/controller.js:45') }) + it('should properly format message containing new-line characters', function () { // FF does not have the message in the stack trace @@ -392,7 +393,17 @@ describe('jasmine adapter', function () { stack: 'Error: Jasmine fail\nmessage\n@file.js:123' } - expect(formatFailedStep(step)).toMatch('Jasmine fail\nmessage\n@file.js:123') + expect(formatFailedStep(step)).toBe('Error: Jasmine fail\nmessage\n@file.js:123') + }) + + it('should properly format message containing repeated new-line characters', function () { + var step = { + passed: false, + message: 'Failed: 1. failure message\n\n\n2. another failure\n3. a third failure\n\n\n\n', + stack: 'Error: Failed: 1. failure message\n2. another failure\n3. a third failure\n at \n at UserContext. (/base/jasmine/test.js:13:9)\n at ' + } + + expect(formatFailedStep(step)).toBe('Error: Failed: 1. failure message\n2. another failure\n3. a third failure\n at \n at UserContext. (/base/jasmine/test.js:13:9)\n at ') }) })