UNPKG

@smpx/snap-shot-it

Version:

Smarter snapshot utility for Mocha and BDD test runners

207 lines (179 loc) 5.58 kB
'use strict' const debug = require('debug')('snap-shot-it') const { core, restore, prune } = require('@smpx/snap-shot-core') const compare = require('snap-shot-compare') const { isDataDriven, dataDriven } = require('@bahmutov/data-driven') const { isNamedSnapshotArguments } = require('./named-snapshots') const { isChunkedSnapshotArguments } = require('./chunked-snapshots') const R = require('ramda') const { hasOnly, hasFailed } = require('has-only') const pluralize = require('pluralize') const path = require('path') // eslint-disable-next-line immutable/no-let let packageFile try { packageFile = require(path.join(process.cwd(), 'package.json')) } catch (err) { packageFile = {} } const config = packageFile['snap-shot-it'] || {} debug('loading snap-shot-it') const EXTENSION = config.extension || '.js' // all tests we have seen so we can prune later const seenSpecs = [] function _pruneSnapshots () { debug('pruning snapshots') debug('seen %s', pluralize('spec', seenSpecs.length, true)) debug(seenSpecs) const opts = { useRelativePath: Boolean(config.useRelativePath), sortSnapshots: !process.env.SNAPSHOT_SKIP_SORTING } prune({ tests: seenSpecs, ext: EXTENSION }, opts) // eslint-disable-next-line immutable/no-mutation seenSpecs.length = 0 } // eslint-disable-next-line immutable/no-let let pruneSnapshots function addToPrune (info) { // do not add if previous info is the same if (R.equals(R.last(seenSpecs), info)) { return } seenSpecs.push(info) } // eslint-disable-next-line immutable/no-let let currentTest function setTest (t) { if (!t) { throw new Error('Expected test object') } currentTest = t } const getTestTitle = test => test.fullTitle().trim() const getTestInfo = test => { return { file: test.file, specName: getTestTitle(test) } } function clearCurrentTest () { if (currentTest) { const fullTitle = getTestTitle(currentTest) debug('clearing current test "%s"', fullTitle) restore(getTestInfo(currentTest)) currentTest = null } } global.beforeEach(function () { /* eslint-disable immutable/no-this */ if (hasOnly(this)) { debug('skip pruning snapshots because found .only') pruneSnapshots = function noop () {} } else { debug('will prune snapshots because no .only') pruneSnapshots = _pruneSnapshots } /* eslint-enable immutable/no-this */ }) global.beforeEach(function () { /* eslint-disable immutable/no-this */ if (this.currentTest) { setTest(this.currentTest) } /* eslint-enable immutable/no-this */ }) global.afterEach(clearCurrentTest) function snapshot (value) { if (!currentTest) { throw new Error('Missing current test, cannot make snapshot') } const fullTitle = getTestTitle(currentTest) debug('snapshot in test "%s"', fullTitle) debug('from file "%s"', currentTest.file) // eslint-disable-next-line immutable/no-let let file = currentTest.file // eslint-disable-next-line immutable/no-let let savedTestTitle = fullTitle if (isDataDriven(arguments)) { // value is a function debug('data-driven test for %s', value.name) value = dataDriven(value, Array.from(arguments).slice(1)) savedTestTitle += ' ' + value.name debug('extended save name to include function name') debug('snapshot name "%s"', savedTestTitle) addToPrune(getTestInfo(currentTest)) } else if (isNamedSnapshotArguments(arguments)) { savedTestTitle = arguments[0] value = arguments[1] debug('named snapshots "%s"', savedTestTitle) addToPrune({ file, specName: savedTestTitle }) } else if (isChunkedSnapshotArguments(arguments)) { if (arguments[0].title) savedTestTitle = arguments[0].title const chunk = arguments[0].chunk if (chunk) { const parsedPath = path.parse(currentTest.file) file = `${path.join( parsedPath.dir, parsedPath.name + '.' + chunk + parsedPath.ext )}` savedTestTitle += ` [${chunk}]` } value = arguments[1] addToPrune({ file, specName: savedTestTitle }) } else { debug('snapshot value %j', value) addToPrune(getTestInfo(currentTest)) } // grab options from environment variables const opts = { show: Boolean(process.env.SNAPSHOT_SHOW), dryRun: Boolean(process.env.SNAPSHOT_DRY), update: Boolean(process.env.SNAPSHOT_UPDATE), ci: Boolean(process.env.CI), resultsDir: String(config.resultsDir), useRelativePath: Boolean(config.useRelativePath), sortSnapshots: !process.env.SNAPSHOT_SKIP_SORTING } const snap = { what: value, file, ext: EXTENSION, compare, opts } if (isNamedSnapshotArguments(arguments)) { // eslint-disable-next-line immutable/no-mutation snap.exactSpecName = savedTestTitle } else { // eslint-disable-next-line immutable/no-mutation snap.specName = savedTestTitle } return core(snap) } /* eslint-disable immutable/no-mutation */ module.exports = snapshot /* eslint-enable immutable/no-mutation */ global.after(function () { /* eslint-disable immutable/no-this */ if (!hasFailed(this)) { debug('the test run was a success') pruneSnapshots.call(this) } else { debug('not attempting to prune snapshots because the test run has failed') } /* eslint-enable immutable/no-this */ }) function deleteFromCache () { // to work with transpiled code, need to force // re-evaluating this module again on watch debug('deleting snap-shot-it from cache') delete require.cache[__filename] } global.after(deleteFromCache)