Skip to content

Commit

Permalink
Update pretty-format and use it for diffs; update snapshot printing; …
Browse files Browse the repository at this point in the history
…print without toJSON if objects appear similar.
  • Loading branch information
cpojer committed Sep 21, 2016
1 parent 1ffad00 commit 628b222
Show file tree
Hide file tree
Showing 14 changed files with 421 additions and 444 deletions.
2 changes: 1 addition & 1 deletion packages/jest-diff/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"chalk": "^1.1.3",
"diff": "^3.0.0",
"jest-matcher-utils": "^15.1.0",
"pretty-format": "~4.0.0"
"pretty-format": "~4.2.1"
},
"scripts": {
"test": "../../packages/jest-cli/bin/jest.js"
Expand Down
13 changes: 13 additions & 0 deletions packages/jest-diff/src/__tests__/__snapshots__/diff-test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
exports[`test falls back to not call toJSON if objects look identical 1`] = `
"Compared values serialize to the same structure.
Printing internal object structure without calling \`toJSON\` instead.
- Expected
+ Received
  Object {
-  \"line\": 1,
+  \"line\": 2,
   \"toJSON\": [Function toJSON],
  }"
`;
8 changes: 7 additions & 1 deletion packages/jest-diff/src/__tests__/diff-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ describe('no visual difference', () => {
`'${JSON.stringify(values[0])}' and '${JSON.stringify(values[1])}'`,
() => {
expect(stripAnsi(diff(values[0], values[1]))).toBe(
'Compared values have no visual difference',
'Compared values have no visual difference.',
);
},
);
Expand All @@ -68,6 +68,12 @@ test('oneline strings', () => {
expect(stripAnsi(diff('123456789', '234567890'))).toBe(null);
});

test('falls back to not call toJSON if objects look identical', () => {
const a = {toJSON: () => 'foo', line: 1};
const b = {toJSON: () => 'foo', line: 2};
expect(diff(a, b)).toMatchSnapshot();
});

test('multiline strings', () => {
const result = diff(
`line 1
Expand Down
10 changes: 8 additions & 2 deletions packages/jest-diff/src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,11 @@

const chalk = require('chalk');

module.exports.NO_DIFF_MESSAGE =
chalk.dim.underline('Compared values have no visual difference');
exports.NO_DIFF_MESSAGE =
chalk.dim('Compared values have no visual difference.');

exports.SIMILAR_MESSAGE =
chalk.dim(
'Compared values serialize to the same structure.\n' +
'Printing internal object structure without calling `toJSON` instead.',
);
2 changes: 1 addition & 1 deletion packages/jest-diff/src/diffStrings.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const getAnnotation = options =>
chalk.red('+ ' + ((options && options.bAnnotation) || 'Received')) + '\n\n';

// diff characters if oneliner and diff lines if multiline
function diffStrings(a: string, b: string, options: ?DiffOptions): ?string {
function diffStrings(a: string, b: string, options: ?DiffOptions): string {
let isDifferent = false;

// `diff` uses the Myers LCS diff algorithm which runs in O(n+d^2) time
Expand Down
35 changes: 30 additions & 5 deletions packages/jest-diff/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,19 @@ const diffStrings = require('./diffStrings');
const {getType} = require('jest-matcher-utils');
const prettyFormat = require('pretty-format');

const jsxLikePlugins = [ReactTestComponentPlugin, ReactElementPlugin];
const NO_DIFF_MESSAGE = require('./constants').NO_DIFF_MESSAGE;
const {
NO_DIFF_MESSAGE,
SIMILAR_MESSAGE,
} = require('./constants');

const PLUGINS = [ReactTestComponentPlugin, ReactElementPlugin];
const FORMAT_OPTIONS = {
plugins: PLUGINS,
};
const FALLBACK_FORMAT_OPTIONS = {
callToJSON: false,
plugins: PLUGINS,
};

// Generate a string that will highlight the difference between two values
// with green and red. (similar to how github does code diffing)
Expand Down Expand Up @@ -49,10 +60,24 @@ function diff(a: any, b: any, options: ?DiffOptions): ?string {
case 'boolean':
return null;
default:
return diffStrings(
prettyFormat(a, {plugins: jsxLikePlugins}, options),
prettyFormat(b, {plugins: jsxLikePlugins}, options),
let diffMessage = diffStrings(
prettyFormat(a, FORMAT_OPTIONS),
prettyFormat(b, FORMAT_OPTIONS),
options,
);
// If the comparison yields no results, compare again but this time
// without calling `toJSON`.
if (diffMessage === NO_DIFF_MESSAGE) {
diffMessage = diffStrings(
prettyFormat(a, FALLBACK_FORMAT_OPTIONS),
prettyFormat(b, FALLBACK_FORMAT_OPTIONS),
options,
);
if (diffMessage !== NO_DIFF_MESSAGE) {
diffMessage = SIMILAR_MESSAGE + '\n\n' + diffMessage;
}
}
return diffMessage;
}
}

Expand Down
3 changes: 2 additions & 1 deletion packages/jest-matcher-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"test": "../../packages/jest-cli/bin/jest.js"
},
"dependencies": {
"chalk": "^1.1.3"
"chalk": "^1.1.3",
"pretty-format": "~4.2.1"
}
}
24 changes: 12 additions & 12 deletions packages/jest-matcher-utils/src/__tests__/index-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,19 @@ const {stringify, getType} = require('../');

describe('.stringify()', () => {
[
[[], '[]'],
[[], 'Array []'],
[{}, '{}'],
[1, '1'],
[0, '0'],
[1.5, '1.5'],
[null, 'null'],
[undefined, '"undefined"'],
[undefined, 'undefined'],
['abc', '"abc"'],
[Symbol.for('abc'), '"Symbol(abc)"'],
[NaN, '"NaN"'],
[Infinity, '"Infinity"'],
[-Infinity, '"-Infinity"'],
[/ab\.c/gi, '"/ab\\\\.c/gi"'],
[Symbol.for('abc'), 'Symbol(abc)'],
[NaN, 'NaN'],
[Infinity, 'Infinity'],
[-Infinity, '-Infinity'],
[/ab\.c/gi, '/ab\\.c/gi'],
].forEach(([v, s]) => {
test(stringify(v), () => {
expect(stringify(v)).toBe(s);
Expand All @@ -36,7 +36,7 @@ describe('.stringify()', () => {
test('circular references', () => {
const a = {};
a.a = a;
expect(stringify(a)).toBe('{"a":"[Circular]"}');
expect(stringify(a)).toBe('{"a": [Circular]}');
});

test('toJSON error', () => {
Expand All @@ -45,12 +45,13 @@ describe('.stringify()', () => {
throw new Error('Nope.');
},
};
expect(stringify(evil)).toBe('[object]');
expect(stringify({a: {b: {evil}}})).toBe('[object]');
expect(stringify(evil)).toBe('{"toJSON": [Function toJSON]}');
expect(stringify({a: {b: {evil}}}))
.toBe('{"a": {"b": {"evil": {"toJSON": [Function toJSON]}}}}');

function Evil() {}
Evil.toJSON = evil.toJSON;
expect(stringify(Evil)).toBe('function Evil() {}');
expect(stringify(Evil)).toBe('[Function Evil]');
});
});

Expand All @@ -66,5 +67,4 @@ describe('.getType()', () => {
test('boolean', () => expect(getType(true)).toBe('boolean'));
test('symbol', () => expect(getType(Symbol.for('a'))).toBe('symbol'));
test('regexp', () => expect(getType(/abc/)).toBe('regexp'));

});
67 changes: 5 additions & 62 deletions packages/jest-matcher-utils/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
'use strict';

const chalk = require('chalk');
const prettyFormat = require('pretty-format');

export type ValueType =
| 'array'
Expand Down Expand Up @@ -74,68 +75,10 @@ const getType = (value: any): ValueType => {
throw new Error(`value of unknown type: ${value}`);
};

const stringifyValue = (value, visitedSet) => {
if (value instanceof Error) {
const name = (value.constructor && value.constructor.name) || 'Error';
return `${name}: ${value.message}`;
} else if (typeof value === 'object' && value !== null) {
if (
value &&
value.constructor &&
value.constructor.name === 'RegExp'
) {
return value.toString();
} else {
if (visitedSet.has(value)) {
return '[Circular]';
}
visitedSet.add(value);
}
} else if (typeof value === 'function') {
return value.toString();
} else if (typeof value === 'undefined') {
return 'undefined';
// $FlowFixMe symbols are not supported by flow yet
} else if (typeof value === 'symbol') {
return value.toString();
} else if (value === Infinity) {
return 'Infinity';
} else if (value === -Infinity) {
return '-Infinity';
} else if (Number.isNaN(value)) {
return 'NaN';
}
return value;
};

const stringifyDeep = obj => {
const visitedSet = new Set();
let result = null;
try {
result = JSON.stringify(
obj,
(_, value) => stringifyValue(value, visitedSet),
);
} catch (err) { }
return typeof result === 'string' ? result : null;
};

const stringifyShallow = obj => {
let result = null;
try {
result = stringifyValue(obj, new Set());
} catch (err) {}
return typeof result === 'string' ? result : null;
};

// Convert to JSON removing circular references and
// converting JS values to strings.
const stringify = (obj: any): string => {
return (
stringifyDeep(obj) ||
stringifyShallow(obj) ||
'[' + typeof obj + ']'
);
const stringify = (object: any): string => {
return prettyFormat(object, {
min: true,
});
};

const printReceived = (object: any) => RECEIVED_COLOR(stringify(object));
Expand Down
Loading

0 comments on commit 628b222

Please sign in to comment.