You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
407 lines
11 KiB
407 lines
11 KiB
'use strict'; |
|
|
|
Object.defineProperty(exports, '__esModule', { |
|
value: true |
|
}); |
|
exports.printSnapshotAndReceived = |
|
exports.printReceived = |
|
exports.printPropertiesAndReceived = |
|
exports.printExpected = |
|
exports.noColor = |
|
exports.matcherHintFromConfig = |
|
exports.getSnapshotColorForChalkInstance = |
|
exports.getReceivedColorForChalkInstance = |
|
exports.bReceivedColor = |
|
exports.aSnapshotColor = |
|
exports.SNAPSHOT_ARG = |
|
exports.PROPERTIES_ARG = |
|
exports.HINT_ARG = |
|
void 0; |
|
|
|
var _chalk = _interopRequireDefault(require('chalk')); |
|
|
|
var _utils = require('expect/build/utils'); |
|
|
|
var _jestDiff = require('jest-diff'); |
|
|
|
var _jestGetType = require('jest-get-type'); |
|
|
|
var _jestMatcherUtils = require('jest-matcher-utils'); |
|
|
|
var _prettyFormat = require('pretty-format'); |
|
|
|
var _colors = require('./colors'); |
|
|
|
var _dedentLines = require('./dedentLines'); |
|
|
|
var _utils2 = require('./utils'); |
|
|
|
function _interopRequireDefault(obj) { |
|
return obj && obj.__esModule ? obj : {default: obj}; |
|
} |
|
|
|
/** |
|
* Copyright (c) Facebook, Inc. and its affiliates. 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. |
|
*/ |
|
|
|
/* eslint-disable local/ban-types-eventually */ |
|
// Temporary hack because getObjectSubset has known limitations, |
|
// is not in the public interface of the expect package, |
|
// and the long-term goal is to use a non-serialization diff. |
|
// Make sure to remove file from `exports` in `expect/package.json`. |
|
const getSnapshotColorForChalkInstance = chalkInstance => { |
|
const level = chalkInstance.level; |
|
|
|
if (level === 3) { |
|
return chalkInstance |
|
.rgb( |
|
_colors.aForeground3[0], |
|
_colors.aForeground3[1], |
|
_colors.aForeground3[2] |
|
) |
|
.bgRgb( |
|
_colors.aBackground3[0], |
|
_colors.aBackground3[1], |
|
_colors.aBackground3[2] |
|
); |
|
} |
|
|
|
if (level === 2) { |
|
return chalkInstance |
|
.ansi256(_colors.aForeground2) |
|
.bgAnsi256(_colors.aBackground2); |
|
} |
|
|
|
return chalkInstance.magenta.bgYellowBright; |
|
}; |
|
|
|
exports.getSnapshotColorForChalkInstance = getSnapshotColorForChalkInstance; |
|
|
|
const getReceivedColorForChalkInstance = chalkInstance => { |
|
const level = chalkInstance.level; |
|
|
|
if (level === 3) { |
|
return chalkInstance |
|
.rgb( |
|
_colors.bForeground3[0], |
|
_colors.bForeground3[1], |
|
_colors.bForeground3[2] |
|
) |
|
.bgRgb( |
|
_colors.bBackground3[0], |
|
_colors.bBackground3[1], |
|
_colors.bBackground3[2] |
|
); |
|
} |
|
|
|
if (level === 2) { |
|
return chalkInstance |
|
.ansi256(_colors.bForeground2) |
|
.bgAnsi256(_colors.bBackground2); |
|
} |
|
|
|
return chalkInstance.cyan.bgWhiteBright; // also known as teal |
|
}; |
|
|
|
exports.getReceivedColorForChalkInstance = getReceivedColorForChalkInstance; |
|
const aSnapshotColor = getSnapshotColorForChalkInstance(_chalk.default); |
|
exports.aSnapshotColor = aSnapshotColor; |
|
const bReceivedColor = getReceivedColorForChalkInstance(_chalk.default); |
|
exports.bReceivedColor = bReceivedColor; |
|
|
|
const noColor = string => string; |
|
|
|
exports.noColor = noColor; |
|
const HINT_ARG = 'hint'; |
|
exports.HINT_ARG = HINT_ARG; |
|
const SNAPSHOT_ARG = 'snapshot'; |
|
exports.SNAPSHOT_ARG = SNAPSHOT_ARG; |
|
const PROPERTIES_ARG = 'properties'; |
|
exports.PROPERTIES_ARG = PROPERTIES_ARG; |
|
|
|
const matcherHintFromConfig = ( |
|
{context: {isNot, promise}, hint, inlineSnapshot, matcherName, properties}, |
|
isUpdatable |
|
) => { |
|
const options = { |
|
isNot, |
|
promise |
|
}; |
|
|
|
if (isUpdatable) { |
|
options.receivedColor = bReceivedColor; |
|
} |
|
|
|
let expectedArgument = ''; |
|
|
|
if (typeof properties === 'object') { |
|
expectedArgument = PROPERTIES_ARG; |
|
|
|
if (isUpdatable) { |
|
options.expectedColor = noColor; |
|
} |
|
|
|
if (typeof hint === 'string' && hint.length !== 0) { |
|
options.secondArgument = HINT_ARG; |
|
options.secondArgumentColor = _jestMatcherUtils.BOLD_WEIGHT; |
|
} else if (typeof inlineSnapshot === 'string') { |
|
options.secondArgument = SNAPSHOT_ARG; |
|
|
|
if (isUpdatable) { |
|
options.secondArgumentColor = aSnapshotColor; |
|
} else { |
|
options.secondArgumentColor = noColor; |
|
} |
|
} |
|
} else { |
|
if (typeof hint === 'string' && hint.length !== 0) { |
|
expectedArgument = HINT_ARG; |
|
options.expectedColor = _jestMatcherUtils.BOLD_WEIGHT; |
|
} else if (typeof inlineSnapshot === 'string') { |
|
expectedArgument = SNAPSHOT_ARG; |
|
|
|
if (isUpdatable) { |
|
options.expectedColor = aSnapshotColor; |
|
} |
|
} |
|
} |
|
|
|
return (0, _jestMatcherUtils.matcherHint)( |
|
matcherName, |
|
undefined, |
|
expectedArgument, |
|
options |
|
); |
|
}; // Given array of diffs, return string: |
|
// * include common substrings |
|
// * exclude change substrings which have opposite op |
|
// * include change substrings which have argument op |
|
// with change color only if there is a common substring |
|
|
|
exports.matcherHintFromConfig = matcherHintFromConfig; |
|
|
|
const joinDiffs = (diffs, op, hasCommon) => |
|
diffs.reduce( |
|
(reduced, diff) => |
|
reduced + |
|
(diff[0] === _jestDiff.DIFF_EQUAL |
|
? diff[1] |
|
: diff[0] !== op |
|
? '' |
|
: hasCommon |
|
? (0, _jestMatcherUtils.INVERTED_COLOR)(diff[1]) |
|
: diff[1]), |
|
'' |
|
); |
|
|
|
const isLineDiffable = received => { |
|
const receivedType = (0, _jestGetType.getType)(received); |
|
|
|
if ((0, _jestGetType.isPrimitive)(received)) { |
|
return typeof received === 'string'; |
|
} |
|
|
|
if ( |
|
receivedType === 'date' || |
|
receivedType === 'function' || |
|
receivedType === 'regexp' |
|
) { |
|
return false; |
|
} |
|
|
|
if (received instanceof Error) { |
|
return false; |
|
} |
|
|
|
if ( |
|
receivedType === 'object' && |
|
typeof received.asymmetricMatch === 'function' |
|
) { |
|
return false; |
|
} |
|
|
|
return true; |
|
}; |
|
|
|
const printExpected = val => |
|
(0, _jestMatcherUtils.EXPECTED_COLOR)((0, _utils2.minify)(val)); |
|
|
|
exports.printExpected = printExpected; |
|
|
|
const printReceived = val => |
|
(0, _jestMatcherUtils.RECEIVED_COLOR)((0, _utils2.minify)(val)); |
|
|
|
exports.printReceived = printReceived; |
|
|
|
const printPropertiesAndReceived = ( |
|
properties, |
|
received, |
|
expand // CLI options: true if `--expand` or false if `--no-expand` |
|
) => { |
|
const aAnnotation = 'Expected properties'; |
|
const bAnnotation = 'Received value'; |
|
|
|
if (isLineDiffable(properties) && isLineDiffable(received)) { |
|
return (0, _jestDiff.diffLinesUnified)( |
|
(0, _utils2.serialize)(properties).split('\n'), |
|
(0, _utils2.serialize)( |
|
(0, _utils.getObjectSubset)(received, properties) |
|
).split('\n'), |
|
{ |
|
aAnnotation, |
|
aColor: _jestMatcherUtils.EXPECTED_COLOR, |
|
bAnnotation, |
|
bColor: _jestMatcherUtils.RECEIVED_COLOR, |
|
changeLineTrailingSpaceColor: _chalk.default.bgYellow, |
|
commonLineTrailingSpaceColor: _chalk.default.bgYellow, |
|
emptyFirstOrLastLinePlaceholder: '↵', |
|
// U+21B5 |
|
expand, |
|
includeChangeCounts: true |
|
} |
|
); |
|
} |
|
|
|
const printLabel = (0, _jestMatcherUtils.getLabelPrinter)( |
|
aAnnotation, |
|
bAnnotation |
|
); |
|
return ( |
|
printLabel(aAnnotation) + |
|
printExpected(properties) + |
|
'\n' + |
|
printLabel(bAnnotation) + |
|
printReceived(received) |
|
); |
|
}; |
|
|
|
exports.printPropertiesAndReceived = printPropertiesAndReceived; |
|
const MAX_DIFF_STRING_LENGTH = 20000; |
|
|
|
const printSnapshotAndReceived = ( |
|
a, |
|
b, |
|
received, |
|
expand // CLI options: true if `--expand` or false if `--no-expand` |
|
) => { |
|
const aAnnotation = 'Snapshot'; |
|
const bAnnotation = 'Received'; |
|
const aColor = aSnapshotColor; |
|
const bColor = bReceivedColor; |
|
const options = { |
|
aAnnotation, |
|
aColor, |
|
bAnnotation, |
|
bColor, |
|
changeLineTrailingSpaceColor: noColor, |
|
commonLineTrailingSpaceColor: _chalk.default.bgYellow, |
|
emptyFirstOrLastLinePlaceholder: '↵', |
|
// U+21B5 |
|
expand, |
|
includeChangeCounts: true |
|
}; |
|
|
|
if (typeof received === 'string') { |
|
if ( |
|
a.length >= 2 && |
|
a.startsWith('"') && |
|
a.endsWith('"') && |
|
b === (0, _prettyFormat.format)(received) |
|
) { |
|
// If snapshot looks like default serialization of a string |
|
// and received is string which has default serialization. |
|
if (!a.includes('\n') && !b.includes('\n')) { |
|
// If neither string is multiline, |
|
// display as labels and quoted strings. |
|
let aQuoted = a; |
|
let bQuoted = b; |
|
|
|
if ( |
|
a.length - 2 <= MAX_DIFF_STRING_LENGTH && |
|
b.length - 2 <= MAX_DIFF_STRING_LENGTH |
|
) { |
|
const diffs = (0, _jestDiff.diffStringsRaw)( |
|
a.slice(1, -1), |
|
b.slice(1, -1), |
|
true |
|
); |
|
const hasCommon = diffs.some( |
|
diff => diff[0] === _jestDiff.DIFF_EQUAL |
|
); |
|
aQuoted = |
|
'"' + joinDiffs(diffs, _jestDiff.DIFF_DELETE, hasCommon) + '"'; |
|
bQuoted = |
|
'"' + joinDiffs(diffs, _jestDiff.DIFF_INSERT, hasCommon) + '"'; |
|
} |
|
|
|
const printLabel = (0, _jestMatcherUtils.getLabelPrinter)( |
|
aAnnotation, |
|
bAnnotation |
|
); |
|
return ( |
|
printLabel(aAnnotation) + |
|
aColor(aQuoted) + |
|
'\n' + |
|
printLabel(bAnnotation) + |
|
bColor(bQuoted) |
|
); |
|
} // Else either string is multiline, so display as unquoted strings. |
|
|
|
a = (0, _utils2.deserializeString)(a); // hypothetical expected string |
|
|
|
b = received; // not serialized |
|
} // Else expected had custom serialization or was not a string |
|
// or received has custom serialization. |
|
|
|
return a.length <= MAX_DIFF_STRING_LENGTH && |
|
b.length <= MAX_DIFF_STRING_LENGTH |
|
? (0, _jestDiff.diffStringsUnified)(a, b, options) |
|
: (0, _jestDiff.diffLinesUnified)(a.split('\n'), b.split('\n'), options); |
|
} |
|
|
|
if (isLineDiffable(received)) { |
|
const aLines2 = a.split('\n'); |
|
const bLines2 = b.split('\n'); // Fall through to fix a regression for custom serializers |
|
// like jest-snapshot-serializer-raw that ignore the indent option. |
|
|
|
const b0 = (0, _utils2.serialize)(received, 0); |
|
|
|
if (b0 !== b) { |
|
const aLines0 = (0, _dedentLines.dedentLines)(aLines2); |
|
|
|
if (aLines0 !== null) { |
|
// Compare lines without indentation. |
|
const bLines0 = b0.split('\n'); |
|
return (0, _jestDiff.diffLinesUnified2)( |
|
aLines2, |
|
bLines2, |
|
aLines0, |
|
bLines0, |
|
options |
|
); |
|
} |
|
} // Fall back because: |
|
// * props include a multiline string |
|
// * text has more than one adjacent line |
|
// * markup does not close |
|
|
|
return (0, _jestDiff.diffLinesUnified)(aLines2, bLines2, options); |
|
} |
|
|
|
const printLabel = (0, _jestMatcherUtils.getLabelPrinter)( |
|
aAnnotation, |
|
bAnnotation |
|
); |
|
return ( |
|
printLabel(aAnnotation) + |
|
aColor(a) + |
|
'\n' + |
|
printLabel(bAnnotation) + |
|
bColor(b) |
|
); |
|
}; |
|
|
|
exports.printSnapshotAndReceived = printSnapshotAndReceived;
|
|
|