e2e tests for updateABI menu item, refactoring of accounts-dropdow source code

This commit is contained in:
Victor Baranov 2019-01-22 19:01:43 +03:00
parent 54eae91265
commit c7a3f6c499
16 changed files with 490 additions and 389 deletions

View File

@ -22,7 +22,7 @@ class AccountImportSubview extends Component {
}
}
static propTypes = {
menuItems: PropTypes.object.Array,
menuItems: PropTypes.array,
warning: PropTypes.node,
goHome: PropTypes.func,
displayWarning: PropTypes.func,

View File

@ -1,20 +1,35 @@
const Component = require('react').Component
const PropTypes = require('prop-types')
const h = require('react-hyperscript')
const actions = require('../../../ui/app/actions')
const connect = require('react-redux').connect
const Dropdown = require('./dropdown').Dropdown
const DropdownMenuItem = require('./dropdown').DropdownMenuItem
const Identicon = require('./identicon')
const ethUtil = require('ethereumjs-util')
const copyToClipboard = require('copy-to-clipboard')
const ethNetProps = require('eth-net-props')
const { getCurrentKeyring, ifLooseAcc, ifContractAcc } = require('../util')
const { getHdPaths } = require('./connect-hardware/util')
const { importTypes, labels } = require('../accounts/import/enums')
const { getFullABI } = require('../accounts/import/helpers')
const log = require('loglevel')
const Web3 = require('web3')
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import actions from '../../../ui/app/actions'
import { connect } from 'react-redux'
import { Dropdown, DropdownMenuItem } from './dropdown'
import Identicon from './identicon'
import ethUtil from 'ethereumjs-util'
import copyToClipboard from 'copy-to-clipboard'
import ethNetProps from 'eth-net-props'
import { getCurrentKeyring, ifLooseAcc, ifContractAcc, ifHardwareAcc } from '../util'
import { getHdPaths, isLedger } from './connect-hardware/util'
import { LEDGER } from './connect-hardware/enum'
import { importTypes, labels } from '../accounts/import/enums'
import { getFullABI } from '../accounts/import/helpers'
import log from 'loglevel'
import Web3 from 'web3'
class AccountsDropdownMenuItemWrapper extends DropdownMenuItem {
render () {
return (
<DropdownMenuItem
style={{
padding: '8px 0px',
}}
closeMenu={() => {}}
onClick={() => this.props.onClick()}
>
<span className="acc-dd-menu-item-text">{this.props.label}</span>
</DropdownMenuItem>
)
}
}
class AccountDropdowns extends Component {
constructor (props) {
@ -23,8 +38,10 @@ class AccountDropdowns extends Component {
this.state = {
accountSelectorActive: false,
optionsMenuActive: false,
contractProps: {},
web3,
labels: {},
isProxy: false,
contractProps: null,
}
this.accountSelectorToggleClassName = 'accounts-selector'
this.optionsMenuToggleClassName = 'account-dropdown'
@ -32,16 +49,9 @@ class AccountDropdowns extends Component {
renderAccounts () {
const { identities, selected, keyrings, network } = this.props
const accountOrder = keyrings.reduce((list, keyring) => {
if (ifContractAcc(keyring) && keyring.network === network) {
list = list.concat(keyring.accounts)
} else if (!ifContractAcc(keyring)) {
list = list.concat(keyring.accounts)
}
return list
}, [])
const accountOrder = this.getAccounts()
return accountOrder.map((address, index) => {
const accountsViews = accountOrder.map((address, index) => {
const identity = identities[address]
if (!identity) {
return null
@ -61,375 +71,348 @@ class AccountDropdowns extends Component {
return this.accountsDropdownItemView(index, isSelected, keyring, identity)
}
})
return accountsViews
}
accountsDropdownItemView (index, isSelected, keyring, identity) {
return h(
DropdownMenuItem,
{
closeMenu: () => {},
onClick: () => {
this.props.actions.showAccountDetail(identity.address)
if (this.ifHardwareAcc(keyring)) {
const ledger = 'ledger'
if (keyring.type.toLowerCase().includes(ledger)) {
const hdPaths = getHdPaths()
return new Promise((resolve, reject) => {
this.props.actions.connectHardwareAndUnlockAddress(ledger, hdPaths[1].value, identity.address)
.then(_ => resolve())
.catch(e => {
this.props.actions.connectHardwareAndUnlockAddress(ledger, hdPaths[0].value, identity.address)
.then(_ => resolve())
.catch(e => reject(e))
})
})
.catch(e => {
this.props.actions.displayWarning((e && e.message) || e)
this.props.actions.displayToast(e)
})
}
}
},
style: {
marginTop: index === 0 ? '5px' : '',
fontSize: '16px',
padding: '8px 0px',
},
},
[
isSelected ? h('div', {
style: {
width: '4px',
height: '26px',
background: '#60db97',
position: 'absolute',
left: '-25px',
},
}) : null,
h(
Identicon,
{
overflow: 'none',
address: identity.address,
diameter: 24,
style: {
marginLeft: '10px',
},
},
),
h('span', {
style: {
marginLeft: '10px',
fontSize: '16px',
maxWidth: '95px',
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
color: isSelected ? 'white' : '',
},
}, identity.name || ''),
this.indicateIfLoose(keyring),
ifLooseAcc(keyring) ? h('.remove', {
onClick: (event) => {
event.preventDefault()
event.stopPropagation()
this.props.actions.showDeleteImportedAccount(identity)
this.setState({
accountSelectorActive: false,
optionsMenuActive: false,
})
},
}) : null,
]
)
const { labels } = this.state
const { address, name } = identity
const leftBorder = isSelected ? <div className="accs-dd-menu-item-selected" /> : null
const accountIcon = (
<Identicon
overflow="none"
address={identity.address}
diameter={24}
style={{ marginLeft: '10px' }}
/>
)
const accountName = (
<span
className="accs-dd-menu-item-account-name"
style={{ color: isSelected ? 'white' : '' }}
>{name || ''}
</span>
)
const accountLabel = labels[address] ? <div className="keyring-label">{labels[address]}</div> : null
const removeIcon = ifLooseAcc(keyring) ? (
<div
className="remove"
onClick={(event) => {
event.preventDefault()
event.stopPropagation()
this.props.actions.showDeleteImportedAccount(identity)
this.setState({
accountSelectorActive: false,
optionsMenuActive: false,
})
}}
/>) : null
return (
<DropdownMenuItem
key={`account_${index}`}
closeMenu={() => {}}
onClick={() => this.accountOnClick(keyring, address)}
style={{
marginTop: index === 0 ? '5px' : '',
fontSize: '16px',
padding: '8px 0px',
}}
>
{leftBorder}
{accountIcon}
{accountName}
{accountLabel}
{removeIcon}
</DropdownMenuItem>
)
}
ifHardwareAcc (keyring) {
if (keyring && keyring.type.search('Hardware') !== -1) {
return true
accountOnClick (keyring, address) {
this.props.actions.showAccountDetail(address)
if (ifHardwareAcc(keyring)) {
if (isLedger(keyring.type)) {
const hdPaths = getHdPaths()
return new Promise((resolve, reject) => {
this.props.actions.connectHardwareAndUnlockAddress(LEDGER, hdPaths[1].value, address)
.then(_ => resolve())
.catch(e => {
this.props.actions.connectHardwareAndUnlockAddress(LEDGER, hdPaths[0].value, address)
.then(_ => resolve())
.catch(e => reject(e))
})
})
.catch(e => {
this.props.actions.displayWarning((e && e.message) || e)
this.props.actions.displayToast(e)
})
}
}
return false
}
ifProxyAcc () {
const { contractProps } = this.state
return contractProps && contractProps.contractType === importTypes.CONTRACT.PROXY
ifProxyAcc (address, setProxy) {
return new Promise((resolve, reject) => {
this.props.actions.getContract(address)
.then(contractProps => {
if (setProxy) {
this.setState({contractProps})
}
resolve(contractProps && contractProps.contractType === importTypes.CONTRACT.PROXY)
})
.catch(e => reject(e))
})
}
indicateIfLoose (keyring) {
setLabel (keyring, address) {
if (ifLooseAcc(keyring)) {
let label
if (ifContractAcc(keyring)) {
if (this.ifProxyAcc()) {
label = labels.PROXY
} else {
label = labels.CONTRACT
}
} else if (this.ifHardwareAcc(keyring)) {
const setProxy = false
this.ifProxyAcc(address, setProxy)
.then(isProxy => {
label = isProxy ? labels.PROXY : labels.CONTRACT
this.setLabelToState(label, address)
})
} else if (ifHardwareAcc(keyring)) {
label = labels.HARDWARE
this.setLabelToState(label, address)
} else {
label = labels.IMPORTED
this.setLabelToState(label, address)
}
return h('.keyring-label', label)
}
}
return null
setLabelToState (label, address) {
const labelsArr = this.state.labels
labelsArr[address] = label
this.setState({labelsArr})
}
renderAccountSelector () {
const { actions } = this.props
const { accountSelectorActive } = this.state
let menuItems = []
menuItems = Object.assign(menuItems, this.renderAccounts())
const bottomMenuItems = [
<AccountsDropdownMenuItemWrapper key="AccountsDropdownMenuItemAdd" onClick={() => actions.addNewAccount()} label="Create Account" />,
<AccountsDropdownMenuItemWrapper key="AccountsDropdownMenuItemImport" onClick={() => actions.showImportPage()} label="Import Account" />,
<AccountsDropdownMenuItemWrapper key="AccountsDropdownMenuItemConnectHD" onClick={() => actions.showConnectHWWalletPage()} label="Connect hardware wallet" />,
]
menuItems = menuItems.concat(bottomMenuItems)
return h(
Dropdown,
{
useCssTransition: true, // Hardcoded because account selector is temporarily in app-header
style: {
return (
<Dropdown
useCssTransition={true} // Hardcoded because account selector is temporarily in app-header
style={{
position: 'absolute',
marginLeft: '-213px',
top: '38px',
minWidth: '180px',
maxHeight: accountSelectorActive ? '300px' : '0px',
width: '265px',
},
innerStyle: {
}}
innerStyle={{
padding: '8px 25px',
},
isOpen: accountSelectorActive,
onClickOutside: (event) => {
}}
isOpen={accountSelectorActive}
onClickOutside={(event) => {
const { classList } = event.target
const isNotToggleElement = !classList.contains(this.accountSelectorToggleClassName)
if (accountSelectorActive && isNotToggleElement) {
this.setState({ accountSelectorActive: false })
}
},
},
[
...this.renderAccounts(),
h(
DropdownMenuItem,
{
style: {
padding: '8px 0px',
},
closeMenu: () => {},
onClick: () => actions.addNewAccount(),
},
[
h('span', { style: { fontSize: '16px', color: '#60db97' } }, 'Create Account'),
],
),
h(
DropdownMenuItem,
{
style: {
padding: '8px 0px',
},
closeMenu: () => {},
onClick: () => actions.showImportPage(),
},
[
h('span', {
style: {
fontSize: '16px',
marginBottom: '5px',
color: '#60db97',
},
}, 'Import Account'),
]
),
h(
DropdownMenuItem,
{
style: {
padding: '8px 0px',
},
closeMenu: () => {},
onClick: () => actions.showConnectHWWalletPage(),
},
[
h('span', {
style: {
fontSize: '16px',
marginBottom: '5px',
color: '#60db97',
},
}, 'Connect hardware wallet'),
]
),
]
}}
>
{menuItems}
</Dropdown>
)
}
renderAccountOptions () {
const { actions, selected, network, keyrings, identities } = this.props
const { optionsMenuActive, contractProps, web3 } = this.state
const { optionsMenuActive, isProxy } = this.state
const keyring = getCurrentKeyring(selected, network, keyrings, identities)
return h(
Dropdown,
{
style: {
return (
<Dropdown
style={{
position: 'relative',
marginLeft: '-234px',
minWidth: '180px',
top: '30px',
width: '280px',
},
isOpen: optionsMenuActive,
onClickOutside: (event) => {
}}
isOpen={optionsMenuActive}
onClickOutside={(event) => {
const { classList } = event.target
const isNotToggleElement = !classList.contains(this.optionsMenuToggleClassName)
if (optionsMenuActive && isNotToggleElement) {
this.setState({ optionsMenuActive: false })
}
},
},
[
h(
DropdownMenuItem,
{
closeMenu: () => {},
onClick: () => {
const { selected, network } = this.props
const url = ethNetProps.explorerLinks.getExplorerAccountLinkFor(selected, network)
global.platform.openWindow({ url })
},
},
`View on block explorer`,
),
h(
DropdownMenuItem,
{
closeMenu: () => {},
onClick: () => {
const { selected, identities } = this.props
var identity = identities[selected]
actions.showQrView(selected, identity ? identity.name : '')
},
},
'Show QR Code',
),
h(
DropdownMenuItem,
{
closeMenu: () => {},
onClick: () => {
const { selected } = this.props
const checkSumAddress = selected && ethUtil.toChecksumAddress(selected)
copyToClipboard(checkSumAddress)
},
},
'Copy address to clipboard',
),
ifContractAcc(keyring) ? h(
DropdownMenuItem,
{
closeMenu: () => {},
onClick: async () => {
const abi = contractProps && contractProps.abi
copyToClipboard(JSON.stringify(abi))
},
},
'Copy ABI to clipboard',
) : null,
this.ifProxyAcc() ? h(
DropdownMenuItem,
{
closeMenu: () => {},
onClick: async () => {
actions.showLoadingIndication()
getFullABI(web3.eth, selected, network, importTypes.CONTRACT.PROXY)
.then(finalABI => {
actions.updateABI(selected, network, finalABI)
.then()
.catch(e => {
log.debug(e)
})
.finally(() => actions.hideLoadingIndication())
})
.catch(e => {
log.debug(e)
actions.hideLoadingIndication()
})
},
},
'Update implementation ABI',
) : null,
(!this.ifHardwareAcc(keyring) && !(ifContractAcc(keyring))) ? h(
DropdownMenuItem,
{
closeMenu: () => {},
onClick: () => {
actions.requestAccountExport()
},
},
'Export Private Key',
) : null,
]
}}
>
<DropdownMenuItem
closeMenu={() => {}}
onClick={() => this.viewOnBlockExplorer()}
>View on block explorer</DropdownMenuItem>
<DropdownMenuItem
closeMenu={() => {}}
onClick={() => this.showQRCode()}
>Show QR Code</DropdownMenuItem>
<DropdownMenuItem
closeMenu={() => {}}
onClick={() => this.copyAddress()}
>Copy address to clipboard</DropdownMenuItem>
{ifContractAcc(keyring) ? <DropdownMenuItem
closeMenu={() => {}}
onClick={() => this.copyABI()}
>Copy ABI to clipboard</DropdownMenuItem> : null}
{isProxy ? <DropdownMenuItem
closeMenu={() => {}}
onClick={() => this.updateABI()}
>Update implementation ABI</DropdownMenuItem> : null}
{(!ifHardwareAcc(keyring) && !(ifContractAcc(keyring))) ? <DropdownMenuItem
closeMenu={() => {}}
onClick={() => actions.requestAccountExport()}
>Export Private Key</DropdownMenuItem> : null}
</Dropdown>
)
}
componentDidMount () {
viewOnBlockExplorer = () => {
const { selected, network } = this.props
const url = ethNetProps.explorerLinks.getExplorerAccountLinkFor(selected, network)
global.platform.openWindow({ url })
}
showQRCode = () => {
const { selected, identities, actions } = this.props
const identity = identities[selected]
actions.showQrView(selected, identity ? identity.name : '')
}
copyAddress = () => {
const { selected } = this.props
this.props.actions.getContract(selected)
.then(contractProps => {
this.setState({ contractProps })
})
const checkSumAddress = selected && ethUtil.toChecksumAddress(selected)
copyToClipboard(checkSumAddress)
}
copyABI = async () => {
const { contractProps } = this.state
const abi = contractProps && contractProps.abi
copyToClipboard(JSON.stringify(abi))
}
updateABI = async () => {
const { actions, selected, network } = this.props
const { web3 } = this.state
actions.showLoadingIndication()
getFullABI(web3.eth, selected, network, importTypes.CONTRACT.PROXY)
.then(finalABI => {
actions.updateABI(selected, network, finalABI)
.then()
.catch(e => {
log.debug(e)
})
.finally(() => actions.hideLoadingIndication())
})
.catch(e => {
log.debug(e)
actions.hideLoadingIndication()
})
}
render () {
const { style, enableAccountsSelector, enableAccountOptions } = this.props
const { optionsMenuActive, accountSelectorActive } = this.state
return h(
'span',
{
style: style,
},
[
enableAccountsSelector && h(
'div.accounts-selector',
{
style: {
background: 'url(images/switch_acc.svg) white center center no-repeat',
height: '25px',
width: '25px',
marginRight: '3px',
},
onClick: (event) => {
event.stopPropagation()
this.setState({
accountSelectorActive: !accountSelectorActive,
optionsMenuActive: false,
})
},
},
this.renderAccountSelector(),
),
enableAccountOptions && h(
'div.address-dropdown.account-dropdown',
{
onClick: (event) => {
event.stopPropagation()
this.setState({
accountSelectorActive: false,
optionsMenuActive: !optionsMenuActive,
})
},
},
this.renderAccountOptions()
),
]
const accountSelector = enableAccountsSelector && (
<div
className="accounts-selector accounts-selector-additional-style"
onClick={(event) => {
event.stopPropagation()
this.setState({
accountSelectorActive: !accountSelectorActive,
optionsMenuActive: false,
})
}}
>
{this.renderAccountSelector()}
</div>
)
const accountOptions = enableAccountOptions && (
<div
className="address-dropdown account-dropdown"
onClick={(event) => {
event.stopPropagation()
this.setState({
accountSelectorActive: false,
optionsMenuActive: !optionsMenuActive,
})
}}
>
{this.renderAccountOptions()}
</div>
)
return (
<span style={style}>
{accountSelector}
{accountOptions}
</span>
)
}
getAccounts () {
const { keyrings, network } = this.props
const accountOrder = keyrings.reduce((list, keyring) => {
if (ifContractAcc(keyring) && keyring.network === network) {
list = list.concat(keyring.accounts)
} else if (!ifContractAcc(keyring)) {
list = list.concat(keyring.accounts)
}
return list
}, [])
return accountOrder
}
checkIfProxy () {
const { selected } = this.props
const setProxy = true
this.ifProxyAcc(selected, setProxy)
.then(isProxy => {
this.setState({isProxy})
})
}
setAllLabels () {
const { identities, keyrings, network } = this.props
const accountOrder = this.getAccounts()
accountOrder.forEach((address) => {
const keyring = getCurrentKeyring(address, network, keyrings, identities)
this.setLabel(keyring, address)
})
}
componentDidMount () {
this.setAllLabels()
this.checkIfProxy()
}
// switch to the first account in the list on network switch, if unlocked account was contract before change
componentDidUpdate (prevProps) {
const { selected, keyrings } = this.props
if (prevProps.selected !== selected) {
this.checkIfProxy()
}
if (prevProps.keyrings.length !== keyrings.length) {
this.setAllLabels()
}
if (!isNaN(this.props.network)) {
const { selected, network, keyrings, identities } = this.props
const { network } = this.props
if (network !== prevProps.network) {
const { keyrings, identities } = this.props
const keyring = getCurrentKeyring(selected, this.props.network, keyrings, identities)
const firstKeyring = keyrings && keyrings[0]
const firstKeyRingAcc = firstKeyring && firstKeyring.accounts && firstKeyring.accounts[0]

View File

@ -0,0 +1,5 @@
const LEDGER = 'ledger'
module.exports = {
LEDGER,
}

View File

@ -1,6 +1,7 @@
import { LEDGER } from './enum'
function isLedger (device) {
return device && device.toLowerCase().includes('ledger')
return device && device.toLowerCase().includes(LEDGER)
}
function getHdPaths () {

View File

@ -94,7 +94,7 @@ class DropdownMenuItem extends Component {
}
DropdownMenuItem.propTypes = {
closeMenu: PropTypes.func.isRequired,
closeMenu: PropTypes.func,
onClick: PropTypes.func.isRequired,
children: PropTypes.node,
style: PropTypes.object,

View File

@ -134,38 +134,47 @@ TokenList.prototype.renderTokenStatusBar = function () {
const tokensFromCurrentNetwork = tokens.filter(token => (parseInt(token.network) === parseInt(network) || !token.network))
let msg
let noTokens = false
if (tokensFromCurrentNetwork.length === 1) {
msg = `You own 1 token`
} else if (tokensFromCurrentNetwork.length > 1) {
msg = `You own ${tokensFromCurrentNetwork.length} tokens`
} else {
msg = `No tokens found`
noTokens = true
}
return h('div', {
style: {
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
minHeight: '70px',
padding: '30px 30px 10px',
},
}, [
h('span', msg),
h('button.btn-primary.wallet-view__add-token-button', {
key: 'reveal-account-bar',
onClick: (event) => {
event.preventDefault()
this.props.addToken()
},
return h('div', [
h('div', {
style: {
display: 'flex',
justifyContent: 'center',
justifyContent: 'space-between',
alignItems: 'center',
minHeight: '70px',
padding: '30px 30px 10px',
},
}, [
'Add Token',
h('span', msg),
h('button.btn-primary.wallet-view__add-token-button', {
key: 'reveal-account-bar',
onClick: (event) => {
event.preventDefault()
this.props.addToken()
},
style: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
},
}, [
'Add Token',
]),
]),
noTokens ? h('div', {
style: {
height: '70px',
},
}) : null,
])
}

View File

@ -76,7 +76,7 @@ TransactionList.prototype.render = function () {
}, [
h('p', {
style: {
marginTop: '50px',
margin: '50px 0',
},
}, 'No transaction history.'),
]),

View File

@ -0,0 +1,27 @@
.accs-dd-menu-item-selected {
width: 4px;
height: 26px;
background: #60db97;
position: absolute;
left: -25px;
}
.accs-dd-menu-item-account-name {
margin-left: 10px;
font-size: 16px;
max-width: 95px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.acc-dd-menu-item-text {
font-size: 16px;
margin-bottom: 5px;
color: #60db97;
}
.accounts-selector-additional-style {
background: url(images/switch_acc.svg) white center center no-repeat;
height: 25px;
width: 25px;
margin-right: 3px;
}

View File

@ -44,6 +44,7 @@ module.exports = {
getCurrentKeyring,
ifLooseAcc,
ifContractAcc,
ifHardwareAcc,
}
function valuesFor (obj) {
@ -323,6 +324,7 @@ function ifLooseAcc (keyring) {
} catch (e) { return }
}
/**
* checks, if keyring is contract
*
@ -337,3 +339,17 @@ function ifContractAcc (keyring) {
return isContract
} catch (e) { return }
}
/**
* checks, if keyring is of hardware type
*
* @param {object} keyring
*
* returns {boolean} true, if keyring is of hardware type and false, if it is not
**/
function ifHardwareAcc (keyring) {
if (keyring && keyring.type.search('Hardware') !== -1) {
return true
}
return false
}

View File

@ -17,6 +17,7 @@ var cssFiles = {
'first-time.css': fs.readFileSync(path.join(__dirname, '../mascara/src/app/first-time/index.css'), 'utf8'),
'react-tooltip-component.css': fs.readFileSync(path.join(__dirname, '..', 'node_modules', 'react-tooltip-component', 'dist', 'react-tooltip-component.css'), 'utf8'),
'react-css': fs.readFileSync(path.join(__dirname, '..', 'node_modules', 'react-select', 'dist', 'react-select.css'), 'utf8'),
'dropdowns.css': fs.readFileSync(path.join(__dirname, '/app/css/dropdowns.css'), 'utf8'),
}
function bundleCss () {

8
package-lock.json generated
View File

@ -16169,7 +16169,7 @@
"integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=",
"dev": true,
"requires": {
"ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799",
"ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215",
"ethereumjs-util": "^5.1.1"
}
},
@ -16180,7 +16180,7 @@
"dev": true
},
"ethereumjs-abi": {
"version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799",
"version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215",
"from": "git+https://github.com/ethereumjs/ethereumjs-abi.git",
"dev": true,
"requires": {
@ -19620,12 +19620,12 @@
"integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=",
"dev": true,
"requires": {
"ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799",
"ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215",
"ethereumjs-util": "^5.1.1"
}
},
"ethereumjs-abi": {
"version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799",
"version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215",
"from": "git+https://github.com/ethereumjs/ethereumjs-abi.git",
"dev": true,
"requires": {

View File

@ -21,7 +21,7 @@
"test:e2e:firefox": "shell-parallel -s 'npm run ganache:start' -x 'sleep 3 && npm run test:e2e:run:firefox'",
"test:e2e:firefox:beta": "SELENIUM_BROWSER=firefox test/e2e/beta/run-all.sh",
"test:e2e:run:chrome": "SELENIUM_BROWSER=chrome mocha test/e2e/nw.spec --bail --recursive",
"test:e2e:run:firefox": "SELENIUM_BROWSER=firefox mocha test/e2e/test-cases/nw.spec --bail --recursive",
"test:e2e:run:firefox": "SELENIUM_BROWSER=firefox mocha test/e2e/nw.spec --bail --recursive",
"test:screens": "shell-parallel -s 'npm run ganache:start' -x 'sleep 3 && npm run test:screens:run'",
"test:screens:run": "node test/screens/new-ui.js",
"test:coverage": "nyc --reporter=text --reporter=html npm run test:unit && npm run test:coveralls-upload",

View File

@ -252,7 +252,7 @@ module.exports = {
error: By.css('span.error'),
selectArrow: By.className('Select-arrow-zone'),
selectType: By.name('import-type-select'),
itemContract: By.id('react-select-3--option-2'),
itemContract: By.id('react-select-4--option-2'),
itemProxyContract: By.id('react-select-3--option-3'),
contractAddress: By.id('address-box'),
contractABI: By.id('abi-box'),
@ -313,7 +313,7 @@ module.exports = {
amount: By.css('#app-content > div > div.app-primary.from-left > div > section > div.full-flex-height > div > span'),
textNoTokens: 'No tokens found',
textYouOwn1token: 'You own 1 token',
buttonAdd: By.css('div.full-flex-height:nth-child(2) > div:nth-child(1) > button:nth-child(2)'),
buttonAdd: By.css('#app-content > div > div.app-primary.from-right > div > section > div.full-flex-height > div > div:nth-child(1) > button'),
buttonAddText: 'Add Token',
counter: By.css('#app-content > div > div.app-primary.from-left > div > section > div.full-flex-height > div > span'),
counterFF: By.css('div.full-flex-height:nth-child(2) > div:nth-child(1) > span:nth-child(1)'),

View File

@ -17,7 +17,6 @@ const addCustomToken = async (f, account1, account2) => {
await f.waitUntilShowUp(screens.main.identicon)
const tab = await f.waitUntilShowUp(screens.main.tokens.menu)
await tab.click()
const addTokenButton = await f.waitUntilShowUp(screens.main.tokens.buttonAdd)
assert.equal(await addTokenButton.getText(), screens.main.tokens.buttonAddText)
await f.click(addTokenButton)

View File

@ -26,12 +26,13 @@ const importAccount = async (f) => {
const privateKeyBox = await f.waitUntilShowUp(importAccounts.fieldPrivateKey)
await privateKeyBox.sendKeys(addrPrivKey)
const button = await f.waitUntilShowUp(importAccounts.buttonImport)
await f.click(button)
assert.equal(await button.getText(), 'Import', 'button has incorrect name')
await f.click(button)
const menu = await f.waitUntilShowUp(account.menu)
await menu.click()
await f.waitUntilShowUp(account.label)
const label = (await f.driver.findElements(account.label))[0]
const labels = await f.driver.findElements(account.label)
const label = labels[0]
assert.equal(await label.getText(), 'IMPORTED')
await menu.click()
})

View File

@ -8,6 +8,7 @@ const importContractAccount = async (f, account1, getCreatedAccounts) => {
const proxyContract = '0x0518ac3db78eb326f42dbcfb4b2978e8059989a5'
const proxyABI = [{'constant': true, 'inputs': [], 'name': 'proxyOwner', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'version', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'version', 'type': 'string'}, {'name': 'implementation', 'type': 'address'}], 'name': 'upgradeTo', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'implementation', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'upgradeabilityOwner', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'version', 'type': 'string'}, {'name': 'implementation', 'type': 'address'}, {'name': 'data', 'type': 'bytes'}], 'name': 'upgradeToAndCall', 'outputs': [], 'payable': true, 'stateMutability': 'payable', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'newOwner', 'type': 'address'}], 'name': 'transferProxyOwnership', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'inputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'constructor'}, {'payable': true, 'stateMutability': 'payable', 'type': 'fallback'}, {'anonymous': false, 'inputs': [{'indexed': false, 'name': 'previousOwner', 'type': 'address'}, {'indexed': false, 'name': 'newOwner', 'type': 'address'}], 'name': 'ProxyOwnershipTransferred', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': false, 'name': 'version', 'type': 'string'}, {'indexed': true, 'name': 'implementation', 'type': 'address'}], 'name': 'Upgraded', 'type': 'event'}] // eslint-disable-line no-unused-vars
const joinedABI = [{'constant': true, 'inputs': [], 'name': 'proxyOwner', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'version', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'version', 'type': 'string'}, {'name': 'implementation', 'type': 'address'}], 'name': 'upgradeTo', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'implementation', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'upgradeabilityOwner', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'version', 'type': 'string'}, {'name': 'implementation', 'type': 'address'}, {'name': 'data', 'type': 'bytes'}], 'name': 'upgradeToAndCall', 'outputs': [], 'payable': true, 'stateMutability': 'payable', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'newOwner', 'type': 'address'}], 'name': 'transferProxyOwnership', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'inputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'constructor'}, {'payable': true, 'stateMutability': 'payable', 'type': 'fallback'}, {'anonymous': false, 'inputs': [{'indexed': false, 'name': 'previousOwner', 'type': 'address'}, {'indexed': false, 'name': 'newOwner', 'type': 'address'}], 'name': 'ProxyOwnershipTransferred', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': false, 'name': 'version', 'type': 'string'}, {'indexed': true, 'name': 'implementation', 'type': 'address'}], 'name': 'Upgraded', 'type': 'event'}, {'constant': true, 'inputs': [], 'name': 'desc', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'methodFromImplementation', 'outputs': [{'name': 'yep', 'type': 'bool'}], 'payable': false, 'stateMutability': 'pure', 'type': 'function'}]
describe('imports ABI of proxy and implementation together', async () => {
it('opens import account menu', async () => {
await f.setProvider(NETWORKS.SOKOL)
@ -40,6 +41,63 @@ const importContractAccount = async (f, account1, getCreatedAccounts) => {
console.log(abiClipboard)
assert.deepEqual(JSON.parse(abiClipboard), joinedABI, "ABI isn't fetched")
})
it("Click button 'Import', main screen opens", async () => {
const button = await f.waitUntilShowUp(screens.importAccounts.buttonImport)
await f.click(button)
const ident = await f.waitUntilShowUp(screens.main.identicon, 20)
assert.notEqual(ident, false, "main screen isn't opened")
})
})
describe("Check 3dots menu for 'Proxy' account", () => {
it('open 3dots menu', async () => {
const menu = await f.waitUntilShowUp(menus.dot.menu)
await menu.click()
await f.waitUntilShowUp(menus.dot.item)
const items = await f.driver.findElements(menus.dot.item)
assert.equal(items.length, 5, '3dot menu has incorrect number of items')
})
it('Check text of items', async () => {
const items = await f.driver.findElements(menus.dot.item)
assert.equal(await items[0].getText(), 'View on block explorer', '1st item has incorrect text')
assert.equal(await items[1].getText(), 'Show QR Code', '2nd item has incorrect text')
assert.equal(await items[2].getText(), 'Copy address to clipboard', '3d item has incorrect text')
assert.equal(await items[3].getText(), 'Copy ABI to clipboard', '4th item has incorrect text')
assert.equal(await items[4].getText(), 'Update implementation ABI', '5th item has incorrect text')
})
it("Click 'Update implementation ABI'", async () => {
const items = await f.driver.findElements(menus.dot.item)
await items[4].click()
const menu = await f.waitUntilShowUp(menus.dot.item, 20)
assert.equal(menu, false, "3dot menu wasn't closed")
})
})
describe("Remove imported 'Proxy' account", async () => {
it("Label 'PROXY' present", async () => {
const menu = await f.waitUntilShowUp(menus.account.menu)
await menu.click()
await f.delay(2000)
await f.waitUntilShowUp(menus.account.label)
const labels = await f.driver.findElements(menus.account.label)
const label = labels[1]
assert.equal(await label.getText(), 'PROXY', 'label incorrect')
})
it('Delete imported account', async () => {
await f.waitUntilShowUp(menus.account.delete)
const items = await f.driver.findElements(menus.account.delete)
await items[1].click()
const button = await f.waitUntilShowUp(screens.deleteImportedAccount.buttons.yes)
await button.click()
const buttonArrow = await f.waitUntilShowUp(screens.settings.buttons.arrow)
await buttonArrow.click()
const identicon = await f.waitUntilShowUp(screens.main.identicon)
assert.notEqual(identicon, false, 'main screen didn\'t opened')
})
})
})
@ -69,6 +127,7 @@ const importContractAccount = async (f, account1, getCreatedAccounts) => {
await f.delay(1000)
const field = await f.waitUntilShowUp(screens.importAccounts.selectArrow)
await field.click()
await f.delay(2000)
const item = await f.waitUntilShowUp(screens.importAccounts.itemContract)
await item.click()
})
@ -149,9 +208,9 @@ const importContractAccount = async (f, account1, getCreatedAccounts) => {
})
})
describe("Check 3dot menu for 'Contract' account", () => {
describe("Check 3dots menu for 'Contract' account", () => {
it('open 3dot menu', async () => {
it('open 3dots menu', async () => {
const menu = await f.waitUntilShowUp(menus.dot.menu)
await menu.click()
await f.waitUntilShowUp(menus.dot.item)
@ -162,9 +221,9 @@ const importContractAccount = async (f, account1, getCreatedAccounts) => {
it('Check text of items', async () => {
const items = await f.driver.findElements(menus.dot.item)
assert.equal(await items[0].getText(), 'View on block explorer', '1st item has incorrect text')
assert.equal(await items[1].getText(), 'Show QR Code', '2st item has incorrect text')
assert.equal(await items[2].getText(), 'Copy address to clipboard', '3st item has incorrect text')
assert.equal(await items[3].getText(), 'Copy ABI to clipboard', '4st item has incorrect text')
assert.equal(await items[1].getText(), 'Show QR Code', '2nd item has incorrect text')
assert.equal(await items[2].getText(), 'Copy address to clipboard', '3d item has incorrect text')
assert.equal(await items[3].getText(), 'Copy ABI to clipboard', '4th item has incorrect text')
})
it("Click 'Copy ABI'", async () => {
@ -737,15 +796,15 @@ const importContractAccount = async (f, account1, getCreatedAccounts) => {
assert.notEqual(buttonExecute, false, "contract's account hasn't opened")
})
// it("Button arrow leads to executor's account screen", async () => {
// assert.equal(await f.executeTransferMethod(0, account1), true, "can't execute the method 'transfer'")
// await f.delay(2000)
// const arrow = await f.waitUntilShowUp(elements.buttonArrow)
// await arrow.click()
// await f.delay(2000)
// const address = await f.waitUntilShowUp(screens.main.address)
// assert.equal((await address.getText()).toUpperCase(), getCreatedAccounts()[0], "executors account isn't opened")
// })
it("Button arrow leads to executor's account screen", async () => {
assert.equal(await f.executeTransferMethod(0, account1), true, "can't execute the method 'transfer'")
await f.delay(2000)
const arrow = await f.waitUntilShowUp(elements.buttonArrow)
await arrow.click()
await f.delay(2000)
const address = await f.waitUntilShowUp(screens.main.address)
assert.equal((await address.getText()).toUpperCase(), getCreatedAccounts()[0], "executors account isn't opened")
})
it('Switch to contract account ', async () => {
const accountMenu = await f.waitUntilShowUp(menus.account.menu)
@ -757,26 +816,26 @@ const importContractAccount = async (f, account1, getCreatedAccounts) => {
assert.equal((await address.getText()).toUpperCase(), contractSokol.toUpperCase(), "contract's account isn't opened")
})
// it("Confirm transaction: button 'Reject All' leads to contract's account screen", async () => {
// assert.equal(await f.executeTransferMethod(0, account1), true, "can't execute the method 'transfer'")
// const rejectAll = await f.waitUntilShowUp(screens.confirmTransaction.button.rejectAll)
// assert.equal(await rejectAll.getText(), 'Reject All', 'button has incorrect name')
// await rejectAll.click()
// await f.delay(2000)
// const address = await f.waitUntilShowUp(screens.main.address)
// assert.equal((await address.getText()).toUpperCase(), contractSokol.toUpperCase(), "contract account isn't opened")
// })
it("Confirm transaction: button 'Reject All' leads to contract's account screen", async () => {
assert.equal(await f.executeTransferMethod(0, account1), true, "can't execute the method 'transfer'")
const rejectAll = await f.waitUntilShowUp(screens.confirmTransaction.button.rejectAll)
assert.equal(await rejectAll.getText(), 'Reject All', 'button has incorrect name')
await rejectAll.click()
await f.delay(2000)
const address = await f.waitUntilShowUp(screens.main.address)
assert.equal((await address.getText()).toUpperCase(), contractSokol.toUpperCase(), "contract account isn't opened")
})
// it("Confirm transaction: button 'Submit' leads to contract's account screen", async () => {
// assert.equal(await f.executeTransferMethod(2, account1), true, "can't execute the method 'transfer'")
// await f.delay(2000)
// const button = await f.waitUntilShowUp(screens.confirmTransaction.button.submit)
// assert.equal(await button.getAttribute('value'), 'Submit', 'button has incorrect name')
// await button.click()
// await f.delay(2000)
// const address = await f.waitUntilShowUp(screens.main.address)
// assert.equal((await address.getText()).toUpperCase(), contractSokol.toUpperCase(), "contract account isn't opened")
// })
it("Confirm transaction: button 'Submit' leads to contract's account screen", async () => {
assert.equal(await f.executeTransferMethod(2, account1), true, "can't execute the method 'transfer'")
await f.delay(2000)
const button = await f.waitUntilShowUp(screens.confirmTransaction.button.submit)
assert.equal(await button.getAttribute('value'), 'Submit', 'button has incorrect name')
await button.click()
await f.delay(2000)
const address = await f.waitUntilShowUp(screens.main.address)
assert.equal((await address.getText()).toUpperCase(), contractSokol.toUpperCase(), "contract account isn't opened")
})
it("Label 'CONTRACT' present", async () => {
const menu = await f.waitUntilShowUp(menus.account.menu)