From cad8ad6403a0b6740ebd1d65fd22876ee2aeef99 Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Mon, 14 Oct 2019 14:48:31 -0400 Subject: [PATCH] feat: allow shared named snapshot close #443 --- README.md | 10 ++++++++++ __snapshots__/named-snapshots-spec.js | 2 ++ src/duplicate-key-spec.js | 2 ++ src/index.js | 17 +++++++++++++---- src/named-snapshots-spec.js | 18 ++++++++++++++++++ src/named-snapshots.js | 7 ++++++- 6 files changed, 51 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 4584a15c..401863a0 100644 --- a/README.md +++ b/README.md @@ -157,6 +157,16 @@ exports['my name'] = 42 **Note** you should make sure that the name is unique per spec file. +### Shared snapshot name + +If you **do want** to share a named snapshot value from several places or tests in the same spec file, you need to pass an option when calling `snapshot`. The the first snapshot is saved, and the next ones will just compare against the value. + +```js +snapshot('my shared snapshot', value, { allowSharedSnapshot : true }) +// some time later +snapshot('my shared snapshot', value, { allowSharedSnapshot : true }) +``` + ## Pruning If the test run is successful and executed _all_ tests (there was no `.only`) then snapshots without a test are pruned. You can skip pruning by running with environment variable diff --git a/__snapshots__/named-snapshots-spec.js b/__snapshots__/named-snapshots-spec.js index 5a17a1a3..0e97ca69 100644 --- a/__snapshots__/named-snapshots-spec.js +++ b/__snapshots__/named-snapshots-spec.js @@ -5,3 +5,5 @@ exports['my snap name'] = 41 exports['second snapshot'] = 2 exports['third snapshot'] = 3 + +exports['shared snapshot'] = 42 diff --git a/src/duplicate-key-spec.js b/src/duplicate-key-spec.js index 6725a901..906eece9 100644 --- a/src/duplicate-key-spec.js +++ b/src/duplicate-key-spec.js @@ -40,6 +40,8 @@ describe('duplicate key', () => { } ) ) + // it is fine to use the same snapshot name if passed an option + snapshot('diff values', 1, { allowSharedSnapshot: true }) }) }) }) diff --git a/src/index.js b/src/index.js index f015954a..704d165a 100644 --- a/src/index.js +++ b/src/index.js @@ -52,15 +52,18 @@ const isPruneInfo = is.schema({ specFile: is.unemptyString, key: is.unemptyString, testTitle: is.unemptyString, - titleParts: is.strings + titleParts: is.strings, + allowDuplicate: is.bool }) function addToPrune (info) { la(isPruneInfo(info), 'wrong info for pruning snapshot', info) const prevInfo = findExistingSnapshotKey(info) - if (prevInfo) { - debug('found duplicate snapshot name: %s', prevInfo.key) + if (prevInfo && !info.allowDuplicate) { + debug('add to prune: found duplicate snapshot name: %s', prevInfo.key) + debug('%o', info) + throwDuplicateSnapshotKeyError(info, prevInfo) } @@ -68,7 +71,7 @@ function addToPrune (info) { } const findExistingSnapshotKey = info => { - la(isPruneInfo(info), 'wrong snapshot info', info) + la(isPruneInfo(info), 'wrong snapshot prune info', info) return R.find(R.propEq('key', info.key))(seenSpecs) } @@ -183,6 +186,7 @@ function snapshot (value) { // eslint-disable-next-line immutable/no-let let savedTestTitle = fullTitle + let snapshotOptions = {} if (isDataDriven(arguments)) { // value is a function @@ -194,6 +198,8 @@ function snapshot (value) { } else if (isNamedSnapshotArguments(arguments)) { savedTestTitle = arguments[0] value = arguments[1] + // and there could be additional arguments for named snapshots + snapshotOptions = arguments[2] || {} debug('named snapshots "%s"', savedTestTitle) } else { debug('snapshot value %j', value) @@ -290,6 +296,7 @@ function snapshot (value) { la('key' in coreResult, 'core result should have key', coreResult) const pruneInfo = R.assoc('key', coreResult.key, snapshotInfo) + pruneInfo.allowDuplicate = Boolean(snapshotOptions.allowSharedSnapshot) debug('prune info %o', pruneInfo) addToPrune(pruneInfo) @@ -307,7 +314,9 @@ function snapshot (value) { // }) // // check if we have a collision + // the code is duplicate from above to get just the key collision error const info = R.assoc('key', e.key, snapshotInfo) + info.allowDuplicate = Boolean(snapshotOptions.allowSharedSnapshot) debug('current snapshot info %o', info) const prevInfo = findExistingSnapshotKey(info) diff --git a/src/named-snapshots-spec.js b/src/named-snapshots-spec.js index 3b7aa724..fff91244 100644 --- a/src/named-snapshots-spec.js +++ b/src/named-snapshots-spec.js @@ -18,4 +18,22 @@ describe('named snapshots', () => { la(e.message.includes(mySnapshotName), e.message) } }) + + context('allows several tests to use same name', () => { + const snapshotName = 'shared snapshot' + + // as long as the value is the same, these two tests + // should be allowed to use same snapshot name + const snapshotOptions = { + allowSharedSnapshot: true + } + + it('test a', () => { + snapshot(snapshotName, 42, snapshotOptions) + }) + + it('test b', () => { + snapshot(snapshotName, 42, snapshotOptions) + }) + }) }) diff --git a/src/named-snapshots.js b/src/named-snapshots.js index 4f3670bc..958a068e 100644 --- a/src/named-snapshots.js +++ b/src/named-snapshots.js @@ -1,7 +1,12 @@ const is = require('check-more-types') +/** + * If we called snapshot like `snapshot('name', value)` + * or like `snapshot('name', value, options)` then this is + * a named snapshot. + */ function isNamedSnapshotArguments (args) { - return args.length === 2 && is.string(args[0]) + return (args.length === 2 || args.length === 3) && is.string(args[0]) } // eslint-disable-next-line immutable/no-mutation