Skip to content

Commit

Permalink
Fix stack traces and runtime error reporting.
Browse files Browse the repository at this point in the history
  • Loading branch information
cpojer committed May 12, 2016
1 parent a825616 commit 9215414
Show file tree
Hide file tree
Showing 16 changed files with 219 additions and 87 deletions.
4 changes: 1 addition & 3 deletions integration_tests/__tests__/coverage_report-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,11 @@
*/
'use strict';

jest.unmock('../runJest');

const runJest = require('../runJest');
const fs = require('fs');
const path = require('path');

describe('coverage_report', () => {
describe('Coverage Report', () => {
it('outputs coverage report', () => {
const result = runJest('coverage_report', ['--coverage']);
const coverageDir = path.resolve(__dirname, '../coverage_report/coverage');
Expand Down
4 changes: 1 addition & 3 deletions integration_tests/__tests__/json_reporter-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,9 @@
*/
'use strict';

jest.unmock('../runJest');

const runJest = require('../runJest');

describe('coverage_report', () => {
describe('JSON Reporter', () => {
it('outputs coverage report', () => {
const result = runJest('json_reporter', ['--json']);
const stdout = result.stdout.toString();
Expand Down
107 changes: 107 additions & 0 deletions integration_tests/__tests__/stack_trace-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/**
* 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';

const runJest = require('../runJest');

describe('Stack Trace', () => {

it('prints a stack trace for runtime errors', () => {
const result = runJest('stack_trace', ['runtime-error-test.js']);
const stdout = result.stdout.toString();

expect(stdout).toMatch(
/1 test suite failed, 0 tests passed/
);
expect(result.status).toBe(1);
expect(stdout).toMatch(
/ReferenceError: thisIsARuntimeError is not defined/
);
expect(stdout).toMatch(
/\s+at\s(?:.+?)\s\(__integration_tests__\/runtime-error-test\.js/
);
});

it('does not print a stack trace for runtime errors when --noStackTrace is given', () => {
const result = runJest('stack_trace', [
'runtime-error-test.js',
'--noStackTrace',
]);
const stdout = result.stdout.toString();

expect(stdout).toMatch(
/1 test suite failed, 0 tests passed/
);
expect(result.status).toBe(1);

expect(stdout).toMatch(
/ReferenceError: thisIsARuntimeError is not defined/
);
expect(stdout).not.toMatch(
/\s+at\s(?:.+?)\s\(__integration_tests__\/runtime-error-test\.js/
);
});

it('prints a stack trace for matching errors', () => {
const result = runJest('stack_trace', ['stack-trace-test.js']);
const stdout = result.stdout.toString();

expect(stdout).toMatch(/1 test failed, 0 tests passed/);
expect(result.status).toBe(1);

expect(stdout).toMatch(
/\s+at\s(?:.+?)\s\(__integration_tests__\/stack-trace-test\.js/
);
});

it('does not print a stack trace for matching errors when --noStackTrace is given', () => {
const result = runJest('stack_trace', [
'stack-trace-test.js',
'--noStackTrace',
]);
const stdout = result.stdout.toString();

expect(stdout).toMatch(/1 test failed, 0 tests passed/);
expect(result.status).toBe(1);

expect(stdout).not.toMatch(
/\s+at\s(?:.+?)\s\(__integration_tests__\/stack-trace-test\.js/
);
});

it('prints a stack trace for errors', () => {
const result = runJest('stack_trace', ['test-error-test.js']);
const stdout = result.stdout.toString();

expect(stdout).toMatch(/2 tests failed, 0 tests passed/);
expect(result.status).toBe(1);

expect(stdout).toMatch(/Error: this is unexpected\./);
expect(stdout).toMatch(/this is a string\. thrown/);

expect(stdout).toMatch(
/\s+at\s(?:.+?)\s\(__integration_tests__\/test-error-test\.js/
);
});

it('does not print a stack trace for errors when --noStackTrace is given', () => {
const result = runJest('stack_trace', [
'test-error-test.js',
'--noStackTrace',
]);
const stdout = result.stdout.toString();

expect(stdout).toMatch(/2 tests failed, 0 tests passed/);
expect(result.status).toBe(1);

expect(stdout).not.toMatch(
/\s+at\s(?:.+?)\s\(__integration_tests__\/test-error-test\.js/
);
});

});
1 change: 0 additions & 1 deletion integration_tests/json_reporter/.gitignore

This file was deleted.

6 changes: 3 additions & 3 deletions integration_tests/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"jest": {
"testPathIgnorePatterns": [
"__integration_tests__/(?!__tests__).*"
]
"unmockedModulePathPatterns": [
"<rootDir>/runJest.js$"
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* 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';

thisIsARuntimeError();
Original file line number Diff line number Diff line change
@@ -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';

describe('stack trace', () => {
it('fails', () => {
expect(1).toBe(3);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* 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.
*/
/* eslint-disable no-throw-literal */
'use strict';

describe('error stack trace', () => {
it('fails', () => {
throw new Error('this is unexpected.');
});

it('fails strings', () => {
throw 'this is a string.';
});
});
5 changes: 5 additions & 0 deletions integration_tests/stack_trace/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"jest": {
"testDirectoryName": "__integration_tests__"
}
}
2 changes: 1 addition & 1 deletion packages/jest-cli/src/jest.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ function runJest(config, argv, pipe, onComplete) {
}
if (argv.json) {
process.stdout.write(
JSON.stringify(formatTestResults(runResults))
JSON.stringify(formatTestResults(runResults, config))
);
}
return runResults;
Expand Down
17 changes: 11 additions & 6 deletions packages/jest-cli/src/lib/formatTestResults.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

const utils = require('jest-util');

const formatResult = (testResult, codeCoverageFormatter, reporter) => {
const formatResult = (testResult, config, codeCoverageFormatter, reporter) => {
const output = {
name: testResult.testFilePath,
summary: '',
Expand All @@ -32,22 +32,27 @@ const formatResult = (testResult, codeCoverageFormatter, reporter) => {

if (!allTestsPassed) {
output.message = utils.formatFailureMessage(testResult, {
rootDir: '',
noStackTrace: config.noStackTrace,
rootDir: config.rootDir,
verbose: false,
});
}
}

return output;
};

function formatTestResults(results, codeCoverageFormatter, reporter) {
function formatTestResults(results, config, codeCoverageFormatter, reporter) {
if (!codeCoverageFormatter) {
codeCoverageFormatter = coverage => coverage;
}

const testResults = results.testResults.map(
testResult => formatResult(testResult, codeCoverageFormatter, reporter)
);
const testResults = results.testResults.map(testResult => formatResult(
testResult,
config,
codeCoverageFormatter,
reporter
));

return {
success: results.success,
Expand Down
9 changes: 7 additions & 2 deletions packages/jest-cli/src/reporters/DefaultTestReporter.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,12 @@ class DefaultTestReporter {
}

if (!allTestsPassed) {
const failureMessage = formatFailureMessage(testResult, config);
const failureMessage = formatFailureMessage(testResult, {
noStackTrace: config.noStackTrace,
rootDir: config.rootDir,
verbose: config.verbose,
});

// If we write more than one character at a time it is possible that
// node exits in the middle of printing the result.
// If you are reading this and you are from the future, this might not
Expand Down Expand Up @@ -110,7 +115,7 @@ class DefaultTestReporter {
const totalErrors = aggregatedResults.numRuntimeErrorTestSuites;
const runTime = (Date.now() - aggregatedResults.startTime) / 1000;

if (totalTests === 0) {
if (totalTests === 0 && totalErrors === 0) {
return;
}

Expand Down
4 changes: 1 addition & 3 deletions packages/jest-jasmine1/src/reporter.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,7 @@ class JasmineReporter extends jasmine.Reporter {
if (result.passed()) {
results.numPassingAsserts++;
} else if (!result.matcherName && result.trace.stack) {
results.failureMessages.push(
this._formatter.formatException(result.trace.stack)
);
results.failureMessages.push(result.trace.stack);
} else {
results.failureMessages.push(
this._formatter.formatMatchFailure(result)
Expand Down
2 changes: 1 addition & 1 deletion packages/jest-jasmine2/src/reporter.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ class Jasmine2Reporter {
specResult.failedExpectations.forEach(failed => {
let message;
if (!failed.matcherName && failed.stack) {
message = this._formatter.formatException(failed.stack);
message = failed.stack;
} else {
message = this._formatter.formatMatchFailure(failed);
}
Expand Down
25 changes: 4 additions & 21 deletions packages/jest-util/lib/JasmineFormatter.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

const diff = require('diff');
const chalk = require('chalk');
const cleanStackTrace = require('./formatMessages').cleanStackTrace;

const ERROR_TITLE_COLOR = chalk.bold.underline.red;
const LINEBREAK_REGEX = /[\r\n]/;
Expand Down Expand Up @@ -60,23 +59,14 @@ class JasmineFormatter {

// error message & stack live on 'trace' field in jasmine 1.3
const error = result.trace ? result.trace : result;
if (error.stack) {
message = this.formatStackTrace(error.stack, error.message, message);
if (!this._config.noStackTrace && error.stack) {
message = error.stack
.replace(message, error.message)
.replace(/^.*Error:\s*/, '');
}
return message;
}


formatException(stackTrace) {
// jasmine doesn't give us access to the actual Error object, so we
// have to regexp out the message from the stack string in order to
// colorize the `message` value
return cleanStackTrace(stackTrace.replace(
/(^(.|\n)*?(?=\n\s*at\s))/,
ERROR_TITLE_COLOR('$1')
));
}

highlightDifferences(a, b) {
let differ;
if (a.match(LINEBREAK_REGEX) || b.match(LINEBREAK_REGEX)) {
Expand Down Expand Up @@ -177,13 +167,6 @@ class JasmineFormatter {
}
}

formatStackTrace(stackTrace, originalMessage, formattedMessage) {
return cleanStackTrace(
stackTrace
.replace(originalMessage, formattedMessage)
.replace(/^.*Error:\s*/, '')
);
}
}

module.exports = JasmineFormatter;
Loading

0 comments on commit 9215414

Please sign in to comment.