584 lines
17 KiB
JavaScript
584 lines
17 KiB
JavaScript
'use strict';
|
|
|
|
Object.defineProperty(exports, '__esModule', {
|
|
value: true
|
|
});
|
|
Object.defineProperty(exports, 'EXTENSION', {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _SnapshotResolver.EXTENSION;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, 'SnapshotState', {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _State.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, 'addSerializer', {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _plugins.addSerializer;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, 'buildSnapshotResolver', {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _SnapshotResolver.buildSnapshotResolver;
|
|
}
|
|
});
|
|
exports.cleanup = void 0;
|
|
Object.defineProperty(exports, 'getSerializers', {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _plugins.getSerializers;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, 'isSnapshotPath', {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _SnapshotResolver.isSnapshotPath;
|
|
}
|
|
});
|
|
exports.toThrowErrorMatchingSnapshot =
|
|
exports.toThrowErrorMatchingInlineSnapshot =
|
|
exports.toMatchSnapshot =
|
|
exports.toMatchInlineSnapshot =
|
|
void 0;
|
|
var fs = _interopRequireWildcard(require('graceful-fs'));
|
|
var _jestMatcherUtils = require('jest-matcher-utils');
|
|
var _SnapshotResolver = require('./SnapshotResolver');
|
|
var _printSnapshot = require('./printSnapshot');
|
|
var _utils = require('./utils');
|
|
var _plugins = require('./plugins');
|
|
var _State = _interopRequireDefault(require('./State'));
|
|
function _interopRequireDefault(obj) {
|
|
return obj && obj.__esModule ? obj : {default: obj};
|
|
}
|
|
function _getRequireWildcardCache(nodeInterop) {
|
|
if (typeof WeakMap !== 'function') return null;
|
|
var cacheBabelInterop = new WeakMap();
|
|
var cacheNodeInterop = new WeakMap();
|
|
return (_getRequireWildcardCache = function (nodeInterop) {
|
|
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
})(nodeInterop);
|
|
}
|
|
function _interopRequireWildcard(obj, nodeInterop) {
|
|
if (!nodeInterop && obj && obj.__esModule) {
|
|
return obj;
|
|
}
|
|
if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
|
|
return {default: obj};
|
|
}
|
|
var cache = _getRequireWildcardCache(nodeInterop);
|
|
if (cache && cache.has(obj)) {
|
|
return cache.get(obj);
|
|
}
|
|
var newObj = {};
|
|
var hasPropertyDescriptor =
|
|
Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
for (var key in obj) {
|
|
if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
var desc = hasPropertyDescriptor
|
|
? Object.getOwnPropertyDescriptor(obj, key)
|
|
: null;
|
|
if (desc && (desc.get || desc.set)) {
|
|
Object.defineProperty(newObj, key, desc);
|
|
} else {
|
|
newObj[key] = obj[key];
|
|
}
|
|
}
|
|
}
|
|
newObj.default = obj;
|
|
if (cache) {
|
|
cache.set(obj, newObj);
|
|
}
|
|
return newObj;
|
|
}
|
|
var Symbol = globalThis['jest-symbol-do-not-touch'] || globalThis.Symbol;
|
|
var Symbol = globalThis['jest-symbol-do-not-touch'] || globalThis.Symbol;
|
|
var jestExistsFile =
|
|
globalThis[Symbol.for('jest-native-exists-file')] || fs.existsSync;
|
|
const DID_NOT_THROW = 'Received function did not throw'; // same as toThrow
|
|
const NOT_SNAPSHOT_MATCHERS = `Snapshot matchers cannot be used with ${(0,
|
|
_jestMatcherUtils.BOLD_WEIGHT)('not')}`;
|
|
const INDENTATION_REGEX = /^([^\S\n]*)\S/m;
|
|
|
|
// Display name in report when matcher fails same as in snapshot file,
|
|
// but with optional hint argument in bold weight.
|
|
const printSnapshotName = (concatenatedBlockNames = '', hint = '', count) => {
|
|
const hasNames = concatenatedBlockNames.length !== 0;
|
|
const hasHint = hint.length !== 0;
|
|
return `Snapshot name: \`${
|
|
hasNames ? (0, _utils.escapeBacktickString)(concatenatedBlockNames) : ''
|
|
}${hasNames && hasHint ? ': ' : ''}${
|
|
hasHint
|
|
? (0, _jestMatcherUtils.BOLD_WEIGHT)(
|
|
(0, _utils.escapeBacktickString)(hint)
|
|
)
|
|
: ''
|
|
} ${count}\``;
|
|
};
|
|
function stripAddedIndentation(inlineSnapshot) {
|
|
// Find indentation if exists.
|
|
const match = inlineSnapshot.match(INDENTATION_REGEX);
|
|
if (!match || !match[1]) {
|
|
// No indentation.
|
|
return inlineSnapshot;
|
|
}
|
|
const indentation = match[1];
|
|
const lines = inlineSnapshot.split('\n');
|
|
if (lines.length <= 2) {
|
|
// Must be at least 3 lines.
|
|
return inlineSnapshot;
|
|
}
|
|
if (lines[0].trim() !== '' || lines[lines.length - 1].trim() !== '') {
|
|
// If not blank first and last lines, abort.
|
|
return inlineSnapshot;
|
|
}
|
|
for (let i = 1; i < lines.length - 1; i++) {
|
|
if (lines[i] !== '') {
|
|
if (lines[i].indexOf(indentation) !== 0) {
|
|
// All lines except first and last should either be blank or have the same
|
|
// indent as the first line (or more). If this isn't the case we don't
|
|
// want to touch the snapshot at all.
|
|
return inlineSnapshot;
|
|
}
|
|
lines[i] = lines[i].substring(indentation.length);
|
|
}
|
|
}
|
|
|
|
// Last line is a special case because it won't have the same indent as others
|
|
// but may still have been given some indent to line up.
|
|
lines[lines.length - 1] = '';
|
|
|
|
// Return inline snapshot, now at indent 0.
|
|
inlineSnapshot = lines.join('\n');
|
|
return inlineSnapshot;
|
|
}
|
|
const fileExists = (filePath, hasteFS) =>
|
|
hasteFS.exists(filePath) || jestExistsFile(filePath);
|
|
const cleanup = (hasteFS, update, snapshotResolver, testPathIgnorePatterns) => {
|
|
const pattern = `\\.${_SnapshotResolver.EXTENSION}$`;
|
|
const files = hasteFS.matchFiles(pattern);
|
|
let testIgnorePatternsRegex = null;
|
|
if (testPathIgnorePatterns && testPathIgnorePatterns.length > 0) {
|
|
testIgnorePatternsRegex = new RegExp(testPathIgnorePatterns.join('|'));
|
|
}
|
|
const list = files.filter(snapshotFile => {
|
|
const testPath = snapshotResolver.resolveTestPath(snapshotFile);
|
|
|
|
// ignore snapshots of ignored tests
|
|
if (testIgnorePatternsRegex && testIgnorePatternsRegex.test(testPath)) {
|
|
return false;
|
|
}
|
|
if (!fileExists(testPath, hasteFS)) {
|
|
if (update === 'all') {
|
|
fs.unlinkSync(snapshotFile);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
return {
|
|
filesRemoved: list.length,
|
|
filesRemovedList: list
|
|
};
|
|
};
|
|
exports.cleanup = cleanup;
|
|
const toMatchSnapshot = function (received, propertiesOrHint, hint) {
|
|
const matcherName = 'toMatchSnapshot';
|
|
let properties;
|
|
const length = arguments.length;
|
|
if (length === 2 && typeof propertiesOrHint === 'string') {
|
|
hint = propertiesOrHint;
|
|
} else if (length >= 2) {
|
|
if (
|
|
Array.isArray(propertiesOrHint) ||
|
|
typeof propertiesOrHint !== 'object' ||
|
|
propertiesOrHint === null
|
|
) {
|
|
const options = {
|
|
isNot: this.isNot,
|
|
promise: this.promise
|
|
};
|
|
let printedWithType = (0, _jestMatcherUtils.printWithType)(
|
|
'Expected properties',
|
|
propertiesOrHint,
|
|
_printSnapshot.printExpected
|
|
);
|
|
if (length === 3) {
|
|
options.secondArgument = 'hint';
|
|
options.secondArgumentColor = _jestMatcherUtils.BOLD_WEIGHT;
|
|
if (propertiesOrHint == null) {
|
|
printedWithType +=
|
|
"\n\nTo provide a hint without properties: toMatchSnapshot('hint')";
|
|
}
|
|
}
|
|
throw new Error(
|
|
(0, _jestMatcherUtils.matcherErrorMessage)(
|
|
(0, _jestMatcherUtils.matcherHint)(
|
|
matcherName,
|
|
undefined,
|
|
_printSnapshot.PROPERTIES_ARG,
|
|
options
|
|
),
|
|
`Expected ${(0, _jestMatcherUtils.EXPECTED_COLOR)(
|
|
'properties'
|
|
)} must be an object`,
|
|
printedWithType
|
|
)
|
|
);
|
|
}
|
|
|
|
// Future breaking change: Snapshot hint must be a string
|
|
// if (arguments.length === 3 && typeof hint !== 'string') {}
|
|
|
|
properties = propertiesOrHint;
|
|
}
|
|
return _toMatchSnapshot({
|
|
context: this,
|
|
hint,
|
|
isInline: false,
|
|
matcherName,
|
|
properties,
|
|
received
|
|
});
|
|
};
|
|
exports.toMatchSnapshot = toMatchSnapshot;
|
|
const toMatchInlineSnapshot = function (
|
|
received,
|
|
propertiesOrSnapshot,
|
|
inlineSnapshot
|
|
) {
|
|
const matcherName = 'toMatchInlineSnapshot';
|
|
let properties;
|
|
const length = arguments.length;
|
|
if (length === 2 && typeof propertiesOrSnapshot === 'string') {
|
|
inlineSnapshot = propertiesOrSnapshot;
|
|
} else if (length >= 2) {
|
|
const options = {
|
|
isNot: this.isNot,
|
|
promise: this.promise
|
|
};
|
|
if (length === 3) {
|
|
options.secondArgument = _printSnapshot.SNAPSHOT_ARG;
|
|
options.secondArgumentColor = _printSnapshot.noColor;
|
|
}
|
|
if (
|
|
Array.isArray(propertiesOrSnapshot) ||
|
|
typeof propertiesOrSnapshot !== 'object' ||
|
|
propertiesOrSnapshot === null
|
|
) {
|
|
throw new Error(
|
|
(0, _jestMatcherUtils.matcherErrorMessage)(
|
|
(0, _jestMatcherUtils.matcherHint)(
|
|
matcherName,
|
|
undefined,
|
|
_printSnapshot.PROPERTIES_ARG,
|
|
options
|
|
),
|
|
`Expected ${(0, _jestMatcherUtils.EXPECTED_COLOR)(
|
|
'properties'
|
|
)} must be an object`,
|
|
(0, _jestMatcherUtils.printWithType)(
|
|
'Expected properties',
|
|
propertiesOrSnapshot,
|
|
_printSnapshot.printExpected
|
|
)
|
|
)
|
|
);
|
|
}
|
|
if (length === 3 && typeof inlineSnapshot !== 'string') {
|
|
throw new Error(
|
|
(0, _jestMatcherUtils.matcherErrorMessage)(
|
|
(0, _jestMatcherUtils.matcherHint)(
|
|
matcherName,
|
|
undefined,
|
|
_printSnapshot.PROPERTIES_ARG,
|
|
options
|
|
),
|
|
'Inline snapshot must be a string',
|
|
(0, _jestMatcherUtils.printWithType)(
|
|
'Inline snapshot',
|
|
inlineSnapshot,
|
|
_utils.serialize
|
|
)
|
|
)
|
|
);
|
|
}
|
|
properties = propertiesOrSnapshot;
|
|
}
|
|
return _toMatchSnapshot({
|
|
context: this,
|
|
inlineSnapshot:
|
|
inlineSnapshot !== undefined
|
|
? stripAddedIndentation(inlineSnapshot)
|
|
: undefined,
|
|
isInline: true,
|
|
matcherName,
|
|
properties,
|
|
received
|
|
});
|
|
};
|
|
exports.toMatchInlineSnapshot = toMatchInlineSnapshot;
|
|
const _toMatchSnapshot = config => {
|
|
const {context, hint, inlineSnapshot, isInline, matcherName, properties} =
|
|
config;
|
|
let {received} = config;
|
|
context.dontThrow && context.dontThrow();
|
|
const {currentTestName, isNot, snapshotState} = context;
|
|
if (isNot) {
|
|
throw new Error(
|
|
(0, _jestMatcherUtils.matcherErrorMessage)(
|
|
(0, _printSnapshot.matcherHintFromConfig)(config, false),
|
|
NOT_SNAPSHOT_MATCHERS
|
|
)
|
|
);
|
|
}
|
|
if (snapshotState == null) {
|
|
// Because the state is the problem, this is not a matcher error.
|
|
// Call generic stringify from jest-matcher-utils package
|
|
// because uninitialized snapshot state does not need snapshot serializers.
|
|
throw new Error(
|
|
`${(0, _printSnapshot.matcherHintFromConfig)(config, false)}\n\n` +
|
|
'Snapshot state must be initialized' +
|
|
`\n\n${(0, _jestMatcherUtils.printWithType)(
|
|
'Snapshot state',
|
|
snapshotState,
|
|
_jestMatcherUtils.stringify
|
|
)}`
|
|
);
|
|
}
|
|
const fullTestName =
|
|
currentTestName && hint
|
|
? `${currentTestName}: ${hint}`
|
|
: currentTestName || ''; // future BREAKING change: || hint
|
|
|
|
if (typeof properties === 'object') {
|
|
if (typeof received !== 'object' || received === null) {
|
|
throw new Error(
|
|
(0, _jestMatcherUtils.matcherErrorMessage)(
|
|
(0, _printSnapshot.matcherHintFromConfig)(config, false),
|
|
`${(0, _jestMatcherUtils.RECEIVED_COLOR)(
|
|
'received'
|
|
)} value must be an object when the matcher has ${(0,
|
|
_jestMatcherUtils.EXPECTED_COLOR)('properties')}`,
|
|
(0, _jestMatcherUtils.printWithType)(
|
|
'Received',
|
|
received,
|
|
_printSnapshot.printReceived
|
|
)
|
|
)
|
|
);
|
|
}
|
|
const propertyPass = context.equals(received, properties, [
|
|
context.utils.iterableEquality,
|
|
context.utils.subsetEquality
|
|
]);
|
|
if (!propertyPass) {
|
|
const key = snapshotState.fail(fullTestName, received);
|
|
const matched = /(\d+)$/.exec(key);
|
|
const count = matched === null ? 1 : Number(matched[1]);
|
|
const message = () =>
|
|
`${(0, _printSnapshot.matcherHintFromConfig)(
|
|
config,
|
|
false
|
|
)}\n\n${printSnapshotName(currentTestName, hint, count)}\n\n${(0,
|
|
_printSnapshot.printPropertiesAndReceived)(
|
|
properties,
|
|
received,
|
|
snapshotState.expand
|
|
)}`;
|
|
return {
|
|
message,
|
|
name: matcherName,
|
|
pass: false
|
|
};
|
|
} else {
|
|
received = (0, _utils.deepMerge)(received, properties);
|
|
}
|
|
}
|
|
const result = snapshotState.match({
|
|
error: context.error,
|
|
inlineSnapshot,
|
|
isInline,
|
|
received,
|
|
testName: fullTestName
|
|
});
|
|
const {actual, count, expected, pass} = result;
|
|
if (pass) {
|
|
return {
|
|
message: () => '',
|
|
pass: true
|
|
};
|
|
}
|
|
const message =
|
|
expected === undefined
|
|
? () =>
|
|
`${(0, _printSnapshot.matcherHintFromConfig)(
|
|
config,
|
|
true
|
|
)}\n\n${printSnapshotName(currentTestName, hint, count)}\n\n` +
|
|
`New snapshot was ${(0, _jestMatcherUtils.BOLD_WEIGHT)(
|
|
'not written'
|
|
)}. The update flag ` +
|
|
'must be explicitly passed to write a new snapshot.\n\n' +
|
|
'This is likely because this test is run in a continuous integration ' +
|
|
'(CI) environment in which snapshots are not written by default.\n\n' +
|
|
`Received:${actual.includes('\n') ? '\n' : ' '}${(0,
|
|
_printSnapshot.bReceivedColor)(actual)}`
|
|
: () =>
|
|
`${(0, _printSnapshot.matcherHintFromConfig)(
|
|
config,
|
|
true
|
|
)}\n\n${printSnapshotName(currentTestName, hint, count)}\n\n${(0,
|
|
_printSnapshot.printSnapshotAndReceived)(
|
|
expected,
|
|
actual,
|
|
received,
|
|
snapshotState.expand,
|
|
snapshotState.snapshotFormat
|
|
)}`;
|
|
|
|
// Passing the actual and expected objects so that a custom reporter
|
|
// could access them, for example in order to display a custom visual diff,
|
|
// or create a different error message
|
|
return {
|
|
actual,
|
|
expected,
|
|
message,
|
|
name: matcherName,
|
|
pass: false
|
|
};
|
|
};
|
|
const toThrowErrorMatchingSnapshot = function (received, hint, fromPromise) {
|
|
const matcherName = 'toThrowErrorMatchingSnapshot';
|
|
|
|
// Future breaking change: Snapshot hint must be a string
|
|
// if (hint !== undefined && typeof hint !== string) {}
|
|
|
|
return _toThrowErrorMatchingSnapshot(
|
|
{
|
|
context: this,
|
|
hint,
|
|
isInline: false,
|
|
matcherName,
|
|
received
|
|
},
|
|
fromPromise
|
|
);
|
|
};
|
|
exports.toThrowErrorMatchingSnapshot = toThrowErrorMatchingSnapshot;
|
|
const toThrowErrorMatchingInlineSnapshot = function (
|
|
received,
|
|
inlineSnapshot,
|
|
fromPromise
|
|
) {
|
|
const matcherName = 'toThrowErrorMatchingInlineSnapshot';
|
|
if (inlineSnapshot !== undefined && typeof inlineSnapshot !== 'string') {
|
|
const options = {
|
|
expectedColor: _printSnapshot.noColor,
|
|
isNot: this.isNot,
|
|
promise: this.promise
|
|
};
|
|
throw new Error(
|
|
(0, _jestMatcherUtils.matcherErrorMessage)(
|
|
(0, _jestMatcherUtils.matcherHint)(
|
|
matcherName,
|
|
undefined,
|
|
_printSnapshot.SNAPSHOT_ARG,
|
|
options
|
|
),
|
|
'Inline snapshot must be a string',
|
|
(0, _jestMatcherUtils.printWithType)(
|
|
'Inline snapshot',
|
|
inlineSnapshot,
|
|
_utils.serialize
|
|
)
|
|
)
|
|
);
|
|
}
|
|
return _toThrowErrorMatchingSnapshot(
|
|
{
|
|
context: this,
|
|
inlineSnapshot:
|
|
inlineSnapshot !== undefined
|
|
? stripAddedIndentation(inlineSnapshot)
|
|
: undefined,
|
|
isInline: true,
|
|
matcherName,
|
|
received
|
|
},
|
|
fromPromise
|
|
);
|
|
};
|
|
exports.toThrowErrorMatchingInlineSnapshot = toThrowErrorMatchingInlineSnapshot;
|
|
const _toThrowErrorMatchingSnapshot = (config, fromPromise) => {
|
|
const {context, hint, inlineSnapshot, isInline, matcherName, received} =
|
|
config;
|
|
context.dontThrow && context.dontThrow();
|
|
const {isNot, promise} = context;
|
|
if (!fromPromise) {
|
|
if (typeof received !== 'function') {
|
|
const options = {
|
|
isNot,
|
|
promise
|
|
};
|
|
throw new Error(
|
|
(0, _jestMatcherUtils.matcherErrorMessage)(
|
|
(0, _jestMatcherUtils.matcherHint)(
|
|
matcherName,
|
|
undefined,
|
|
'',
|
|
options
|
|
),
|
|
`${(0, _jestMatcherUtils.RECEIVED_COLOR)(
|
|
'received'
|
|
)} value must be a function`,
|
|
(0, _jestMatcherUtils.printWithType)(
|
|
'Received',
|
|
received,
|
|
_printSnapshot.printReceived
|
|
)
|
|
)
|
|
);
|
|
}
|
|
}
|
|
if (isNot) {
|
|
throw new Error(
|
|
(0, _jestMatcherUtils.matcherErrorMessage)(
|
|
(0, _printSnapshot.matcherHintFromConfig)(config, false),
|
|
NOT_SNAPSHOT_MATCHERS
|
|
)
|
|
);
|
|
}
|
|
let error;
|
|
if (fromPromise) {
|
|
error = received;
|
|
} else {
|
|
try {
|
|
received();
|
|
} catch (e) {
|
|
error = e;
|
|
}
|
|
}
|
|
if (error === undefined) {
|
|
// Because the received value is a function, this is not a matcher error.
|
|
throw new Error(
|
|
`${(0, _printSnapshot.matcherHintFromConfig)(
|
|
config,
|
|
false
|
|
)}\n\n${DID_NOT_THROW}`
|
|
);
|
|
}
|
|
return _toMatchSnapshot({
|
|
context,
|
|
hint,
|
|
inlineSnapshot,
|
|
isInline,
|
|
matcherName,
|
|
received: error.message
|
|
});
|
|
};
|