Merge branch 'master' into AddBalanceController
This commit is contained in:
commit
c17c657693
|
@ -2,6 +2,10 @@
|
||||||
|
|
||||||
## Current Master
|
## Current Master
|
||||||
|
|
||||||
|
- Add ability to export private keys as a file.
|
||||||
|
- Add ability to export seed words as a file.
|
||||||
|
- Changed state logs to a file download than a clipboard copy.
|
||||||
|
|
||||||
## 3.10.0 2017-9-11
|
## 3.10.0 2017-9-11
|
||||||
|
|
||||||
- Readded loose keyring label back into the account list.
|
- Readded loose keyring label back into the account list.
|
||||||
|
|
11
circle.yml
11
circle.yml
|
@ -4,3 +4,14 @@ machine:
|
||||||
test:
|
test:
|
||||||
override:
|
override:
|
||||||
- "npm run ci"
|
- "npm run ci"
|
||||||
|
dependencies:
|
||||||
|
pre:
|
||||||
|
- sudo apt-get update
|
||||||
|
# get latest stable firefox
|
||||||
|
- sudo apt-get install firefox
|
||||||
|
- firefox_cmd=`which firefox`; sudo rm -f $firefox_cmd; sudo ln -s `which firefox.ubuntu` $firefox_cmd
|
||||||
|
# get latest stable chrome
|
||||||
|
- wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
|
||||||
|
- sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
|
||||||
|
- sudo apt-get update
|
||||||
|
- sudo apt-get install google-chrome-stable
|
|
@ -0,0 +1,61 @@
|
||||||
|
// Karma configuration
|
||||||
|
// Generated on Mon Sep 11 2017 18:45:48 GMT-0700 (PDT)
|
||||||
|
|
||||||
|
module.exports = function(config) {
|
||||||
|
config.set({
|
||||||
|
// base path that will be used to resolve all patterns (eg. files, exclude)
|
||||||
|
basePath: process.cwd(),
|
||||||
|
|
||||||
|
browserConsoleLogOptions: {
|
||||||
|
terminal: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
// frameworks to use
|
||||||
|
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
|
||||||
|
frameworks: ['qunit'],
|
||||||
|
|
||||||
|
// list of files / patterns to load in the browser
|
||||||
|
files: [
|
||||||
|
'development/bundle.js',
|
||||||
|
'test/integration/jquery-3.1.0.min.js',
|
||||||
|
'test/integration/bundle.js',
|
||||||
|
{ pattern: 'dist/chrome/images/**/*.*', watched: false, included: false, served: true },
|
||||||
|
{ pattern: 'dist/chrome/fonts/**/*.*', watched: false, included: false, served: true },
|
||||||
|
],
|
||||||
|
|
||||||
|
proxies: {
|
||||||
|
'/images/': '/base/dist/chrome/images/',
|
||||||
|
'/fonts/': '/base/dist/chrome/fonts/',
|
||||||
|
},
|
||||||
|
|
||||||
|
// test results reporter to use
|
||||||
|
// possible values: 'dots', 'progress'
|
||||||
|
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
|
||||||
|
reporters: ['progress'],
|
||||||
|
|
||||||
|
// web server port
|
||||||
|
port: 9876,
|
||||||
|
|
||||||
|
// enable / disable colors in the output (reporters and logs)
|
||||||
|
colors: true,
|
||||||
|
|
||||||
|
// level of logging
|
||||||
|
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
|
||||||
|
logLevel: config.LOG_INFO,
|
||||||
|
|
||||||
|
// enable / disable watching file and executing tests whenever any file changes
|
||||||
|
autoWatch: false,
|
||||||
|
|
||||||
|
// start these browsers
|
||||||
|
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
|
||||||
|
browsers: ['Chrome', 'Firefox'],
|
||||||
|
|
||||||
|
// Continuous Integration mode
|
||||||
|
// if true, Karma captures browsers, runs the tests and exits
|
||||||
|
singleRun: true,
|
||||||
|
|
||||||
|
// Concurrency level
|
||||||
|
// how many browser should be started simultaneous
|
||||||
|
concurrency: Infinity
|
||||||
|
})
|
||||||
|
}
|
63
mock-dev.js
63
mock-dev.js
|
@ -85,40 +85,47 @@ actions.update = function(stateName) {
|
||||||
var css = MetaMaskUiCss()
|
var css = MetaMaskUiCss()
|
||||||
injectCss(css)
|
injectCss(css)
|
||||||
|
|
||||||
const container = document.querySelector('#app-content')
|
|
||||||
|
|
||||||
// parse opts
|
// parse opts
|
||||||
var store = configureStore(firstState)
|
var store = configureStore(firstState)
|
||||||
|
|
||||||
// start app
|
// start app
|
||||||
render(
|
startApp()
|
||||||
h('.super-dev-container', [
|
|
||||||
|
|
||||||
h('button', {
|
function startApp(){
|
||||||
onClick: (ev) => {
|
const body = document.body
|
||||||
ev.preventDefault()
|
const container = document.createElement('div')
|
||||||
store.dispatch(actions.update('terms'))
|
container.id = 'app-content'
|
||||||
},
|
body.appendChild(container)
|
||||||
style: {
|
console.log('container', container)
|
||||||
margin: '19px 19px 0px 19px',
|
|
||||||
},
|
|
||||||
}, 'Reset State'),
|
|
||||||
|
|
||||||
h(Selector, { actions, selectedKey: selectedView, states, store }),
|
render(
|
||||||
|
h('.super-dev-container', [
|
||||||
|
|
||||||
h('.mock-app-root', {
|
h('button', {
|
||||||
style: {
|
onClick: (ev) => {
|
||||||
height: '500px',
|
ev.preventDefault()
|
||||||
width: '360px',
|
store.dispatch(actions.update('terms'))
|
||||||
boxShadow: 'grey 0px 2px 9px',
|
},
|
||||||
margin: '20px',
|
style: {
|
||||||
},
|
margin: '19px 19px 0px 19px',
|
||||||
}, [
|
},
|
||||||
h(Root, {
|
}, 'Reset State'),
|
||||||
store: store,
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
|
|
||||||
]
|
h(Selector, { actions, selectedKey: selectedView, states, store }),
|
||||||
), container)
|
|
||||||
|
|
||||||
|
h('.mock-app-root', {
|
||||||
|
style: {
|
||||||
|
height: '500px',
|
||||||
|
width: '360px',
|
||||||
|
boxShadow: 'grey 0px 2px 9px',
|
||||||
|
margin: '20px',
|
||||||
|
},
|
||||||
|
}, [
|
||||||
|
h(Root, {
|
||||||
|
store: store,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
|
||||||
|
]
|
||||||
|
), container)
|
||||||
|
}
|
||||||
|
|
12
package.json
12
package.json
|
@ -12,8 +12,8 @@
|
||||||
"test": "npm run lint && npm run test-unit && npm run test-integration",
|
"test": "npm run lint && npm run test-unit && npm run test-integration",
|
||||||
"test-unit": "METAMASK_ENV=test mocha --require test/helper.js --recursive \"test/unit/**/*.js\"",
|
"test-unit": "METAMASK_ENV=test mocha --require test/helper.js --recursive \"test/unit/**/*.js\"",
|
||||||
"single-test": "METAMASK_ENV=test mocha --require test/helper.js",
|
"single-test": "METAMASK_ENV=test mocha --require test/helper.js",
|
||||||
"test-integration": "npm run buildMock && npm run buildCiUnits && testem ci -P 2",
|
"test-integration": "npm run buildMock && npm run buildCiUnits && karma start",
|
||||||
"test-coverage": "nyc npm run test-unit && nyc report --reporter=text-lcov | coveralls",
|
"test-coverage": "nyc npm run test-unit && if [ $COVERALLS_REPO_TOKEN ]; then nyc report --reporter=text-lcov | coveralls; fi",
|
||||||
"ci": "npm run lint && npm run test-coverage && npm run test-integration",
|
"ci": "npm run lint && npm run test-coverage && npm run test-integration",
|
||||||
"lint": "gulp lint",
|
"lint": "gulp lint",
|
||||||
"buildCiUnits": "node test/integration/index.js",
|
"buildCiUnits": "node test/integration/index.js",
|
||||||
|
@ -22,7 +22,6 @@
|
||||||
"ui": "npm run genStates && beefy ui-dev.js:bundle.js --live --open --index=./development/index.html --cwd ./",
|
"ui": "npm run genStates && beefy ui-dev.js:bundle.js --live --open --index=./development/index.html --cwd ./",
|
||||||
"mock": "beefy mock-dev.js:bundle.js --live --open --index=./development/index.html --cwd ./",
|
"mock": "beefy mock-dev.js:bundle.js --live --open --index=./development/index.html --cwd ./",
|
||||||
"buildMock": "npm run genStates && browserify ./mock-dev.js -o ./development/bundle.js",
|
"buildMock": "npm run genStates && browserify ./mock-dev.js -o ./development/bundle.js",
|
||||||
"testem": "npm run buildMock && testem",
|
|
||||||
"announce": "node development/announcer.js",
|
"announce": "node development/announcer.js",
|
||||||
"generateNotice": "node notices/notice-generator.js",
|
"generateNotice": "node notices/notice-generator.js",
|
||||||
"deleteNotice": "node notices/notice-delete.js",
|
"deleteNotice": "node notices/notice-delete.js",
|
||||||
|
@ -138,7 +137,7 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-core": "^6.24.1",
|
"babel-core": "^6.24.1",
|
||||||
"babel-eslint": "^7.2.3",
|
"babel-eslint": "^8.0.0",
|
||||||
"babel-plugin-transform-async-to-generator": "^6.24.1",
|
"babel-plugin-transform-async-to-generator": "^6.24.1",
|
||||||
"babel-plugin-transform-runtime": "^6.23.0",
|
"babel-plugin-transform-runtime": "^6.23.0",
|
||||||
"babel-polyfill": "^6.23.0",
|
"babel-polyfill": "^6.23.0",
|
||||||
|
@ -172,6 +171,11 @@
|
||||||
"jsdom-global": "^3.0.2",
|
"jsdom-global": "^3.0.2",
|
||||||
"jshint-stylish": "~2.2.1",
|
"jshint-stylish": "~2.2.1",
|
||||||
"json-rpc-engine": "^3.0.1",
|
"json-rpc-engine": "^3.0.1",
|
||||||
|
"karma": "^1.7.1",
|
||||||
|
"karma-chrome-launcher": "^2.2.0",
|
||||||
|
"karma-cli": "^1.0.1",
|
||||||
|
"karma-firefox-launcher": "^1.0.1",
|
||||||
|
"karma-qunit": "^1.2.1",
|
||||||
"lodash.assign": "^4.0.6",
|
"lodash.assign": "^4.0.6",
|
||||||
"mocha": "^3.4.2",
|
"mocha": "^3.4.2",
|
||||||
"mocha-eslint": "^4.0.0",
|
"mocha-eslint": "^4.0.0",
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
function wait(time) {
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
setTimeout(function () {
|
|
||||||
resolve()
|
|
||||||
}, time * 3 || 1500)
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,5 +1,6 @@
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
const pump = require('pump')
|
||||||
const browserify = require('browserify')
|
const browserify = require('browserify')
|
||||||
const tests = fs.readdirSync(path.join(__dirname, 'lib'))
|
const tests = fs.readdirSync(path.join(__dirname, 'lib'))
|
||||||
const bundlePath = path.join(__dirname, 'bundle.js')
|
const bundlePath = path.join(__dirname, 'bundle.js')
|
||||||
|
@ -9,11 +10,17 @@ const b = browserify()
|
||||||
const writeStream = fs.createWriteStream(bundlePath)
|
const writeStream = fs.createWriteStream(bundlePath)
|
||||||
|
|
||||||
tests.forEach(function (fileName) {
|
tests.forEach(function (fileName) {
|
||||||
b.add(path.join(__dirname, 'lib', fileName))
|
const filePath = path.join(__dirname, 'lib', fileName)
|
||||||
|
console.log(`bundling test "${filePath}"`)
|
||||||
|
b.add(filePath)
|
||||||
})
|
})
|
||||||
|
|
||||||
b.bundle()
|
pump(
|
||||||
.pipe(writeStream)
|
b.bundle(),
|
||||||
.on('error', (err) => {
|
writeStream,
|
||||||
throw err
|
(err) => {
|
||||||
})
|
if (err) throw err
|
||||||
|
console.log(`Integration test build completed: "${bundlePath}"`)
|
||||||
|
process.exit(0)
|
||||||
|
}
|
||||||
|
)
|
|
@ -2,125 +2,137 @@ const PASSWORD = 'password123'
|
||||||
|
|
||||||
QUnit.module('first time usage')
|
QUnit.module('first time usage')
|
||||||
|
|
||||||
QUnit.test('render init screen', function (assert) {
|
QUnit.test('render init screen', (assert) => {
|
||||||
var done = assert.async()
|
const done = assert.async()
|
||||||
let app
|
runFirstTimeUsageTest(assert).then(done).catch((err) => {
|
||||||
|
assert.notOk(err, `Error was thrown: ${err.stack}`)
|
||||||
wait().then(function() {
|
|
||||||
app = $('iframe').contents().find('#app-content .mock-app-root')
|
|
||||||
|
|
||||||
const recurseNotices = function () {
|
|
||||||
let button = app.find('button')
|
|
||||||
if (button.html() === 'Accept') {
|
|
||||||
let termsPage = app.find('.markdown')[0]
|
|
||||||
termsPage.scrollTop = termsPage.scrollHeight
|
|
||||||
return wait().then(() => {
|
|
||||||
button.click()
|
|
||||||
return wait()
|
|
||||||
}).then(() => {
|
|
||||||
return recurseNotices()
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
return wait()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return recurseNotices()
|
|
||||||
}).then(function() {
|
|
||||||
// Scroll through terms
|
|
||||||
var title = app.find('h1').text()
|
|
||||||
assert.equal(title, 'MetaMask', 'title screen')
|
|
||||||
|
|
||||||
// enter password
|
|
||||||
var pwBox = app.find('#password-box')[0]
|
|
||||||
var confBox = app.find('#password-box-confirm')[0]
|
|
||||||
pwBox.value = PASSWORD
|
|
||||||
confBox.value = PASSWORD
|
|
||||||
|
|
||||||
return wait()
|
|
||||||
}).then(function() {
|
|
||||||
|
|
||||||
// create vault
|
|
||||||
var createButton = app.find('button.primary')[0]
|
|
||||||
createButton.click()
|
|
||||||
|
|
||||||
return wait(1500)
|
|
||||||
}).then(function() {
|
|
||||||
|
|
||||||
var created = app.find('h3')[0]
|
|
||||||
assert.equal(created.textContent, 'Vault Created', 'Vault created screen')
|
|
||||||
|
|
||||||
// Agree button
|
|
||||||
var button = app.find('button')[0]
|
|
||||||
assert.ok(button, 'button present')
|
|
||||||
button.click()
|
|
||||||
|
|
||||||
return wait(1000)
|
|
||||||
}).then(function() {
|
|
||||||
|
|
||||||
var detail = app.find('.account-detail-section')[0]
|
|
||||||
assert.ok(detail, 'Account detail section loaded.')
|
|
||||||
|
|
||||||
var sandwich = app.find('.sandwich-expando')[0]
|
|
||||||
sandwich.click()
|
|
||||||
|
|
||||||
return wait()
|
|
||||||
}).then(function() {
|
|
||||||
|
|
||||||
var sandwich = app.find('.menu-droppo')[0]
|
|
||||||
var children = sandwich.children
|
|
||||||
var lock = children[children.length - 2]
|
|
||||||
assert.ok(lock, 'Lock menu item found')
|
|
||||||
lock.click()
|
|
||||||
|
|
||||||
return wait(1000)
|
|
||||||
}).then(function() {
|
|
||||||
|
|
||||||
var pwBox = app.find('#password-box')[0]
|
|
||||||
pwBox.value = PASSWORD
|
|
||||||
|
|
||||||
var createButton = app.find('button.primary')[0]
|
|
||||||
createButton.click()
|
|
||||||
|
|
||||||
return wait(1000)
|
|
||||||
}).then(function() {
|
|
||||||
|
|
||||||
var detail = app.find('.account-detail-section')[0]
|
|
||||||
assert.ok(detail, 'Account detail section loaded again.')
|
|
||||||
|
|
||||||
return wait()
|
|
||||||
}).then(function (){
|
|
||||||
|
|
||||||
var qrButton = app.find('.fa.fa-ellipsis-h')[0] // open account settings dropdown
|
|
||||||
qrButton.click()
|
|
||||||
|
|
||||||
return wait(1000)
|
|
||||||
}).then(function (){
|
|
||||||
|
|
||||||
var qrButton = app.find('.dropdown-menu-item')[1] // qr code item
|
|
||||||
qrButton.click()
|
|
||||||
|
|
||||||
return wait(1000)
|
|
||||||
}).then(function (){
|
|
||||||
|
|
||||||
var qrHeader = app.find('.qr-header')[0]
|
|
||||||
var qrContainer = app.find('#qr-container')[0]
|
|
||||||
assert.equal(qrHeader.textContent, 'Account 1', 'Should show account label.')
|
|
||||||
assert.ok(qrContainer, 'QR Container found')
|
|
||||||
|
|
||||||
return wait()
|
|
||||||
}).then(function (){
|
|
||||||
|
|
||||||
var networkMenu = app.find('.network-indicator')[0]
|
|
||||||
networkMenu.click()
|
|
||||||
|
|
||||||
return wait()
|
|
||||||
}).then(function (){
|
|
||||||
|
|
||||||
var networkMenu = app.find('.network-indicator')[0]
|
|
||||||
var children = networkMenu.children
|
|
||||||
children.length[3]
|
|
||||||
assert.ok(children, 'All network options present')
|
|
||||||
|
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// QUnit.testDone(({ module, name, total, passed, failed, skipped, todo, runtime }) => {
|
||||||
|
// if (failed > 0) {
|
||||||
|
// const app = $('iframe').contents()[0].documentElement
|
||||||
|
// console.warn('Test failures - dumping DOM:')
|
||||||
|
// console.log(app.innerHTML)
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
|
||||||
|
async function runFirstTimeUsageTest(assert, done) {
|
||||||
|
|
||||||
|
await timeout()
|
||||||
|
|
||||||
|
const app = $('#app-content .mock-app-root')
|
||||||
|
|
||||||
|
// recurse notices
|
||||||
|
while (true) {
|
||||||
|
const button = app.find('button')
|
||||||
|
if (button.html() === 'Accept') {
|
||||||
|
// still notices to accept
|
||||||
|
const termsPage = app.find('.markdown')[0]
|
||||||
|
termsPage.scrollTop = termsPage.scrollHeight
|
||||||
|
await timeout()
|
||||||
|
button.click()
|
||||||
|
await timeout()
|
||||||
|
} else {
|
||||||
|
// exit loop
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await timeout()
|
||||||
|
|
||||||
|
// Scroll through terms
|
||||||
|
const title = app.find('h1').text()
|
||||||
|
assert.equal(title, 'MetaMask', 'title screen')
|
||||||
|
|
||||||
|
// enter password
|
||||||
|
const pwBox = app.find('#password-box')[0]
|
||||||
|
const confBox = app.find('#password-box-confirm')[0]
|
||||||
|
pwBox.value = PASSWORD
|
||||||
|
confBox.value = PASSWORD
|
||||||
|
|
||||||
|
await timeout()
|
||||||
|
|
||||||
|
// create vault
|
||||||
|
const createButton = app.find('button.primary')[0]
|
||||||
|
createButton.click()
|
||||||
|
|
||||||
|
await timeout(1500)
|
||||||
|
|
||||||
|
const created = app.find('h3')[0]
|
||||||
|
assert.equal(created.textContent, 'Vault Created', 'Vault created screen')
|
||||||
|
|
||||||
|
// Agree button
|
||||||
|
const button = app.find('button')[0]
|
||||||
|
assert.ok(button, 'button present')
|
||||||
|
button.click()
|
||||||
|
|
||||||
|
await timeout(1000)
|
||||||
|
|
||||||
|
const detail = app.find('.account-detail-section')[0]
|
||||||
|
assert.ok(detail, 'Account detail section loaded.')
|
||||||
|
|
||||||
|
const sandwich = app.find('.sandwich-expando')[0]
|
||||||
|
sandwich.click()
|
||||||
|
|
||||||
|
await timeout()
|
||||||
|
|
||||||
|
const menu = app.find('.menu-droppo')[0]
|
||||||
|
const children = menu.children
|
||||||
|
const lock = children[children.length - 2]
|
||||||
|
assert.ok(lock, 'Lock menu item found')
|
||||||
|
lock.click()
|
||||||
|
|
||||||
|
await timeout(1000)
|
||||||
|
|
||||||
|
const pwBox2 = app.find('#password-box')[0]
|
||||||
|
pwBox2.value = PASSWORD
|
||||||
|
|
||||||
|
const createButton2 = app.find('button.primary')[0]
|
||||||
|
createButton2.click()
|
||||||
|
|
||||||
|
await timeout(1000)
|
||||||
|
|
||||||
|
const detail2 = app.find('.account-detail-section')[0]
|
||||||
|
assert.ok(detail2, 'Account detail section loaded again.')
|
||||||
|
|
||||||
|
await timeout()
|
||||||
|
|
||||||
|
// open account settings dropdown
|
||||||
|
const qrButton = app.find('.fa.fa-ellipsis-h')[0]
|
||||||
|
qrButton.click()
|
||||||
|
|
||||||
|
await timeout(1000)
|
||||||
|
|
||||||
|
// qr code item
|
||||||
|
const qrButton2 = app.find('.dropdown-menu-item')[1]
|
||||||
|
qrButton2.click()
|
||||||
|
|
||||||
|
await timeout(1000)
|
||||||
|
|
||||||
|
const qrHeader = app.find('.qr-header')[0]
|
||||||
|
const qrContainer = app.find('#qr-container')[0]
|
||||||
|
assert.equal(qrHeader.textContent, 'Account 1', 'Should show account label.')
|
||||||
|
assert.ok(qrContainer, 'QR Container found')
|
||||||
|
|
||||||
|
await timeout()
|
||||||
|
|
||||||
|
const networkMenu = app.find('.network-indicator')[0]
|
||||||
|
networkMenu.click()
|
||||||
|
|
||||||
|
await timeout()
|
||||||
|
|
||||||
|
const networkMenu2 = app.find('.network-indicator')[0]
|
||||||
|
const children2 = networkMenu2.children
|
||||||
|
children2.length[3]
|
||||||
|
assert.ok(children2, 'All network options present')
|
||||||
|
}
|
||||||
|
|
||||||
|
function timeout(time) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
setTimeout(function () {
|
||||||
|
resolve()
|
||||||
|
}, time * 3 || 1500)
|
||||||
|
})
|
||||||
|
}
|
10
testem.yml
10
testem.yml
|
@ -1,10 +0,0 @@
|
||||||
launch_in_dev:
|
|
||||||
- Chrome
|
|
||||||
- Firefox
|
|
||||||
launch_in_ci:
|
|
||||||
- Chrome
|
|
||||||
- Firefox
|
|
||||||
framework:
|
|
||||||
- qunit
|
|
||||||
before_tests: "npm run buildCiUnits"
|
|
||||||
test_page: "test/integration/index.html"
|
|
|
@ -1,6 +1,7 @@
|
||||||
const Component = require('react').Component
|
const Component = require('react').Component
|
||||||
const h = require('react-hyperscript')
|
const h = require('react-hyperscript')
|
||||||
const inherits = require('util').inherits
|
const inherits = require('util').inherits
|
||||||
|
const exportAsFile = require('../util').exportAsFile
|
||||||
const copyToClipboard = require('copy-to-clipboard')
|
const copyToClipboard = require('copy-to-clipboard')
|
||||||
const actions = require('../actions')
|
const actions = require('../actions')
|
||||||
const ethUtil = require('ethereumjs-util')
|
const ethUtil = require('ethereumjs-util')
|
||||||
|
@ -20,20 +21,21 @@ function mapStateToProps (state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ExportAccountView.prototype.render = function () {
|
ExportAccountView.prototype.render = function () {
|
||||||
var state = this.props
|
const state = this.props
|
||||||
var accountDetail = state.accountDetail
|
const accountDetail = state.accountDetail
|
||||||
|
const nickname = state.identities[state.address].name
|
||||||
|
|
||||||
if (!accountDetail) return h('div')
|
if (!accountDetail) return h('div')
|
||||||
var accountExport = accountDetail.accountExport
|
const accountExport = accountDetail.accountExport
|
||||||
|
|
||||||
var notExporting = accountExport === 'none'
|
const notExporting = accountExport === 'none'
|
||||||
var exportRequested = accountExport === 'requested'
|
const exportRequested = accountExport === 'requested'
|
||||||
var accountExported = accountExport === 'completed'
|
const accountExported = accountExport === 'completed'
|
||||||
|
|
||||||
if (notExporting) return h('div')
|
if (notExporting) return h('div')
|
||||||
|
|
||||||
if (exportRequested) {
|
if (exportRequested) {
|
||||||
var warning = `Export private keys at your own risk.`
|
const warning = `Export private keys at your own risk.`
|
||||||
return (
|
return (
|
||||||
h('div', {
|
h('div', {
|
||||||
style: {
|
style: {
|
||||||
|
@ -89,6 +91,8 @@ ExportAccountView.prototype.render = function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (accountExported) {
|
if (accountExported) {
|
||||||
|
const plainKey = ethUtil.stripHexPrefix(accountDetail.privateKey)
|
||||||
|
|
||||||
return h('div.privateKey', {
|
return h('div.privateKey', {
|
||||||
style: {
|
style: {
|
||||||
margin: '0 20px',
|
margin: '0 20px',
|
||||||
|
@ -105,10 +109,16 @@ ExportAccountView.prototype.render = function () {
|
||||||
onClick: function (event) {
|
onClick: function (event) {
|
||||||
copyToClipboard(ethUtil.stripHexPrefix(accountDetail.privateKey))
|
copyToClipboard(ethUtil.stripHexPrefix(accountDetail.privateKey))
|
||||||
},
|
},
|
||||||
}, ethUtil.stripHexPrefix(accountDetail.privateKey)),
|
}, plainKey),
|
||||||
h('button', {
|
h('button', {
|
||||||
onClick: () => this.props.dispatch(actions.backToAccountDetail(this.props.address)),
|
onClick: () => this.props.dispatch(actions.backToAccountDetail(this.props.address)),
|
||||||
}, 'Done'),
|
}, 'Done'),
|
||||||
|
h('button', {
|
||||||
|
style: {
|
||||||
|
marginLeft: '10px',
|
||||||
|
},
|
||||||
|
onClick: () => exportAsFile(`MetaMask ${nickname} Private Key`, plainKey),
|
||||||
|
}, 'Save as File'),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,6 +127,6 @@ ExportAccountView.prototype.onExportKeyPress = function (event) {
|
||||||
if (event.key !== 'Enter') return
|
if (event.key !== 'Enter') return
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
||||||
var input = document.getElementById('exportAccount').value
|
const input = document.getElementById('exportAccount').value
|
||||||
this.props.dispatch(actions.exportAccount(input, this.props.address))
|
this.props.dispatch(actions.exportAccount(input, this.props.address))
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,8 @@ const connect = require('react-redux').connect
|
||||||
const actions = require('./actions')
|
const actions = require('./actions')
|
||||||
const currencies = require('./conversion.json').rows
|
const currencies = require('./conversion.json').rows
|
||||||
const validUrl = require('valid-url')
|
const validUrl = require('valid-url')
|
||||||
const copyToClipboard = require('copy-to-clipboard')
|
const exportAsFile = require('./util').exportAsFile
|
||||||
|
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(ConfigScreen)
|
module.exports = connect(mapStateToProps)(ConfigScreen)
|
||||||
|
|
||||||
|
@ -110,9 +111,9 @@ ConfigScreen.prototype.render = function () {
|
||||||
alignSelf: 'center',
|
alignSelf: 'center',
|
||||||
},
|
},
|
||||||
onClick (event) {
|
onClick (event) {
|
||||||
copyToClipboard(window.logState())
|
exportAsFile('MetaMask State Logs', window.logState())
|
||||||
},
|
},
|
||||||
}, 'Copy State Logs'),
|
}, 'Download State Logs'),
|
||||||
]),
|
]),
|
||||||
|
|
||||||
h('hr.horizontal-line'),
|
h('hr.horizontal-line'),
|
||||||
|
|
|
@ -3,6 +3,7 @@ const Component = require('react').Component
|
||||||
const connect = require('react-redux').connect
|
const connect = require('react-redux').connect
|
||||||
const h = require('react-hyperscript')
|
const h = require('react-hyperscript')
|
||||||
const actions = require('../../actions')
|
const actions = require('../../actions')
|
||||||
|
const exportAsFile = require('../../util').exportAsFile
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(CreateVaultCompleteScreen)
|
module.exports = connect(mapStateToProps)(CreateVaultCompleteScreen)
|
||||||
|
|
||||||
|
@ -65,8 +66,17 @@ CreateVaultCompleteScreen.prototype.render = function () {
|
||||||
style: {
|
style: {
|
||||||
margin: '24px',
|
margin: '24px',
|
||||||
fontSize: '0.9em',
|
fontSize: '0.9em',
|
||||||
|
marginBottom: '10px',
|
||||||
},
|
},
|
||||||
}, 'I\'ve copied it somewhere safe'),
|
}, 'I\'ve copied it somewhere safe'),
|
||||||
|
|
||||||
|
h('button.primary', {
|
||||||
|
onClick: () => exportAsFile(`MetaMask Seed Words`, seed),
|
||||||
|
style: {
|
||||||
|
margin: '10px',
|
||||||
|
fontSize: '0.9em',
|
||||||
|
},
|
||||||
|
}, 'Save Seed Words As File'),
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ module.exports = {
|
||||||
valueTable: valueTable,
|
valueTable: valueTable,
|
||||||
bnTable: bnTable,
|
bnTable: bnTable,
|
||||||
isHex: isHex,
|
isHex: isHex,
|
||||||
|
exportAsFile: exportAsFile,
|
||||||
}
|
}
|
||||||
|
|
||||||
function valuesFor (obj) {
|
function valuesFor (obj) {
|
||||||
|
@ -215,3 +216,18 @@ function readableDate (ms) {
|
||||||
function isHex (str) {
|
function isHex (str) {
|
||||||
return Boolean(str.match(/^(0x)?[0-9a-fA-F]+$/))
|
return Boolean(str.match(/^(0x)?[0-9a-fA-F]+$/))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function exportAsFile (filename, data) {
|
||||||
|
// source: https://stackoverflow.com/a/33542499 by Ludovic Feltz
|
||||||
|
const blob = new Blob([data], {type: 'text/csv'})
|
||||||
|
if (window.navigator.msSaveOrOpenBlob) {
|
||||||
|
window.navigator.msSaveBlob(blob, filename)
|
||||||
|
} else {
|
||||||
|
const elem = window.document.createElement('a')
|
||||||
|
elem.href = window.URL.createObjectURL(blob)
|
||||||
|
elem.download = filename
|
||||||
|
document.body.appendChild(elem)
|
||||||
|
elem.click()
|
||||||
|
document.body.removeChild(elem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue