aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/scripts/controllers/transactions/lib/tx-state-history-helper.js21
-rw-r--r--app/scripts/controllers/transactions/tx-state-manager.js23
-rw-r--r--test/unit/tx-state-history-helper-test.js139
-rw-r--r--test/unit/tx-state-history-helper.js46
-rw-r--r--test/unit/tx-state-manager-test.js9
5 files changed, 157 insertions, 81 deletions
diff --git a/app/scripts/controllers/transactions/lib/tx-state-history-helper.js b/app/scripts/controllers/transactions/lib/tx-state-history-helper.js
index 59a4b562c..bb51c9871 100644
--- a/app/scripts/controllers/transactions/lib/tx-state-history-helper.js
+++ b/app/scripts/controllers/transactions/lib/tx-state-history-helper.js
@@ -25,26 +25,31 @@ function migrateFromSnapshotsToDiffs (longHistory) {
}
/**
- generates an array of history objects sense the previous state.
- The object has the keys opp(the operation preformed),
- path(the key and if a nested object then each key will be seperated with a `/`)
- value
- with the first entry having the note
+ Generates an array of history objects sense the previous state.
+ The object has the keys
+ op (the operation performed),
+ path (the key and if a nested object then each key will be seperated with a `/`)
+ value
+ with the first entry having the note and a timestamp when the change took place
@param previousState {object} - the previous state of the object
@param newState {object} - the update object
@param note {string} - a optional note for the state change
- @reurns {array}
+ @returns {array}
*/
function generateHistoryEntry (previousState, newState, note) {
const entry = jsonDiffer.compare(previousState, newState)
// Add a note to the first op, since it breaks if we append it to the entry
- if (note && entry[0]) entry[0].note = note
+ if (entry[0]) {
+ if (note) entry[0].note = note
+
+ entry[0].timestamp = (new Date()).getTime()
+ }
return entry
}
/**
Recovers previous txMeta state obj
- @return {object}
+ @returns {object}
*/
function replayHistory (_shortHistory) {
const shortHistory = clone(_shortHistory)
diff --git a/app/scripts/controllers/transactions/tx-state-manager.js b/app/scripts/controllers/transactions/tx-state-manager.js
index 380214c1d..0aae4774b 100644
--- a/app/scripts/controllers/transactions/tx-state-manager.js
+++ b/app/scripts/controllers/transactions/tx-state-manager.js
@@ -2,6 +2,7 @@ const extend = require('xtend')
const EventEmitter = require('events')
const ObservableStore = require('obs-store')
const ethUtil = require('ethereumjs-util')
+const log = require('loglevel')
const txStateHistoryHelper = require('./lib/tx-state-history-helper')
const createId = require('../../lib/random-id')
const { getFinalStates } = require('./lib/util')
@@ -158,7 +159,7 @@ class TransactionStateManager extends EventEmitter {
/**
updates the txMeta in the list and adds a history entry
@param txMeta {Object} - the txMeta to update
- @param [note] {string} - a not about the update for history
+ @param [note] {string} - a note about the update for history
*/
updateTx (txMeta, note) {
// validate txParams
@@ -398,13 +399,19 @@ class TransactionStateManager extends EventEmitter {
_setTxStatus (txId, status) {
const txMeta = this.getTx(txId)
txMeta.status = status
- this.emit(`${txMeta.id}:${status}`, txId)
- this.emit(`tx:status-update`, txId, status)
- if (['submitted', 'rejected', 'failed'].includes(status)) {
- this.emit(`${txMeta.id}:finished`, txMeta)
- }
- this.updateTx(txMeta, `txStateManager: setting status to ${status}`)
- this.emit('update:badge')
+ setTimeout(() => {
+ try {
+ this.updateTx(txMeta, `txStateManager: setting status to ${status}`)
+ this.emit(`${txMeta.id}:${status}`, txId)
+ this.emit(`tx:status-update`, txId, status)
+ if (['submitted', 'rejected', 'failed'].includes(status)) {
+ this.emit(`${txMeta.id}:finished`, txMeta)
+ }
+ this.emit('update:badge')
+ } catch (error) {
+ log.error(error)
+ }
+ })
}
/**
diff --git a/test/unit/tx-state-history-helper-test.js b/test/unit/tx-state-history-helper-test.js
index 35e9ef188..5ad014dbb 100644
--- a/test/unit/tx-state-history-helper-test.js
+++ b/test/unit/tx-state-history-helper-test.js
@@ -1,26 +1,129 @@
const assert = require('assert')
-const clone = require('clone')
const txStateHistoryHelper = require('../../app/scripts/controllers/transactions/lib/tx-state-history-helper')
+const testVault = require('../data/v17-long-history.json')
-describe('deepCloneFromTxMeta', function () {
- it('should clone deep', function () {
- const input = {
- foo: {
- bar: {
- bam: 'baz'
+describe ('Transaction state history helper', function () {
+
+ describe('#snapshotFromTxMeta', function () {
+ it('should clone deep', function () {
+ const input = {
+ foo: {
+ bar: {
+ bam: 'baz'
+ }
}
}
- }
- 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')
+ 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')
+ })
})
- 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')
+ 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 = [{
+ "op": "replace",
+ "path": "/message",
+ "value": "haay",
+ }]
+ const diff2 = [{
+ "op": "replace",
+ "path": "/value",
+ "value": 2,
+ }]
+ 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 () {
+
+ function generateHistoryEntryTest(note) {
+
+ const prevState = {
+ someValue: 'value 1',
+ foo: {
+ bar: {
+ bam: 'baz'
+ }
+ }
+ }
+
+ const nextState = {
+ newPropRoot: 'new property - root',
+ someValue: 'value 2',
+ foo: {
+ newPropFirstLevel: 'new property - first level',
+ bar: {
+ bam: 'baz'
+ }
+ }
+ }
+
+ 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)
+ if (note)
+ assert.equal(result[0].note, note)
+
+ 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')
+ })
})
-})
+}) \ No newline at end of file
diff --git a/test/unit/tx-state-history-helper.js b/test/unit/tx-state-history-helper.js
deleted file mode 100644
index 35f7dac57..000000000
--- a/test/unit/tx-state-history-helper.js
+++ /dev/null
@@ -1,46 +0,0 @@
-const assert = require('assert')
-const txStateHistoryHelper = require('../../app/scripts/controllers/transactions/lib/tx-state-history-helper')
-const testVault = require('../data/v17-long-history.json')
-
-
-describe('tx-state-history-helper', 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')
- })
- })
- })
-
- it('replaying history does not mutate the original obj', function () {
- const initialState = { test: true, message: 'hello', value: 1 }
- const diff1 = [{
- "op": "replace",
- "path": "/message",
- "value": "haay",
- }]
- const diff2 = [{
- "op": "replace",
- "path": "/value",
- "value": 2,
- }]
- 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')
- })
-
-})
diff --git a/test/unit/tx-state-manager-test.js b/test/unit/tx-state-manager-test.js
index e5fe68d0b..179542f90 100644
--- a/test/unit/tx-state-manager-test.js
+++ b/test/unit/tx-state-manager-test.js
@@ -176,14 +176,21 @@ describe('TransactionStateManager', function () {
assert.deepEqual(updatedTx.history[0], txStateHistoryHelper.snapshotFromTxMeta(updatedTx), 'first history item is initial state')
// modify value and updateTx
updatedTx.txParams.gasPrice = desiredGasPrice
+ const before = new Date().getTime()
txStateManager.updateTx(updatedTx)
+ const after = new Date().getTime()
// check updated value
const result = txStateManager.getTx('1')
assert.equal(result.txParams.gasPrice, desiredGasPrice, 'gas price updated')
// validate history was updated
assert.equal(result.history.length, 2, 'two history items (initial + diff)')
+ assert.equal(result.history[1].length, 1, 'two history state items (initial + diff)')
+
const expectedEntry = { op: 'replace', path: '/txParams/gasPrice', value: desiredGasPrice }
- assert.deepEqual(result.history[1], [expectedEntry], 'two history items (initial + diff)')
+ assert.deepEqual(result.history[1][0].op, expectedEntry.op, 'two history items (initial + diff) operation')
+ assert.deepEqual(result.history[1][0].path, expectedEntry.path, 'two history items (initial + diff) path')
+ assert.deepEqual(result.history[1][0].value, expectedEntry.value, 'two history items (initial + diff) value')
+ assert.ok(result.history[1][0].timestamp >= before && result.history[1][0].timestamp <= after)
})
})