"use strict"; const fs = require("fs"); const path = require("path"); const cbor = require("cbor"); function sanitizeTestName(name) { return name.replace(/[\/\\\s]+/g, "-"); } function serializeValue(value) { return cbor.encodeOne(value, { highWaterMark: 1e8 }); } function deserializeValue(value) { return cbor.decodeFirstSync(value); } module.exports = { setup: function (tape, snapshotsRoot) { Object.assign(tape.Test.prototype, { equalsSnapshot: function (value, id) { let testName = sanitizeTestName(this.name); let snapshotNumber = (this.__lastSnapshot ?? 0) + 1; this.__lastSnapshot = snapshotNumber; let fullTestName = (id != null) ? `${testName}-${id}` : `${testName}-snapshot-${snapshotNumber}` let snapshotPath = path.resolve(snapshotsRoot, `${fullTestName}.cbor`); let serializedValue = serializeValue(value); if (process.env.UPDATE_SNAPSHOT === "ALL" || process.env.UPDATE_SNAPSHOT === fullTestName) { fs.mkdirSync(snapshotsRoot, { recursive: true }); fs.writeFileSync(snapshotPath, serializedValue); console.warn(`[!] Snapshot for '${fullTestName}' was updated`); } else if (fs.existsSync(snapshotPath)) { // NOTE: To ensure that the replacer transforms are applied to *both* values, we *always* serialize the current value even when we're just comparing it against a known one; we then just deserialize it again below. // TODO: Investigate whether this can be optimized with a recursive object transform instead let knownValue = deserializeValue(fs.readFileSync(snapshotPath)); let deserializedValue = deserializeValue(serializedValue); this.deepEquals(deserializedValue, knownValue, `Snapshot for '${fullTestName}' does not match; re-run with UPDATE_SNAPSHOT=${fullTestName} to update the snapshot and mark the current result as valid`); } else { throw new Error(`No known snapshot for '${fullTestName}'; re-run with UPDATE_SNAPSHOT=${fullTestName} to create it automatically`); } } }); } };