279 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			279 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | '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; |