'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); exports.deepMerge = exports.saveSnapshotFile = exports.ensureDirectoryExists = exports.escapeBacktickString = exports.unescape = exports.serialize = exports.getSnapshotData = exports.keyToTestName = exports.testNameToKey = exports.SNAPSHOT_VERSION_WARNING = exports.SNAPSHOT_GUIDE_LINK = exports.SNAPSHOT_VERSION = void 0; var _fs = _interopRequireDefault(require('fs')); var _path = _interopRequireDefault(require('path')); var _mkdirp = _interopRequireDefault(require('mkdirp')); var _naturalCompare = _interopRequireDefault(require('natural-compare')); var _chalk = _interopRequireDefault(require('chalk')); var _prettyFormat = _interopRequireDefault(require('pretty-format')); var _plugins = require('./plugins'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : {default: obj}; } var Symbol = global['jest-symbol-do-not-touch'] || global.Symbol; function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat( Object.getOwnPropertySymbols(source).filter(function(sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; }) ); } ownKeys.forEach(function(key) { _defineProperty(target, key, source[key]); }); } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } var Symbol = global['jest-symbol-do-not-touch'] || global.Symbol; var jestWriteFile = global[Symbol.for('jest-native-write-file')] || _fs.default.writeFileSync; var Symbol = global['jest-symbol-do-not-touch'] || global.Symbol; var jestReadFile = global[Symbol.for('jest-native-read-file')] || _fs.default.readFileSync; var Symbol = global['jest-symbol-do-not-touch'] || global.Symbol; var jestExistsFile = global[Symbol.for('jest-native-exists-file')] || _fs.default.existsSync; const SNAPSHOT_VERSION = '1'; exports.SNAPSHOT_VERSION = SNAPSHOT_VERSION; const SNAPSHOT_VERSION_REGEXP = /^\/\/ Jest Snapshot v(.+),/; const SNAPSHOT_GUIDE_LINK = 'https://goo.gl/fbAQLP'; exports.SNAPSHOT_GUIDE_LINK = SNAPSHOT_GUIDE_LINK; const SNAPSHOT_VERSION_WARNING = _chalk.default.yellow( `${_chalk.default.bold('Warning')}: Before you upgrade snapshots, ` + `we recommend that you revert any local changes to tests or other code, ` + `to ensure that you do not store invalid state.` ); exports.SNAPSHOT_VERSION_WARNING = SNAPSHOT_VERSION_WARNING; const writeSnapshotVersion = () => `// Jest Snapshot v${SNAPSHOT_VERSION}, ${SNAPSHOT_GUIDE_LINK}`; const validateSnapshotVersion = snapshotContents => { const versionTest = SNAPSHOT_VERSION_REGEXP.exec(snapshotContents); const version = versionTest && versionTest[1]; if (!version) { return new Error( _chalk.default.red( `${_chalk.default.bold( 'Outdated snapshot' )}: No snapshot header found. ` + `Jest 19 introduced versioned snapshots to ensure all developers ` + `on a project are using the same version of Jest. ` + `Please update all snapshots during this upgrade of Jest.\n\n` ) + SNAPSHOT_VERSION_WARNING ); } if (version < SNAPSHOT_VERSION) { return new Error( _chalk.default.red( `${_chalk.default.red.bold( 'Outdated snapshot' )}: The version of the snapshot ` + `file associated with this test is outdated. The snapshot file ` + `version ensures that all developers on a project are using ` + `the same version of Jest. ` + `Please update all snapshots during this upgrade of Jest.\n\n` ) + `Expected: v${SNAPSHOT_VERSION}\n` + `Received: v${version}\n\n` + SNAPSHOT_VERSION_WARNING ); } if (version > SNAPSHOT_VERSION) { return new Error( _chalk.default.red( `${_chalk.default.red.bold( 'Outdated Jest version' )}: The version of this ` + `snapshot file indicates that this project is meant to be used ` + `with a newer version of Jest. The snapshot file version ensures ` + `that all developers on a project are using the same version of ` + `Jest. Please update your version of Jest and re-run the tests.\n\n` ) + `Expected: v${SNAPSHOT_VERSION}\n` + `Received: v${version}` ); } return null; }; function isObject(item) { return item && typeof item === 'object' && !Array.isArray(item); } const testNameToKey = (testName, count) => testName + ' ' + count; exports.testNameToKey = testNameToKey; const keyToTestName = key => { if (!/ \d+$/.test(key)) { throw new Error('Snapshot keys must end with a number.'); } return key.replace(/ \d+$/, ''); }; exports.keyToTestName = keyToTestName; const getSnapshotData = (snapshotPath, update) => { const data = Object.create(null); let snapshotContents = ''; let dirty = false; if (jestExistsFile(snapshotPath)) { try { snapshotContents = jestReadFile(snapshotPath, 'utf8'); // eslint-disable-next-line no-new-func const populate = new Function('exports', snapshotContents); populate(data); } catch (e) {} } const validationResult = validateSnapshotVersion(snapshotContents); const isInvalid = snapshotContents && validationResult; if (update === 'none' && isInvalid) { throw validationResult; } if ((update === 'all' || update === 'new') && isInvalid) { dirty = true; } return { data, dirty }; }; // Extra line breaks at the beginning and at the end of the snapshot are useful // to make the content of the snapshot easier to read exports.getSnapshotData = getSnapshotData; const addExtraLineBreaks = string => string.includes('\n') ? `\n${string}\n` : string; const serialize = data => addExtraLineBreaks( normalizeNewlines( (0, _prettyFormat.default)(data, { escapeRegex: true, plugins: (0, _plugins.getSerializers)(), printFunctionName: false }) ) ); // unescape double quotes exports.serialize = serialize; const unescape = data => data.replace(/\\(")/g, '$1'); exports.unescape = unescape; const escapeBacktickString = str => str.replace(/`|\\|\${/g, '\\$&'); exports.escapeBacktickString = escapeBacktickString; const printBacktickString = str => '`' + escapeBacktickString(str) + '`'; const ensureDirectoryExists = filePath => { try { _mkdirp.default.sync( _path.default.join(_path.default.dirname(filePath)), '777' ); } catch (e) {} }; exports.ensureDirectoryExists = ensureDirectoryExists; const normalizeNewlines = string => string.replace(/\r\n|\r/g, '\n'); const saveSnapshotFile = (snapshotData, snapshotPath) => { const snapshots = Object.keys(snapshotData) .sort(_naturalCompare.default) .map( key => 'exports[' + printBacktickString(key) + '] = ' + printBacktickString(normalizeNewlines(snapshotData[key])) + ';' ); ensureDirectoryExists(snapshotPath); jestWriteFile( snapshotPath, writeSnapshotVersion() + '\n\n' + snapshots.join('\n\n') + '\n' ); }; exports.saveSnapshotFile = saveSnapshotFile; const deepMerge = (target, source) => { const mergedOutput = _objectSpread({}, target); if (isObject(target) && isObject(source)) { Object.keys(source).forEach(key => { if (isObject(source[key]) && !source[key].$$typeof) { if (!(key in target)) Object.assign(mergedOutput, { [key]: source[key] }); else mergedOutput[key] = deepMerge(target[key], source[key]); } else { Object.assign(mergedOutput, { [key]: source[key] }); } }); } return mergedOutput; }; exports.deepMerge = deepMerge;