2017-08-28 20:40:28 +02:00
|
|
|
const assert = require('assert')
|
2018-05-21 14:59:26 +02:00
|
|
|
const txStateHistoryHelper = require('../../../../../app/scripts/controllers/transactions/lib/tx-state-history-helper')
|
|
|
|
const testVault = require('../../../../data/v17-long-history.json')
|
2017-08-28 20:40:28 +02:00
|
|
|
|
2018-07-03 00:49:33 +02:00
|
|
|
describe('Transaction state history helper', function () {
|
2018-05-10 13:26:02 +02:00
|
|
|
|
|
|
|
describe('#snapshotFromTxMeta', function () {
|
|
|
|
it('should clone deep', function () {
|
|
|
|
const input = {
|
|
|
|
foo: {
|
|
|
|
bar: {
|
2018-07-03 00:49:33 +02:00
|
|
|
bam: 'baz',
|
|
|
|
},
|
|
|
|
},
|
2017-08-28 20:40:28 +02:00
|
|
|
}
|
2018-05-10 13:26:02 +02:00
|
|
|
const output = txStateHistoryHelper.snapshotFromTxMeta(input)
|
|
|
|
assert('foo' in output, 'has a foo key')
|
|
|
|
assert('bar' in output.foo, 'has a bar key')
|
|
|
|
assert('bam' in output.foo.bar, 'has a bar key')
|
|
|
|
assert.equal(output.foo.bar.bam, 'baz', 'has a baz value')
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should remove the history key', function () {
|
|
|
|
const input = { foo: 'bar', history: 'remembered' }
|
|
|
|
const output = txStateHistoryHelper.snapshotFromTxMeta(input)
|
|
|
|
assert(typeof output.history, 'undefined', 'should remove history')
|
|
|
|
})
|
2017-08-28 20:40:28 +02:00
|
|
|
})
|
|
|
|
|
2018-05-10 13:26:02 +02:00
|
|
|
describe('#migrateFromSnapshotsToDiffs', function () {
|
|
|
|
it('migrates history to diffs and can recover original values', function () {
|
|
|
|
testVault.data.TransactionController.transactions.forEach((tx, index) => {
|
|
|
|
const newHistory = txStateHistoryHelper.migrateFromSnapshotsToDiffs(tx.history)
|
|
|
|
newHistory.forEach((newEntry, index) => {
|
|
|
|
if (index === 0) {
|
|
|
|
assert.equal(Array.isArray(newEntry), false, 'initial history item IS NOT a json patch obj')
|
|
|
|
} else {
|
|
|
|
assert.equal(Array.isArray(newEntry), true, 'non-initial history entry IS a json patch obj')
|
|
|
|
}
|
|
|
|
const oldEntry = tx.history[index]
|
|
|
|
const historySubset = newHistory.slice(0, index + 1)
|
|
|
|
const reconstructedValue = txStateHistoryHelper.replayHistory(historySubset)
|
|
|
|
assert.deepEqual(oldEntry, reconstructedValue, 'was able to reconstruct old entry from diffs')
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('#replayHistory', function () {
|
|
|
|
it('replaying history does not mutate the original obj', function () {
|
|
|
|
const initialState = { test: true, message: 'hello', value: 1 }
|
|
|
|
const diff1 = [{
|
2018-07-03 00:49:33 +02:00
|
|
|
'op': 'replace',
|
|
|
|
'path': '/message',
|
|
|
|
'value': 'haay',
|
2018-05-10 13:26:02 +02:00
|
|
|
}]
|
|
|
|
const diff2 = [{
|
2018-07-03 00:49:33 +02:00
|
|
|
'op': 'replace',
|
|
|
|
'path': '/value',
|
|
|
|
'value': 2,
|
2018-05-10 13:26:02 +02:00
|
|
|
}]
|
|
|
|
const history = [initialState, diff1, diff2]
|
|
|
|
|
|
|
|
const beforeStateSnapshot = JSON.stringify(initialState)
|
|
|
|
const latestState = txStateHistoryHelper.replayHistory(history)
|
|
|
|
const afterStateSnapshot = JSON.stringify(initialState)
|
|
|
|
|
|
|
|
assert.notEqual(initialState, latestState, 'initial state is not the same obj as the latest state')
|
|
|
|
assert.equal(beforeStateSnapshot, afterStateSnapshot, 'initial state is not modified during run')
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('#generateHistoryEntry', function () {
|
|
|
|
|
2018-07-03 00:49:33 +02:00
|
|
|
function generateHistoryEntryTest (note) {
|
2018-05-10 13:26:02 +02:00
|
|
|
|
|
|
|
const prevState = {
|
|
|
|
someValue: 'value 1',
|
|
|
|
foo: {
|
|
|
|
bar: {
|
2018-07-03 00:49:33 +02:00
|
|
|
bam: 'baz',
|
|
|
|
},
|
|
|
|
},
|
2018-05-10 13:26:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const nextState = {
|
|
|
|
newPropRoot: 'new property - root',
|
|
|
|
someValue: 'value 2',
|
|
|
|
foo: {
|
|
|
|
newPropFirstLevel: 'new property - first level',
|
|
|
|
bar: {
|
2018-07-03 00:49:33 +02:00
|
|
|
bam: 'baz',
|
|
|
|
},
|
|
|
|
},
|
2018-05-10 13:26:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const before = new Date().getTime()
|
|
|
|
const result = txStateHistoryHelper.generateHistoryEntry(prevState, nextState, note)
|
|
|
|
const after = new Date().getTime()
|
|
|
|
|
|
|
|
assert.ok(Array.isArray(result))
|
|
|
|
assert.equal(result.length, 3)
|
|
|
|
|
|
|
|
const expectedEntry1 = { op: 'add', path: '/foo/newPropFirstLevel', value: 'new property - first level' }
|
|
|
|
assert.equal(result[0].op, expectedEntry1.op)
|
|
|
|
assert.equal(result[0].path, expectedEntry1.path)
|
|
|
|
assert.equal(result[0].value, expectedEntry1.value)
|
|
|
|
assert.equal(result[0].value, expectedEntry1.value)
|
2018-07-03 00:49:33 +02:00
|
|
|
if (note) { assert.equal(result[0].note, note) }
|
2018-05-10 13:26:02 +02:00
|
|
|
|
|
|
|
assert.ok(result[0].timestamp >= before && result[0].timestamp <= after)
|
|
|
|
|
|
|
|
const expectedEntry2 = { op: 'replace', path: '/someValue', value: 'value 2' }
|
|
|
|
assert.deepEqual(result[1], expectedEntry2)
|
|
|
|
|
|
|
|
const expectedEntry3 = { op: 'add', path: '/newPropRoot', value: 'new property - root' }
|
|
|
|
assert.deepEqual(result[2], expectedEntry3)
|
|
|
|
}
|
|
|
|
|
|
|
|
it('should generate history entries', function () {
|
|
|
|
generateHistoryEntryTest()
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should add note to first entry', function () {
|
|
|
|
generateHistoryEntryTest('custom note')
|
2018-07-03 00:49:33 +02:00
|
|
|
})
|
2017-08-28 20:40:28 +02:00
|
|
|
})
|
2018-07-03 00:49:33 +02:00
|
|
|
})
|