Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Codeframe fixes #5094

Merged
merged 8 commits into from
Dec 17, 2017
53 changes: 53 additions & 0 deletions integration_tests/__tests__/__snapshots__/failures.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,59 @@ exports[`not throwing Error objects 4`] = `
"
`;

exports[`works with assertions in separate files 1`] = `
"FAIL __tests__/test_macro.test.js
✕ use some imported macro to make assertion

● use some imported macro to make assertion

expect(received).toEqual(expected)

Expected value to equal:
2
Received:
1

10 |
11 | module.exports = (one: any, two: any) => {
> 12 | expect(one).toEqual(two);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potentially we can walk down the stack until we find the test file. But I think this makes more sense

13 | };
14 |

at macros.js:12:15
at __tests__/test_macro.test.js:14:3

"
`;

exports[`works with async failures 1`] = `
"FAIL __tests__/async_failures.test.js
✕ something async

● something async

expect(received).toEqual(expected)

Expected value to equal:
{\\"baz\\": \\"bar\\"}
Received:
{\\"foo\\": \\"bar\\"}

Difference:

- Expected
+ Received

Object {
- \\"baz\\": \\"bar\\",
+ \\"foo\\": \\"bar\\",
}

at ../../packages/expect/build/index.js:155:54

"
`;

exports[`works with node assert 1`] = `
"FAIL __tests__/node_assertion_error.test.js
✕ assert
Expand Down
15 changes: 9 additions & 6 deletions integration_tests/__tests__/coverage_remapping.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,23 @@
const {readFileSync} = require('fs');
const path = require('path');
const skipOnWindows = require('../../scripts/skip_on_windows');
const {run} = require('../utils');
const {cleanup, run} = require('../utils');
const runJest = require('../runJest');

const dir = path.resolve(__dirname, '../coverage-remapping');
const coverageDir = path.join(dir, 'coverage');

skipOnWindows.suite();

beforeAll(() => {
cleanup(coverageDir);
});

it('maps code coverage against original source', () => {
const dir = path.resolve(__dirname, '../coverage-remapping');
run('yarn', dir);
runJest(dir, ['--coverage', '--mapCoverage', '--no-cache']);

const coverageMapFile = path.join(
__dirname,
'../coverage-remapping/coverage/coverage-final.json',
);
const coverageMapFile = path.join(coverageDir, 'coverage-final.json');
const coverageMap = JSON.parse(readFileSync(coverageMapFile, 'utf-8'));

// reduce absolute paths embedded in the coverage map to just filenames
Expand Down
12 changes: 12 additions & 0 deletions integration_tests/__tests__/failures.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,15 @@ test('works with node assert', () => {

expect(summary).toMatchSnapshot();
});

test('works with assertions in separate files', () => {
const {stderr} = runJest(dir, ['test_macro.test.js']);

expect(normalizeDots(extractSummary(stderr).rest)).toMatchSnapshot();
});

test('works with async failures', () => {
const {stderr} = runJest(dir, ['async_failures.test.js']);

expect(normalizeDots(extractSummary(stderr).rest)).toMatchSnapshot();
});
13 changes: 13 additions & 0 deletions integration_tests/failures/__tests__/async_failures.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails oncall+jsinfra
*/
'use strict';

test('something async', () => {
return expect(Promise.resolve({foo: 'bar'})).resolves.toEqual({baz: 'bar'});
});
15 changes: 15 additions & 0 deletions integration_tests/failures/__tests__/test_macro.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails oncall+jsinfra
*/
'use strict';

const shouldEqual = require('../macros');

test('use some imported macro to make assertion', () => {
shouldEqual(1, 2);
});
13 changes: 13 additions & 0 deletions integration_tests/failures/macros.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
'use strict';

module.exports = (one: any, two: any) => {
expect(one).toEqual(two);
};
39 changes: 28 additions & 11 deletions packages/jest-message-util/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ import slash from 'slash';
import {codeFrameColumns} from '@babel/code-frame';
import StackUtils from 'stack-utils';

// stack utils tries to create pretty stack by making paths relative.
const stackUtils = new StackUtils({
cwd: 'something which does not exist',
});

let nodeInternals = [];

try {
Expand Down Expand Up @@ -45,6 +50,7 @@ const JEST_INTERNALS_IGNORE = /^\s+at.*?jest(-.*?)?(\/|\\)(build|node_modules|pa
const ANONYMOUS_FN_IGNORE = /^\s+at <anonymous>.*$/;
const ANONYMOUS_PROMISE_IGNORE = /^\s+at (new )?Promise \(<anonymous>\).*$/;
const ANONYMOUS_GENERATOR_IGNORE = /^\s+at Generator.next \(<anonymous>\).*$/;
const NATIVE_NEXT_IGNORE = /^\s+at next \(native\).*$/;
const TITLE_INDENT = ' ';
const MESSAGE_INDENT = ' ';
const STACK_INDENT = ' ';
Expand Down Expand Up @@ -136,6 +142,10 @@ const removeInternalStackEntries = (lines, options: StackTraceOptions) => {
return false;
}

if (NATIVE_NEXT_IGNORE.test(line)) {
return false;
}

if (nodeInternals.some(internal => internal.test(line))) {
return false;
}
Expand Down Expand Up @@ -202,19 +212,26 @@ export const formatStackTrace = (
: null;
lines = removeInternalStackEntries(lines, options);

if (testPath) {
const topFrame = lines
.join('\n')
.trim()
.split('\n')[0];

const parsedFrame = StackUtils.parseLine(topFrame);

if (parsedFrame) {
const topFrame = lines
.map(line => line.trim())
.filter(Boolean)
.filter(
line =>
!line.includes(`${path.sep}node_modules${path.sep}`) &&
!line.includes(`${path.sep}expect${path.sep}build${path.sep}`),
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this second one is only needed in jest's own tests, as we resolve the symlink properly. In normal cases only node_modules is needed

)
.map(line => stackUtils.parseLine(line))
.filter(Boolean)
.filter(parsedFrame => parsedFrame.file)[0];

if (topFrame) {
const filename = topFrame.file;

if (path.isAbsolute(filename)) {
renderedCallsite = codeFrameColumns(
fs.readFileSync(testPath, 'utf8'),
fs.readFileSync(filename, 'utf8'),
{
start: {line: parsedFrame.line},
start: {line: topFrame.line},
},
{highlightCode: true},
);
Expand Down