Skip to content

Commit

Permalink
Polish failure reporting in Jest. (#1458)
Browse files Browse the repository at this point in the history
  • Loading branch information
cpojer authored Aug 18, 2016
1 parent 2453935 commit 081bdd5
Show file tree
Hide file tree
Showing 26 changed files with 317 additions and 227 deletions.
26 changes: 15 additions & 11 deletions integration_tests/__tests__/__snapshots__/console-test.js.snap
Original file line number Diff line number Diff line change
@@ -1,34 +1,38 @@
exports[`test console printing 1`] = `
" PASS __tests__/console-test.js
● Console
log __tests__/console-test.js:11
console.log __tests__/console-test.js:11
This is a log message.
info __tests__/console-test.js:13
console.info __tests__/console-test.js:13
This is an info message.
warn __tests__/console-test.js:15
console.warn __tests__/console-test.js:15
This is a warning message.
error __tests__/console-test.js:17
console.error __tests__/console-test.js:17
This is a error message.
PASS __tests__/console2-test.js
● Console
error __tests__/console2-test.js:18
This is an error from another test file."
console.error __tests__/console2-test.js:18
This is an error from another test file.
"
`;

exports[`test console printing with --verbose 1`] = `
" log __tests__/console-test.js:11
" console.log __tests__/console-test.js:11
This is a log message.
info __tests__/console-test.js:13
console.info __tests__/console-test.js:13
This is an info message.
warn __tests__/console-test.js:15
console.warn __tests__/console-test.js:15
This is a warning message.
error __tests__/console-test.js:17
console.error __tests__/console-test.js:17
This is a error message.
error __tests__/console2-test.js:18
console.error __tests__/console2-test.js:18
This is an error from another test file.
"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
exports[`test failure messages 1`] = `
" console.log __tests__/test-error-test.js:12
This is what a log looks like.
console.error __tests__/test-error-test.js:14
This is what an error looks like.
"
`;
4 changes: 2 additions & 2 deletions integration_tests/__tests__/empty_suite_error-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ describe('JSON Reporter', () => {
it('fails the test suite if it contains no tests', () => {
const result = runJest(DIR, []);
const stderr = result.stderr.toString();
expect(stderr).toMatch('Test suite failed to run:');
expect(stderr).toMatch('Test suite failed to run');
expect(stderr).toMatch(
'Error: Your test suite must contain at least one test.'
'Your test suite must contain at least one test.'
);
});
});
18 changes: 18 additions & 0 deletions integration_tests/__tests__/failures-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* 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 path = require('path');
const runJest = require('../runJest');

it('failure messages', () => {
const dir = path.resolve(__dirname, '../failures');
const {stdout} = runJest(dir);
expect(stdout).toMatchSnapshot();
});
4 changes: 2 additions & 2 deletions integration_tests/__tests__/stack_trace-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ describe('Stack Trace', () => {
expect(stderr).toMatch(/3 tests failed, 0 tests passed/);
expect(result.status).toBe(1);

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

expect(stderr).toMatch(
Expand All @@ -91,7 +91,7 @@ describe('Stack Trace', () => {
// Make sure we show Jest's jest-resolve as part of the stack trace
/* eslint-disable max-len */
expect(stderr).toMatch(
/Error: Cannot find module 'this-module-does-not-exist' from 'test-error-test\.js'/
/Cannot find module 'this-module-does-not-exist' from 'test-error-test\.js'/
);
/* eslint-enable max-len */

Expand Down
2 changes: 1 addition & 1 deletion integration_tests/__tests__/testcheck-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ describe('testcheck', () => {
const result = runJest('testcheck', ['testcheck-exceptions-test.js']);
expect(result.status).toBe(1);
expect(result.stderr.toString()).toMatch(
/Error: This error should be reported/
/This error should be reported/
);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
exports[`failure messages toMatchSnapshot 1`] = `
Object {
"a": 1,
"b": 2
}
`;
69 changes: 69 additions & 0 deletions integration_tests/failures/__tests__/test-error-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/**
* 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('failure messages', () => {
test('logs', () => {
console.log('This is what a log looks like.');

console.error('This is what an error looks like.');
});

[
() => expect(1).toBe(2),
() => expect('a').toBe(2),
() => expect(true).toBe(5),
() => expect({a: 1, b: 2}).toBe({a: 1, b: 3}),
() => expect({
a: 1,
b: 2,
c: {
apple: 'banana',
},
}).toEqual({
a: 2,
b: 2,
c: {
kiwi: 'melon',
},
}),
() => expect([1, 2, 3]).toEqual([2, 3, 1]),
() => expect([1, 2, 3]).toEqual([1, 3, 2]),
() => expect(true).not.toBeTruthy(),
() => expect(false).toBeTruthy(),
() => expect(true).toBeFalsy(),
() => expect(false).not.toBeFalsy(),
() => expect({a: 1, b: 2}).toBeFalsy(),
() => expect(1).toBeNaN(),
() => expect({}).toBeNull(),
() => expect(undefined).toBeDefined(),
() => expect(1).toBeUndefined(),
() => expect(1).toBeGreaterThan(5),
() => expect(1).toBeGreaterThanOrEqual(5),
() => expect(5).toBeLessThan(1),
() => expect(5).toBeLessThanOrEqual(1),
() => expect([1, 2]).toContain({apple: 'banana'}),
() => expect(4).toBeCloseTo(100),
() => expect('hello this is a message').toMatch('bye'),
() => expect(() => {}).toThrow(),
() => expect(() => {}).toThrow(new TypeError('This is an error!')),
() => expect(() => { throw new Error('not an error'); })
.toThrow('This is an error!'),
() => expect(() => {}).toThrow('This is an error!'),
() => expect(() => { throw new Error('not an error'); })
.toThrowError('This is an error!'),
].forEach(fn => test(fn.toString(), fn));

test('toMatchSnapshot', () => {
expect({
a: 1,
apple: 'banana',
}).toMatchSnapshot();
});

});
5 changes: 5 additions & 0 deletions integration_tests/failures/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"jest": {
"testEnvironment": "node"
}
}
4 changes: 2 additions & 2 deletions packages/jest-cli/src/reporters/DefaultReporter.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ class DefaultReporter extends BaseReporter {
const consoleBuffer = testResult.console;
if (consoleBuffer && consoleBuffer.length) {
this._write(
' ' + TITLE_BULLET + 'Console\n' +
getConsoleOutput(config.rootDir, config.verbose, consoleBuffer),
' ' + TITLE_BULLET + 'Console\n\n' +
getConsoleOutput(config.rootDir, config.verbose, consoleBuffer) + '\n',
);
}

Expand Down
12 changes: 5 additions & 7 deletions packages/jest-cli/src/reporters/getConsoleOutput.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,18 @@ module.exports = (root: string, verbose: boolean, buffer: ConsoleBuffer) => {
.map(line => CONSOLE_INDENT + line)
.join('\n');

let typeMessage = 'console.' + type;
if (type === 'warn') {
message = chalk.yellow(message);
type = chalk.yellow(type);
typeMessage = chalk.yellow(typeMessage);
} else if (type === 'error') {
message = chalk.red(message);
type = chalk.red(type);
typeMessage = chalk.red(typeMessage);
}

return (
output +
TITLE_INDENT +
(verbose ? type : chalk.bold(type)) +
' ' + chalk.gray(origin) + '\n' +
message + '\n'
output + TITLE_INDENT + chalk.dim(typeMessage) +
' ' + chalk.gray(origin) + '\n' + message + '\n'
);
}, '');
};
12 changes: 6 additions & 6 deletions packages/jest-diff/src/__tests__/diff-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ describe('different types', () => {

test(`'${a}' and '${b}'`, () => {
expect(stripAnsi(diff(a, b))).toBe(
'Comparing different types of values.\n' +
`Actual: '${typeB}', Expected: '${typeA}'`,
'Comparing two different types of values:\n' +
` Expected: ${typeA}\n Received: ${typeB}`,
);

});
Expand Down Expand Up @@ -91,12 +91,12 @@ test('objects', () => {

test('numbers', () => {
const result = diff(123, 234);
expect(stripAnsi(result)).toMatch(/Actual\: 234/);
expect(stripAnsi(result)).toMatch(/Expected\: 123/);
expect(result).toBe(null);
expect(result).toBe(null);
});

test('booleans', () => {
const result = diff(true, false);
expect(stripAnsi(result)).toMatch(/Actual\: false/);
expect(stripAnsi(result)).toMatch(/Expected\: true/);
expect(result).toBe(null);
expect(result).toBe(null);
});
26 changes: 16 additions & 10 deletions packages/jest-diff/src/diffStrings.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,19 @@
const chalk = require('chalk');
const jsDiff = require('diff');

const ANNOTATION = `${chalk.red('- expected')} ${chalk.green('+ actual')}\n\n`;
const NO_DIFF_MESSAGE = require('./constants.js').NO_DIFF_MESSAGE;
const {NO_DIFF_MESSAGE} = require('./constants.js');

export type DiffOptions = {
aAnnotation: string,
bAnnotation: string,
};

const getAnnotation = options =>
chalk.green('- ' + ((options && options.aAnnotation) || 'Expected')) + '\n' +
chalk.red('+ ' + ((options && options.bAnnotation) || 'Received')) + '\n\n';

// diff characters if oneliner and diff lines if multiline
function diffStrings(a: string, b: string): ?string {
function diffStrings(a: string, b: string, options: ?DiffOptions): ?string {
const multiline = a.match(/[\r\n]/) !== -1 && b.indexOf('\n') !== -1;
let isDifferent = false;
let result;
Expand All @@ -34,20 +42,18 @@ function diffStrings(a: string, b: string): ?string {

const lines = part.value.split('\n');
const color = part.added
? chalk.green
: (part.removed ? chalk.red : chalk.white);
? chalk.red
: (part.removed ? chalk.green : chalk.white);

if (lines[lines.length - 1] === '') {
lines.pop();
}

return lines.map(line => {
const mark = part.added
? chalk.green('+')
: part.removed ? chalk.red('-') : ' ';
const mark = color(part.added ? '+' : part.removed ? '-' : ' ');
return mark + ' ' + color(line) + '\n';
}).join('');
}).join('');
}).join('').trim();
} else {
result = jsDiff.diffChars(a, b).map(part => {
if (part.added || part.removed) {
Expand All @@ -62,7 +68,7 @@ function diffStrings(a: string, b: string): ?string {
}

if (isDifferent) {
return ANNOTATION + result;
return getAnnotation(options) + result;
} else {
return NO_DIFF_MESSAGE;
}
Expand Down
23 changes: 11 additions & 12 deletions packages/jest-diff/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

'use strict';

import type {DiffOptions} from './diffStrings';

const chalk = require('chalk');
const diffStrings = require('./diffStrings');
const {getType} = require('jest-matcher-utils');
Expand All @@ -20,32 +22,29 @@ const NO_DIFF_MESSAGE = require('./constants').NO_DIFF_MESSAGE;

// Generate a string that will highlight the difference between two values
// with green and red. (similar to how github does code diffing)
function diff(a: any, b: any): ?string {
function diff(a: any, b: any, options: ?DiffOptions): ?string {
if (a === b) {
return NO_DIFF_MESSAGE;
}

if (getType(a) !== getType(b)) {
return chalk.reset.gray(
'Comparing different types of values.\n' +
`Actual: '${chalk.cyan(getType(b))}'` +
', ' +
`Expected: '${chalk.cyan(getType(a))}'`,
return (
'Comparing two different types of values:\n' +
` Expected: ${chalk.green(getType(a))}\n` +
` Received: ${chalk.red(getType(b))}`
);
}

switch (getType(a)) {
case 'string':
return diffStrings(String(a), String(b));
return diffStrings(String(a), String(b), options);
case 'number':
case 'boolean':
return chalk.gray('Actual: ') + chalk.red(b) +
'\n' +
chalk.gray('Expected: ') + chalk.green(a);
return null;
default:
return diffStrings(
prettyFormat(a, {plugins: [jsxLikeExtension]}),
prettyFormat(b, {plugins: [jsxLikeExtension]}),
prettyFormat(a, {plugins: [jsxLikeExtension]}, options),
prettyFormat(b, {plugins: [jsxLikeExtension]}, options),
);
}
}
Expand Down
3 changes: 2 additions & 1 deletion packages/jest-jasmine2/src/__tests__/matchers-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ jest.disableAutomock();

describe('matchers', () => {
it('proxies matchers to jest-matchers', () => {
expect(() => expect(1).toBe(2)).toThrowError(/expected.*to be.*using '===/);
expect(() => expect(1).toBe(2))
.toThrowError(/Received.*but expected.*using '===/);
});
});
Loading

0 comments on commit 081bdd5

Please sign in to comment.