diff --git a/integration_tests/__tests__/__snapshots__/stack_trace-test.js.snap b/integration_tests/__tests__/__snapshots__/stack_trace-test.js.snap index 7c69c1c5616a..da982fbd5eb9 100644 --- a/integration_tests/__tests__/__snapshots__/stack_trace-test.js.snap +++ b/integration_tests/__tests__/__snapshots__/stack_trace-test.js.snap @@ -36,6 +36,15 @@ Ran all test suites matching \\"test-error-test.js\\". " `; +exports[`Stack Trace prints a stack trace for errors without message in stack trace 1`] = ` +"Test Suites: 1 failed, 1 total +Tests: 1 failed, 1 total +Snapshots: 0 total +Time: <> +Ran all test suites matching \\"stack-trace-without-message-test.js\\". +" +`; + exports[`Stack Trace prints a stack trace for matching errors 1`] = ` "Test Suites: 1 failed, 1 total Tests: 1 failed, 1 total diff --git a/integration_tests/__tests__/stack_trace-test.js b/integration_tests/__tests__/stack_trace-test.js index 4d46f446cfeb..8015311b1a1e 100644 --- a/integration_tests/__tests__/stack_trace-test.js +++ b/integration_tests/__tests__/stack_trace-test.js @@ -93,6 +93,21 @@ describe('Stack Trace', () => { ); }); + it('prints a stack trace for errors without message in stack trace', () => { + const result = runJest('stack_trace', [ + 'stack-trace-without-message-test.js', + ]); + const stderr = result.stderr.toString(); + + expect(extractSummary(stderr).summary).toMatchSnapshot(); + expect(result.status).toBe(1); + + expect(stderr).toMatch(/important message/); + expect(stderr).toMatch( + /\s+at\s(?:.+?)\s\(__tests__\/stack-trace-without-message-test\.js/, + ); + }); + it('does not print a stack trace for errors when --noStackTrace is given', () => { const result = runJest('stack_trace', [ 'test-error-test.js', diff --git a/integration_tests/stack_trace/__tests__/stack-trace-without-message-test.js b/integration_tests/stack_trace/__tests__/stack-trace-without-message-test.js new file mode 100644 index 000000000000..e40e5a0fe7f1 --- /dev/null +++ b/integration_tests/stack_trace/__tests__/stack-trace-without-message-test.js @@ -0,0 +1,14 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +'use strict'; + +test('fails with error without proper message', () => { + const error = new Error('important message'); + error.stack = error.stack.replace('Error: important message', 'Error '); + throw error; +}); diff --git a/packages/jest-jasmine2/src/reporter.js b/packages/jest-jasmine2/src/reporter.js index d575571e6a70..9ade7625f078 100644 --- a/packages/jest-jasmine2/src/reporter.js +++ b/packages/jest-jasmine2/src/reporter.js @@ -129,6 +129,21 @@ class Jasmine2Reporter { return this._resultsPromise; } + _addMissingMessageToStack(stack: string, message: ?string) { + // Some errors (e.g. Angular injection error) don't prepend error.message + // to stack, instead the first line of the stack is just plain 'Error' + const ERROR_REGEX = /^Error\s*\n/; + if ( + stack && + message && + ERROR_REGEX.test(stack) && + stack.indexOf(message) === -1 + ) { + return message + stack.replace(ERROR_REGEX, '\n'); + } + return stack; + } + _extractSpecResults( specResult: SpecResult, ancestorTitles: Array, @@ -150,7 +165,7 @@ class Jasmine2Reporter { specResult.failedExpectations.forEach(failed => { const message = !failed.matcherName && failed.stack - ? failed.stack + ? this._addMissingMessageToStack(failed.stack, failed.message) : failed.message || ''; results.failureMessages.push(message); });