snapshot/src/index.js

174 lines
4.5 KiB
JavaScript
Raw Normal View History

2017-12-10 03:08:35 +00:00
'use strict'
2017-12-10 03:22:23 +00:00
/* global cy, Cypress */
const itsName = require('its-name')
const { initStore } = require('snap-shot-store')
const la = require('lazy-ass')
const is = require('check-more-types')
const compare = require('snap-shot-compare')
2017-12-10 18:28:34 +00:00
const {
serializeDomElement,
2017-12-10 18:28:34 +00:00
serializeReactToHTML,
identity,
countSnapshots
} = require('./utils')
2017-12-10 03:22:23 +00:00
/* eslint-disable no-console */
2017-12-10 03:08:35 +00:00
function compareValues ({ expected, value }) {
const noColor = true
const json = true
return compare({ expected, value, noColor, json })
}
2017-12-10 03:22:23 +00:00
function registerCypressSnapshot () {
la(is.fn(global.before), 'missing global before function')
la(is.fn(global.after), 'missing global after function')
la(is.object(global.Cypress), 'missing Cypress object')
2017-12-10 04:02:38 +00:00
console.log('registering @cypress/snapshot')
2017-12-10 03:22:23 +00:00
let storeSnapshot
// for each full test name, keeps number of snapshots
// allows using multiple snapshots inside single test
// without confusing them
// eslint-disable-next-line immutable/no-let
let counters = {}
function getSnapshotIndex (key) {
if (key in counters) {
// eslint-disable-next-line immutable/no-mutation
counters[key] += 1
} else {
// eslint-disable-next-line immutable/no-mutation
counters[key] = 1
}
return counters[key]
}
const SNAPSHOT_FILENAME = 'snapshots.js'
function evaluateLoadedSnapShots (js) {
la(is.string(js), 'expected JavaScript snapshot source', js)
console.log('read snapshots.js file')
const store = eval(js) || {}
console.log('have %d snapshot(s)', countSnapshots(store))
2017-12-10 03:22:23 +00:00
storeSnapshot = initStore(store)
}
global.before(function loadSnapshots () {
2017-12-10 04:07:08 +00:00
cy
.readFile(SNAPSHOT_FILENAME, 'utf-8', { log: false })
.then(evaluateLoadedSnapShots)
2017-12-10 03:22:23 +00:00
// no way to catch an error yet
})
function getTestName (test) {
const names = itsName(test)
// la(is.strings(names), 'could not get name from current test', test)
return names
}
function getSnapshotName (test, humanName) {
const names = getTestName(test)
const key = names.join(' - ')
const index = humanName || getSnapshotIndex(key)
names.push(String(index))
return names
}
function setSnapshot (name, value, $el) {
// snapshots were not initialized
if (!storeSnapshot) {
return
}
// show just the last part of the name list (the index)
const message = Cypress._.last(name)
console.log('current snapshot name', name)
const devToolsLog = {
value
}
if (Cypress.dom.isJquery($el)) {
// only add DOM elements, otherwise "expected" value is enough
devToolsLog.$el = $el
}
2017-12-10 03:22:23 +00:00
const options = {
name: 'snapshot',
message,
consoleProps: () => devToolsLog
2017-12-10 03:22:23 +00:00
}
if ($el) {
options.$el = $el
}
const cyRaiser = ({ value, expected }) => {
const result = compareValues({ expected, value })
result.orElse((json) => {
// by deleting property and adding it at the last position
// we reorder how the object is displayed
// We want convenient:
// - message
// - expected
// - value
devToolsLog.message = json.message
devToolsLog.expected = expected
delete devToolsLog.value
devToolsLog.value = value
throw new Error(`Snapshot difference. To update, delete snapshot and rerun test.\n${json.message}`)
})
}
2017-12-10 03:22:23 +00:00
Cypress.log(options)
storeSnapshot({
value,
name,
raiser: cyRaiser
2017-12-10 03:22:23 +00:00
})
}
const pickSerializer = (asJson, value) => {
if (Cypress.dom.isJquery(value)) {
return asJson ? serializeDomElement : serializeReactToHTML
}
return identity
}
2017-12-10 03:22:23 +00:00
function snapshot (value, { name, json } = {}) {
console.log('human name', name)
const snapshotName = getSnapshotName(this.test, name)
const serializer = pickSerializer(json, value)
const serialized = serializer(value)
setSnapshot(snapshotName, serialized, value)
2017-12-10 03:22:23 +00:00
// always just pass value
return value
}
Cypress.Commands.add('snapshot', { prevSubject: true }, snapshot)
global.after(function saveSnapshots () {
2017-12-10 03:22:23 +00:00
if (storeSnapshot) {
const snapshots = storeSnapshot()
console.log('%d snapshot(s) on finish', countSnapshots(snapshots))
2017-12-10 03:22:23 +00:00
console.log(snapshots)
snapshots.__version = Cypress.version
const s = JSON.stringify(snapshots, null, 2)
const str = `module.exports = ${s}\n`
2017-12-10 04:07:08 +00:00
cy.writeFile(SNAPSHOT_FILENAME, str, 'utf-8', { log: false })
2017-12-10 03:22:23 +00:00
}
})
return snapshot
2017-12-10 03:22:23 +00:00
}
module.exports = {
register: registerCypressSnapshot
}