303 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			303 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 'use strict';
 | |
| 
 | |
| Object.defineProperty(exports, '__esModule', {
 | |
|   value: true
 | |
| });
 | |
| exports.default = void 0;
 | |
| 
 | |
| var _fs = _interopRequireDefault(require('fs'));
 | |
| 
 | |
| var _jestMessageUtil = require('jest-message-util');
 | |
| 
 | |
| var _utils = require('./utils');
 | |
| 
 | |
| var _inline_snapshots = require('./inline_snapshots');
 | |
| 
 | |
| function _interopRequireDefault(obj) {
 | |
|   return obj && obj.__esModule ? obj : {default: obj};
 | |
| }
 | |
| 
 | |
| var Symbol = global['jest-symbol-do-not-touch'] || global.Symbol;
 | |
| var Symbol = global['jest-symbol-do-not-touch'] || global.Symbol;
 | |
| 
 | |
| var jestExistsFile =
 | |
|   global[Symbol.for('jest-native-exists-file')] || _fs.default.existsSync;
 | |
| 
 | |
| 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;
 | |
| }
 | |
| 
 | |
| class SnapshotState {
 | |
|   // @ts-ignore
 | |
|   constructor(snapshotPath, options) {
 | |
|     _defineProperty(this, '_counters', void 0);
 | |
| 
 | |
|     _defineProperty(this, '_dirty', void 0);
 | |
| 
 | |
|     _defineProperty(this, '_index', void 0);
 | |
| 
 | |
|     _defineProperty(this, '_updateSnapshot', void 0);
 | |
| 
 | |
|     _defineProperty(this, '_snapshotData', void 0);
 | |
| 
 | |
|     _defineProperty(this, '_snapshotPath', void 0);
 | |
| 
 | |
|     _defineProperty(this, '_inlineSnapshots', void 0);
 | |
| 
 | |
|     _defineProperty(this, '_uncheckedKeys', void 0);
 | |
| 
 | |
|     _defineProperty(this, '_getBabelTraverse', void 0);
 | |
| 
 | |
|     _defineProperty(this, '_getPrettier', void 0);
 | |
| 
 | |
|     _defineProperty(this, 'added', void 0);
 | |
| 
 | |
|     _defineProperty(this, 'expand', void 0);
 | |
| 
 | |
|     _defineProperty(this, 'matched', void 0);
 | |
| 
 | |
|     _defineProperty(this, 'unmatched', void 0);
 | |
| 
 | |
|     _defineProperty(this, 'updated', void 0);
 | |
| 
 | |
|     this._snapshotPath = snapshotPath;
 | |
| 
 | |
|     const _getSnapshotData = (0, _utils.getSnapshotData)(
 | |
|         this._snapshotPath,
 | |
|         options.updateSnapshot
 | |
|       ),
 | |
|       data = _getSnapshotData.data,
 | |
|       dirty = _getSnapshotData.dirty;
 | |
| 
 | |
|     this._snapshotData = data;
 | |
|     this._dirty = dirty;
 | |
|     this._getBabelTraverse = options.getBabelTraverse;
 | |
|     this._getPrettier = options.getPrettier;
 | |
|     this._inlineSnapshots = [];
 | |
|     this._uncheckedKeys = new Set(Object.keys(this._snapshotData));
 | |
|     this._counters = new Map();
 | |
|     this._index = 0;
 | |
|     this.expand = options.expand || false;
 | |
|     this.added = 0;
 | |
|     this.matched = 0;
 | |
|     this.unmatched = 0;
 | |
|     this._updateSnapshot = options.updateSnapshot;
 | |
|     this.updated = 0;
 | |
|   }
 | |
| 
 | |
|   markSnapshotsAsCheckedForTest(testName) {
 | |
|     this._uncheckedKeys.forEach(uncheckedKey => {
 | |
|       if ((0, _utils.keyToTestName)(uncheckedKey) === testName) {
 | |
|         this._uncheckedKeys.delete(uncheckedKey);
 | |
|       }
 | |
|     });
 | |
|   }
 | |
| 
 | |
|   _addSnapshot(key, receivedSerialized, options) {
 | |
|     this._dirty = true;
 | |
| 
 | |
|     if (options.isInline) {
 | |
|       const error = options.error || new Error();
 | |
|       const lines = (0, _jestMessageUtil.getStackTraceLines)(error.stack || '');
 | |
|       const frame = (0, _jestMessageUtil.getTopFrame)(lines);
 | |
| 
 | |
|       if (!frame) {
 | |
|         throw new Error(
 | |
|           "Jest: Couldn't infer stack frame for inline snapshot."
 | |
|         );
 | |
|       }
 | |
| 
 | |
|       this._inlineSnapshots.push({
 | |
|         frame,
 | |
|         snapshot: receivedSerialized
 | |
|       });
 | |
|     } else {
 | |
|       this._snapshotData[key] = receivedSerialized;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   save() {
 | |
|     const hasExternalSnapshots = Object.keys(this._snapshotData).length;
 | |
|     const hasInlineSnapshots = this._inlineSnapshots.length;
 | |
|     const isEmpty = !hasExternalSnapshots && !hasInlineSnapshots;
 | |
|     const status = {
 | |
|       deleted: false,
 | |
|       saved: false
 | |
|     };
 | |
| 
 | |
|     if ((this._dirty || this._uncheckedKeys.size) && !isEmpty) {
 | |
|       if (hasExternalSnapshots) {
 | |
|         (0, _utils.saveSnapshotFile)(this._snapshotData, this._snapshotPath);
 | |
|       }
 | |
| 
 | |
|       if (hasInlineSnapshots) {
 | |
|         const prettier = this._getPrettier(); // Load lazily
 | |
| 
 | |
|         const babelTraverse = this._getBabelTraverse(); // Load lazily
 | |
| 
 | |
|         (0, _inline_snapshots.saveInlineSnapshots)(
 | |
|           this._inlineSnapshots,
 | |
|           prettier,
 | |
|           babelTraverse
 | |
|         );
 | |
|       }
 | |
| 
 | |
|       status.saved = true;
 | |
|     } else if (!hasExternalSnapshots && jestExistsFile(this._snapshotPath)) {
 | |
|       if (this._updateSnapshot === 'all') {
 | |
|         _fs.default.unlinkSync(this._snapshotPath);
 | |
|       }
 | |
| 
 | |
|       status.deleted = true;
 | |
|     }
 | |
| 
 | |
|     return status;
 | |
|   }
 | |
| 
 | |
|   getUncheckedCount() {
 | |
|     return this._uncheckedKeys.size || 0;
 | |
|   }
 | |
| 
 | |
|   getUncheckedKeys() {
 | |
|     return Array.from(this._uncheckedKeys);
 | |
|   }
 | |
| 
 | |
|   removeUncheckedKeys() {
 | |
|     if (this._updateSnapshot === 'all' && this._uncheckedKeys.size) {
 | |
|       this._dirty = true;
 | |
| 
 | |
|       this._uncheckedKeys.forEach(key => delete this._snapshotData[key]);
 | |
| 
 | |
|       this._uncheckedKeys.clear();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   match({testName, received, key, inlineSnapshot, error}) {
 | |
|     this._counters.set(testName, (this._counters.get(testName) || 0) + 1);
 | |
| 
 | |
|     const count = Number(this._counters.get(testName));
 | |
|     const isInline = inlineSnapshot !== undefined;
 | |
| 
 | |
|     if (!key) {
 | |
|       key = (0, _utils.testNameToKey)(testName, count);
 | |
|     } // Do not mark the snapshot as "checked" if the snapshot is inline and
 | |
|     // there's an external snapshot. This way the external snapshot can be
 | |
|     // removed with `--updateSnapshot`.
 | |
| 
 | |
|     if (!(isInline && this._snapshotData[key])) {
 | |
|       this._uncheckedKeys.delete(key);
 | |
|     }
 | |
| 
 | |
|     const receivedSerialized = (0, _utils.serialize)(received);
 | |
|     const expected = isInline ? inlineSnapshot : this._snapshotData[key];
 | |
|     const pass = expected === receivedSerialized;
 | |
|     const hasSnapshot = isInline
 | |
|       ? inlineSnapshot !== ''
 | |
|       : this._snapshotData[key] !== undefined;
 | |
| 
 | |
|     const snapshotIsPersisted =
 | |
|       isInline || _fs.default.existsSync(this._snapshotPath);
 | |
| 
 | |
|     if (pass && !isInline) {
 | |
|       // Executing a snapshot file as JavaScript and writing the strings back
 | |
|       // when other snapshots have changed loses the proper escaping for some
 | |
|       // characters. Since we check every snapshot in every test, use the newly
 | |
|       // generated formatted string.
 | |
|       // Note that this is only relevant when a snapshot is added and the dirty
 | |
|       // flag is set.
 | |
|       this._snapshotData[key] = receivedSerialized;
 | |
|     } // These are the conditions on when to write snapshots:
 | |
|     //  * There's no snapshot file in a non-CI environment.
 | |
|     //  * There is a snapshot file and we decided to update the snapshot.
 | |
|     //  * There is a snapshot file, but it doesn't have this snaphsot.
 | |
|     // These are the conditions on when not to write snapshots:
 | |
|     //  * The update flag is set to 'none'.
 | |
|     //  * There's no snapshot file or a file without this snapshot on a CI environment.
 | |
| 
 | |
|     if (
 | |
|       (hasSnapshot && this._updateSnapshot === 'all') ||
 | |
|       ((!hasSnapshot || !snapshotIsPersisted) &&
 | |
|         (this._updateSnapshot === 'new' || this._updateSnapshot === 'all'))
 | |
|     ) {
 | |
|       if (this._updateSnapshot === 'all') {
 | |
|         if (!pass) {
 | |
|           if (hasSnapshot) {
 | |
|             this.updated++;
 | |
|           } else {
 | |
|             this.added++;
 | |
|           }
 | |
| 
 | |
|           this._addSnapshot(key, receivedSerialized, {
 | |
|             error,
 | |
|             isInline
 | |
|           });
 | |
|         } else {
 | |
|           this.matched++;
 | |
|         }
 | |
|       } else {
 | |
|         this._addSnapshot(key, receivedSerialized, {
 | |
|           error,
 | |
|           isInline
 | |
|         });
 | |
| 
 | |
|         this.added++;
 | |
|       }
 | |
| 
 | |
|       return {
 | |
|         actual: '',
 | |
|         count,
 | |
|         expected: '',
 | |
|         key,
 | |
|         pass: true
 | |
|       };
 | |
|     } else {
 | |
|       if (!pass) {
 | |
|         this.unmatched++;
 | |
|         return {
 | |
|           actual: (0, _utils.unescape)(receivedSerialized),
 | |
|           count,
 | |
|           expected: expected ? (0, _utils.unescape)(expected) : null,
 | |
|           key,
 | |
|           pass: false
 | |
|         };
 | |
|       } else {
 | |
|         this.matched++;
 | |
|         return {
 | |
|           actual: '',
 | |
|           count,
 | |
|           expected: '',
 | |
|           key,
 | |
|           pass: true
 | |
|         };
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   fail(testName, _received, key) {
 | |
|     this._counters.set(testName, (this._counters.get(testName) || 0) + 1);
 | |
| 
 | |
|     const count = Number(this._counters.get(testName));
 | |
| 
 | |
|     if (!key) {
 | |
|       key = (0, _utils.testNameToKey)(testName, count);
 | |
|     }
 | |
| 
 | |
|     this._uncheckedKeys.delete(key);
 | |
| 
 | |
|     this.unmatched++;
 | |
|     return key;
 | |
|   }
 | |
| }
 | |
| 
 | |
| exports.default = SnapshotState;
 |