aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md4
-rw-r--r--README.md13
-rw-r--r--app/scripts/background.js3
-rw-r--r--app/scripts/contentscript.js3
-rw-r--r--app/scripts/lib/config-manager.js50
-rw-r--r--app/scripts/lib/idStore.js14
-rw-r--r--package.json13
-rw-r--r--test/helper.js3
-rw-r--r--test/unit/actions/config_test.js (renamed from ui/test/unit/actions/config_test.js)4
-rw-r--r--test/unit/actions/restore_vault_test.js (renamed from ui/test/unit/actions/restore_vault_test.js)4
-rw-r--r--test/unit/actions/set_selected_account_test.js (renamed from ui/test/unit/actions/set_selected_account_test.js)4
-rw-r--r--test/unit/actions/tx_test.js (renamed from ui/test/unit/actions/tx_test.js)4
-rw-r--r--test/unit/actions/view_info_test.js (renamed from ui/test/unit/actions/view_info_test.js)4
-rw-r--r--test/unit/actions/warning_test.js (renamed from ui/test/unit/actions/warning_test.js)4
-rw-r--r--test/unit/config-manager-test.js79
-rw-r--r--test/unit/migrations-test.js14
-rw-r--r--test/unit/util_test.js (renamed from ui/test/unit/util_test.js)2
-rw-r--r--ui/app/config.js3
-rw-r--r--ui/test/setup.js8
19 files changed, 178 insertions, 55 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e74a095dd..6a4e7fd3c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,10 @@
## Current Master
+- Pending transactions are now persisted to localStorage and resume even after browser is closed.
+- Completed transactions are now persisted and can be displayed via UI.
+- Fix bug on config screen where current RPC address was always displayed wrong.
+
# 1.5.1 2016-04-15
- Corrected text above account list. Selected account is visible to all sites, not just the current domain.
diff --git a/README.md b/README.md
index 1d15fa204..1c5508a49 100644
--- a/README.md
+++ b/README.md
@@ -44,18 +44,11 @@ To enjoy the live-reloading that `gulp dev` offers while working on the `web3-pr
### Running Tests
-Currently the tests are split between two suites (we recently merged the UI into the main plugin repository). There are two different test suites to be concerned with:
-
-Plugin tests, `npm test`.
-UI tests, `npm run testUi`.
-
-You can also run both of these with continuously watching processes, via `npm run watch` and `npm run watchUi`.
-
-#### UI Testing Particulars
-
Requires `mocha` installed. Run `npm install -g mocha`.
-You can either run the test suite once with `npm testUi`, or you can reload on file changes, by running `mocha watch ui/test/**/**`.
+Then just run `npm test`.
+
+You can also test with a continuously watching process, via `npm run watch`.
### Deploying the UI
diff --git a/app/scripts/background.js b/app/scripts/background.js
index db4927083..1519f63db 100644
--- a/app/scripts/background.js
+++ b/app/scripts/background.js
@@ -191,7 +191,8 @@ idStore.on('update', updateBadge)
function updateBadge(state){
var label = ''
- var count = Object.keys(state.unconfTxs).length
+ var unconfTxs = configManager.unconfirmedTxs()
+ var count = Object.keys(unconfTxs).length
if (count) {
label = String(count)
}
diff --git a/app/scripts/contentscript.js b/app/scripts/contentscript.js
index 105f24988..a256a3f5b 100644
--- a/app/scripts/contentscript.js
+++ b/app/scripts/contentscript.js
@@ -7,7 +7,8 @@ var scriptTag = document.createElement('script')
scriptTag.src = chrome.extension.getURL('scripts/inpage.js')
scriptTag.onload = function() { this.parentNode.removeChild(this) }
var container = document.head || document.documentElement
-container.appendChild(scriptTag)
+// append as first child
+container.insertBefore(scriptTag, container.children[0])
// setup communication to page and plugin
var pageStream = new LocalMessageDuplexStream({
diff --git a/app/scripts/lib/config-manager.js b/app/scripts/lib/config-manager.js
index f024729cc..356d53c22 100644
--- a/app/scripts/lib/config-manager.js
+++ b/app/scripts/lib/config-manager.js
@@ -134,6 +134,56 @@ ConfigManager.prototype.setData = function(data) {
this.migrator.saveData(data)
}
+ConfigManager.prototype.getTxList = function() {
+ var data = this.migrator.getData()
+ if ('transactions' in data) {
+ return data.transactions
+ } else {
+ return []
+ }
+}
+
+ConfigManager.prototype._saveTxList = function(txList) {
+ var data = this.migrator.getData()
+ data.transactions = txList
+ this.setData(data)
+}
+
+ConfigManager.prototype.addTx = function(tx) {
+ var transactions = this.getTxList()
+ transactions.push(tx)
+ this._saveTxList(transactions)
+}
+
+ConfigManager.prototype.getTx = function(txId) {
+ var transactions = this.getTxList()
+ var matching = transactions.filter(tx => tx.id === txId)
+ return matching.length > 0 ? matching[0] : null
+}
+
+ConfigManager.prototype.confirmTx = function(txId) {
+ this._setTxStatus(txId, 'confirmed')
+}
+
+ConfigManager.prototype.rejectTx = function(txId) {
+ this._setTxStatus(txId, 'rejected')
+}
+
+ConfigManager.prototype._setTxStatus = function(txId, status) {
+ var transactions = this.getTxList()
+ transactions.forEach((tx) => {
+ if (tx.id === txId) {
+ tx.status = status
+ }
+ })
+ this._saveTxList(transactions)
+}
+ConfigManager.prototype.unconfirmedTxs = function() {
+ var transactions = this.getTxList()
+ return transactions.filter(tx => tx.status === 'unconfirmed')
+ .reduce((result, tx) => { result[tx.id] = tx; return result }, {})
+}
+
// observable
ConfigManager.prototype.subscribe = function(fn){
diff --git a/app/scripts/lib/idStore.js b/app/scripts/lib/idStore.js
index f44300273..b451fd6d4 100644
--- a/app/scripts/lib/idStore.js
+++ b/app/scripts/lib/idStore.js
@@ -31,7 +31,6 @@ function IdentityStore(ethStore) {
this._currentState = {
selectedAddress: null,
identities: {},
- unconfTxs: {},
}
// not part of serilized metamask state - only kept in memory
this._unconfTxCbs = {}
@@ -83,6 +82,8 @@ IdentityStore.prototype.getState = function(){
isInitialized: !!configManager.getWallet() && !seedWords,
isUnlocked: this._isUnlocked(),
seedWords: seedWords,
+ unconfTxs: configManager.unconfirmedTxs(),
+ transactions: configManager.getTxList(),
}))
}
@@ -140,10 +141,11 @@ IdentityStore.prototype.addUnconfirmedTransaction = function(txParams, cb){
time: time,
status: 'unconfirmed',
}
- this._currentState.unconfTxs[txId] = txData
+ configManager.addTx(txData)
console.log('addUnconfirmedTransaction:', txData)
// keep the cb around for after approval (requires user interaction)
+ // This cb fires completion to the Dapp's write operation.
this._unconfTxCbs[txId] = cb
// signal update
@@ -154,7 +156,7 @@ IdentityStore.prototype.addUnconfirmedTransaction = function(txParams, cb){
// comes from metamask ui
IdentityStore.prototype.approveTransaction = function(txId, cb){
- var txData = this._currentState.unconfTxs[txId]
+ var txData = configManager.getTx(txId)
var txParams = txData.txParams
var approvalCb = this._unconfTxCbs[txId] || noop
@@ -162,20 +164,20 @@ IdentityStore.prototype.approveTransaction = function(txId, cb){
cb()
approvalCb(null, true)
// clean up
- delete this._currentState.unconfTxs[txId]
+ configManager.confirmTx(txId)
delete this._unconfTxCbs[txId]
this._didUpdate()
}
// comes from metamask ui
IdentityStore.prototype.cancelTransaction = function(txId){
- var txData = this._currentState.unconfTxs[txId]
+ var txData = configManager.getTx(txId)
var approvalCb = this._unconfTxCbs[txId] || noop
// reject tx
approvalCb(null, false)
// clean up
- delete this._currentState.unconfTxs[txId]
+ configManager.rejectTx(txId)
delete this._unconfTxCbs[txId]
this._didUpdate()
}
diff --git a/package.json b/package.json
index db0e2823a..b2e2b3c61 100644
--- a/package.json
+++ b/package.json
@@ -5,11 +5,8 @@
"private": true,
"scripts": {
"start": "gulp dev",
- "test": "npm run testUi",
- "testPlugin": "mocha --require test/helper.js --compilers js:babel-register --recursive",
- "watch": "mocha watch --compilers js:babel-register --recursive",
- "testUi": "mocha ui/test/**/**/*test.js",
- "watchUi": "mocha watch ui/test/**/*test.js"
+ "test": "mocha --require test/helper.js --compilers js:babel-register --recursive",
+ "watch": "mocha watch --compilers js:babel-register --recursive"
},
"browserify": {
"transform": [
@@ -35,19 +32,19 @@
"eth-store": "^1.1.0",
"ethereumjs-tx": "^1.0.0",
"ethereumjs-util": "^4.3.0",
- "faux-jax": "git+https://github.com/kumavis/faux-jax.git#c3648de04804f3895c5b4972750cae5b51ddb103",
"hat": "0.0.3",
"inject-css": "^0.1.1",
"metamask-logo": "^1.1.5",
"multiplex": "^6.7.0",
"pojo-migrator": "^2.1.0",
+ "polyfill-crypto.getrandomvalues": "^1.0.0",
"pumpify": "^1.3.4",
"react": "^0.14.3",
"react-addons-css-transition-group": "^0.14.7",
"react-dom": "^0.14.3",
"react-hyperscript": "^2.2.2",
- "readable-stream": "^2.0.5",
"react-redux": "^4.0.3",
+ "readable-stream": "^2.0.5",
"redux": "^3.0.5",
"redux-logger": "^2.3.1",
"redux-thunk": "^1.0.2",
@@ -55,7 +52,7 @@
"three.js": "^0.73.2",
"through2": "^2.0.1",
"web3": "^0.15.1",
- "web3-provider-engine": "^7.2.1",
+ "web3-provider-engine": "^7.4.0",
"xtend": "^4.0.1"
},
"devDependencies": {
diff --git a/test/helper.js b/test/helper.js
index 4c7f8b4c6..64fe5bd07 100644
--- a/test/helper.js
+++ b/test/helper.js
@@ -1,2 +1,5 @@
require('jsdom-global')()
window.localStorage = {}
+
+if (!('crypto' in window)) { window.crypto = {} }
+window.crypto.getRandomValues = require('polyfill-crypto.getrandomvalues')
diff --git a/ui/test/unit/actions/config_test.js b/test/unit/actions/config_test.js
index d38210bfc..6a0d20f31 100644
--- a/ui/test/unit/actions/config_test.js
+++ b/test/unit/actions/config_test.js
@@ -3,8 +3,8 @@ var assert = require('assert')
var freeze = require('deep-freeze-strict')
var path = require('path')
-var actions = require(path.join(__dirname, '..', '..', '..', 'app', 'actions.js'))
-var reducers = require(path.join(__dirname, '..', '..', '..', 'app', 'reducers.js'))
+var actions = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'actions.js'))
+var reducers = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'reducers.js'))
describe ('config view actions', function() {
diff --git a/ui/test/unit/actions/restore_vault_test.js b/test/unit/actions/restore_vault_test.js
index da0d71ce7..5873a0181 100644
--- a/ui/test/unit/actions/restore_vault_test.js
+++ b/test/unit/actions/restore_vault_test.js
@@ -4,8 +4,8 @@ var freeze = require('deep-freeze-strict')
var path = require('path')
var sinon = require('sinon')
-var actions = require(path.join(__dirname, '..', '..', '..', 'app', 'actions.js'))
-var reducers = require(path.join(__dirname, '..', '..', '..', 'app', 'reducers.js'))
+var actions = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'actions.js'))
+var reducers = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'reducers.js'))
describe('#recoverFromSeed(password, seed)', function() {
diff --git a/ui/test/unit/actions/set_selected_account_test.js b/test/unit/actions/set_selected_account_test.js
index 1af6c964f..0487bc5f0 100644
--- a/ui/test/unit/actions/set_selected_account_test.js
+++ b/test/unit/actions/set_selected_account_test.js
@@ -3,8 +3,8 @@ var assert = require('assert')
var freeze = require('deep-freeze-strict')
var path = require('path')
-var actions = require(path.join(__dirname, '..', '..', '..', 'app', 'actions.js'))
-var reducers = require(path.join(__dirname, '..', '..', '..', 'app', 'reducers.js'))
+var actions = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'actions.js'))
+var reducers = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'reducers.js'))
describe('SET_SELECTED_ACCOUNT', function() {
diff --git a/ui/test/unit/actions/tx_test.js b/test/unit/actions/tx_test.js
index d83ae16c0..b15bee393 100644
--- a/ui/test/unit/actions/tx_test.js
+++ b/test/unit/actions/tx_test.js
@@ -3,8 +3,8 @@ var assert = require('assert')
var freeze = require('deep-freeze-strict')
var path = require('path')
-var actions = require(path.join(__dirname, '..', '..', '..', 'app', 'actions.js'))
-var reducers = require(path.join(__dirname, '..', '..', '..', 'app', 'reducers.js'))
+var actions = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'actions.js'))
+var reducers = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'reducers.js'))
describe('tx confirmation screen', function() {
var initialState, result
diff --git a/ui/test/unit/actions/view_info_test.js b/test/unit/actions/view_info_test.js
index 888712c67..0558c6e42 100644
--- a/ui/test/unit/actions/view_info_test.js
+++ b/test/unit/actions/view_info_test.js
@@ -3,8 +3,8 @@ var assert = require('assert')
var freeze = require('deep-freeze-strict')
var path = require('path')
-var actions = require(path.join(__dirname, '..', '..', '..', 'app', 'actions.js'))
-var reducers = require(path.join(__dirname, '..', '..', '..', 'app', 'reducers.js'))
+var actions = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'actions.js'))
+var reducers = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'reducers.js'))
describe('SHOW_INFO_PAGE', function() {
diff --git a/ui/test/unit/actions/warning_test.js b/test/unit/actions/warning_test.js
index eee198656..37be9ee85 100644
--- a/ui/test/unit/actions/warning_test.js
+++ b/test/unit/actions/warning_test.js
@@ -3,8 +3,8 @@ var assert = require('assert')
var freeze = require('deep-freeze-strict')
var path = require('path')
-var actions = require(path.join(__dirname, '..', '..', '..', 'app', 'actions.js'))
-var reducers = require(path.join(__dirname, '..', '..', '..', 'app', 'reducers.js'))
+var actions = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'actions.js'))
+var reducers = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'reducers.js'))
describe('action DISPLAY_WARNING', function() {
diff --git a/test/unit/config-manager-test.js b/test/unit/config-manager-test.js
index 10b6716d6..84632b0ea 100644
--- a/test/unit/config-manager-test.js
+++ b/test/unit/config-manager-test.js
@@ -68,4 +68,83 @@ describe('config-manager', function() {
assert.equal(secondResult, secondRpc)
})
})
+
+ describe('transactions', function() {
+ beforeEach(function() {
+ configManager._saveTxList([])
+ })
+
+ describe('#getTxList', function() {
+ it('when new should return empty array', function() {
+ var result = configManager.getTxList()
+ assert.ok(Array.isArray(result))
+ assert.equal(result.length, 0)
+ })
+ })
+
+ describe('#_saveTxList', function() {
+ it('saves the submitted data to the tx list', function() {
+ var target = [{ foo: 'bar' }]
+ configManager._saveTxList(target)
+ var result = configManager.getTxList()
+ assert.equal(result[0].foo, 'bar')
+ })
+ })
+
+ describe('#addTx', function() {
+ it('adds a tx returned in getTxList', function() {
+ var tx = { id: 1 }
+ configManager.addTx(tx)
+ var result = configManager.getTxList()
+ assert.ok(Array.isArray(result))
+ assert.equal(result.length, 1)
+ assert.equal(result[0].id, 1)
+ })
+ })
+
+ describe('#confirmTx', function() {
+ it('sets the tx status to confirmed', function() {
+ var tx = { id: 1, status: 'unconfirmed' }
+ configManager.addTx(tx)
+ configManager.confirmTx(1)
+ var result = configManager.getTxList()
+ assert.ok(Array.isArray(result))
+ assert.equal(result.length, 1)
+ assert.equal(result[0].status, 'confirmed')
+ })
+ })
+
+ describe('#rejectTx', function() {
+ it('sets the tx status to rejected', function() {
+ var tx = { id: 1, status: 'unconfirmed' }
+ configManager.addTx(tx)
+ configManager.rejectTx(1)
+ var result = configManager.getTxList()
+ assert.ok(Array.isArray(result))
+ assert.equal(result.length, 1)
+ assert.equal(result[0].status, 'rejected')
+ })
+ })
+
+ describe('#unconfirmedTxs', function() {
+ it('returns unconfirmed txs in a hash', function() {
+ configManager.addTx({ id: '1', status: 'unconfirmed' })
+ configManager.addTx({ id: '2', status: 'confirmed' })
+ let result = configManager.unconfirmedTxs()
+ assert.equal(typeof result, 'object')
+ assert.equal(result['1'].status, 'unconfirmed')
+ assert.equal(result['0'], undefined)
+ assert.equal(result['2'], undefined)
+ })
+ })
+
+ describe('#getTx', function() {
+ it('returns a tx with the requested id', function() {
+ configManager.addTx({ id: '1', status: 'unconfirmed' })
+ configManager.addTx({ id: '2', status: 'confirmed' })
+ assert.equal(configManager.getTx('1').status, 'unconfirmed')
+ assert.equal(configManager.getTx('2').status, 'confirmed')
+ })
+ })
+ })
})
diff --git a/test/unit/migrations-test.js b/test/unit/migrations-test.js
index 3a3213ac5..092c0eccd 100644
--- a/test/unit/migrations-test.js
+++ b/test/unit/migrations-test.js
@@ -1,14 +1,16 @@
-var test = require('tape')
+var assert = require('assert')
var path = require('path')
var wallet1 = require(path.join('..', 'lib', 'migrations', '001.json'))
var migration2 = require(path.join('..', '..', 'app', 'scripts', 'migrations', '002'))
-test('wallet1 is migrated successfully', function(t) {
-
- var result = migration2.migrate(wallet1.data)
- t.equal(result.config.provider.type, 'rpc', 'provider should be rpc')
- t.equal(result.config.provider.rpcTarget, 'https://rpc.metamask.io/', 'provider should be our rpc')
+describe('wallet1 is migrated successfully', function() {
+ it('should convert etherscan provider', function(done) {
+ var result = migration2.migrate(wallet1.data)
+ assert.equal(result.config.provider.type, 'rpc', 'provider should be rpc')
+ assert.equal(result.config.provider.rpcTarget, 'https://rpc.metamask.io/', 'provider should be our rpc')
+ done()
+ })
})
diff --git a/ui/test/unit/util_test.js b/test/unit/util_test.js
index b35d60812..7f8103d3b 100644
--- a/ui/test/unit/util_test.js
+++ b/test/unit/util_test.js
@@ -3,7 +3,7 @@ var sinon = require('sinon')
const ethUtil = require('ethereumjs-util')
var path = require('path')
-var util = require(path.join(__dirname, '..', '..', 'app', 'util.js'))
+var util = require(path.join(__dirname, '..', '..', 'ui', 'app', 'util.js'))
describe('util', function() {
var ethInWei = '1'
diff --git a/ui/app/config.js b/ui/app/config.js
index 33d87bcc2..878c9955f 100644
--- a/ui/app/config.js
+++ b/ui/app/config.js
@@ -47,7 +47,6 @@ ConfigScreen.prototype.render = function() {
currentProviderDisplay(metamaskState),
-
h('div', [
h('input', {
placeholder: 'New RPC URL',
@@ -95,7 +94,7 @@ ConfigScreen.prototype.render = function() {
}
function currentProviderDisplay(metamaskState) {
- var rpc = metamaskState.rpcTarget
+ var rpc = metamaskState.provider.rpcTarget
return h('div', [
h('h3', {style: { fontWeight: 'bold' }}, 'Currently using RPC'),
h('p', rpc)
diff --git a/ui/test/setup.js b/ui/test/setup.js
deleted file mode 100644
index 7985e9a00..000000000
--- a/ui/test/setup.js
+++ /dev/null
@@ -1,8 +0,0 @@
-if (typeof process === 'object') {
- // Initialize node environment
- global.expect = require('chai').expect
- require('mocha-jsdom')()
-} else {
- window.expect = window.chai.expect
- window.require = function () { /* noop */ }
-}