diff --git a/packages/jest-message-util/package.json b/packages/jest-message-util/package.json index ff5a7c7018ab..05168fe7ee3a 100644 --- a/packages/jest-message-util/package.json +++ b/packages/jest-message-util/package.json @@ -8,6 +8,7 @@ "license": "MIT", "main": "build/index.js", "dependencies": { + "@babel/code-frame": "^7.0.0-beta.35", "chalk": "^2.0.1", "micromatch": "^2.3.11", "slash": "^1.0.0", diff --git a/packages/jest-message-util/src/index.js b/packages/jest-message-util/src/index.js index 3ed544fdffbb..baf20ee74439 100644 --- a/packages/jest-message-util/src/index.js +++ b/packages/jest-message-util/src/index.js @@ -10,10 +10,12 @@ import type {Glob, Path} from 'types/Config'; import type {AssertionResult, TestResult} from 'types/TestResult'; +import fs from 'fs'; import path from 'path'; import chalk from 'chalk'; import micromatch from 'micromatch'; import slash from 'slash'; +import {codeFrameColumns} from '@babel/code-frame'; import StackUtils from 'stack-utils'; let nodeInternals = []; @@ -194,15 +196,45 @@ export const formatStackTrace = ( testPath: ?Path, ) => { let lines = stack.split(/\n/); + let renderedCallsite = ''; const relativeTestPath = testPath ? slash(path.relative(config.rootDir, testPath)) : null; lines = removeInternalStackEntries(lines, options); - return lines + + if (testPath) { + const topFrame = lines + .join('\n') + .trim() + .split('\n')[0]; + + const parsedFrame = StackUtils.parseLine(topFrame); + + if (parsedFrame) { + renderedCallsite = codeFrameColumns( + fs.readFileSync(testPath, 'utf8'), + { + start: {line: parsedFrame.line}, + }, + {highlightCode: true}, + ); + + renderedCallsite = renderedCallsite + .split('\n') + .map(line => MESSAGE_INDENT + line) + .join('\n'); + + renderedCallsite = `\n\n${renderedCallsite}\n\n`; + } + } + + const stacktrace = lines .map(trimPaths) .map(formatPaths.bind(null, config, options, relativeTestPath)) .map(line => STACK_INDENT + line) .join('\n'); + + return renderedCallsite + stacktrace; }; export const formatResultsErrors = ( @@ -222,14 +254,14 @@ export const formatResultsErrors = ( return failedResults .map(({result, content}) => { - let {message, stack} = separateMessageFromStack(content); - stack = options.noStackTrace + const separated = separateMessageFromStack(content); + const formattedStack = options.noStackTrace ? '' : STACK_TRACE_COLOR( - formatStackTrace(stack, config, options, testPath), + formatStackTrace(separated.stack, config, options, testPath), ) + '\n'; - message = message + const message = separated.message .split(/\n/) .map(line => MESSAGE_INDENT + line) .join('\n'); @@ -243,7 +275,7 @@ export const formatResultsErrors = ( result.title, ) + '\n'; - return title + '\n' + message + '\n' + stack; + return title + '\n' + message + '\n' + formattedStack; }) .join('\n'); }; diff --git a/yarn.lock b/yarn.lock index ad7e65cf58d6..a59d9e7ab28b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,14 @@ # yarn lockfile v1 +"@babel/code-frame@^7.0.0-beta.35": + version "7.0.0-beta.35" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.35.tgz#04eeb6dca7efef8f65776a4c214157303b85ad51" + dependencies: + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^3.0.0" + "@types/node@*": version "8.0.53" resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.53.tgz#396b35af826fa66aad472c8cb7b8d5e277f4e6d8"