Merge pull request #332 from poanetwork/vb-fix-remove-acc
Return to main screen after removal of imported account
This commit is contained in:
commit
fd1e6c9c61
4
.babelrc
4
.babelrc
|
@ -1,4 +0,0 @@
|
||||||
{
|
|
||||||
"presets": [["env", { "targets": { "browsers": [">0.25%", "not ie 11", "not op_mini all"] } } ], "react", "stage-0"],
|
|
||||||
"plugins": ["transform-runtime", "transform-async-to-generator", "transform-class-properties"]
|
|
||||||
}
|
|
|
@ -337,12 +337,6 @@ jobs:
|
||||||
- run:
|
- run:
|
||||||
name: sentry sourcemaps upload
|
name: sentry sourcemaps upload
|
||||||
command: npm run sentry:publish
|
command: npm run sentry:publish
|
||||||
# - run:
|
|
||||||
# name: github gh-pages docs publish
|
|
||||||
# command: >
|
|
||||||
# git config user.name metamaskbot
|
|
||||||
# git config user.email admin@metamask.io
|
|
||||||
# gh-pages -d docs/jsdocs
|
|
||||||
|
|
||||||
test-unit:
|
test-unit:
|
||||||
docker:
|
docker:
|
||||||
|
|
|
@ -27,8 +27,8 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
"plugins": [
|
"plugins": [
|
||||||
|
"babel",
|
||||||
"mocha",
|
"mocha",
|
||||||
"chai",
|
|
||||||
"react",
|
"react",
|
||||||
"json"
|
"json"
|
||||||
],
|
],
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
## Current Master
|
## Current Master
|
||||||
|
|
||||||
|
- [#332](https://github.com/poanetwork/nifty-wallet/pull/332) - (Chore) Return to main screen from removal of imported account
|
||||||
- [#330](https://github.com/poanetwork/nifty-wallet/pull/330) - (Fix) Derive correct addresses for custom networks (RSK/ETC)
|
- [#330](https://github.com/poanetwork/nifty-wallet/pull/330) - (Fix) Derive correct addresses for custom networks (RSK/ETC)
|
||||||
- [#329](https://github.com/poanetwork/nifty-wallet/pull/329) - (Fix) Connect to unknown private network fix
|
- [#329](https://github.com/poanetwork/nifty-wallet/pull/329) - (Fix) Connect to unknown private network fix
|
||||||
- [#326](https://github.com/poanetwork/nifty-wallet/pull/326) - (Chore) HTTP2 RPC endpoints for POA and xDai
|
- [#326](https://github.com/poanetwork/nifty-wallet/pull/326) - (Chore) HTTP2 RPC endpoints for POA and xDai
|
||||||
|
|
|
@ -18,10 +18,6 @@
|
||||||
|
|
||||||
Uncompressed builds can be found in `/dist`, compressed builds can be found in `/builds` once they're built.
|
Uncompressed builds can be found in `/dist`, compressed builds can be found in `/builds` once they're built.
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
You can re-generate the docs locally by running `npm run doc`, and contributors can update the hosted docs by running `npm run publish-docs`.
|
|
||||||
|
|
||||||
### Running Tests
|
### Running Tests
|
||||||
|
|
||||||
Requires `mocha` installed. Run `npm install -g mocha`.
|
Requires `mocha` installed. Run `npm install -g mocha`.
|
||||||
|
|
|
@ -110,7 +110,7 @@ class ExtensionPlatform {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_subscribeToNotificationClicked = () => {
|
_subscribeToNotificationClicked () {
|
||||||
if (extension.notifications.onClicked.hasListener(this._viewOnExplorer)) {
|
if (extension.notifications.onClicked.hasListener(this._viewOnExplorer)) {
|
||||||
extension.notifications.onClicked.removeListener(this._viewOnExplorer)
|
extension.notifications.onClicked.removeListener(this._viewOnExplorer)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
module.exports = function (api) {
|
||||||
|
api.cache(false)
|
||||||
|
return {
|
||||||
|
presets: [
|
||||||
|
[
|
||||||
|
'@babel/preset-env',
|
||||||
|
{
|
||||||
|
targets: {
|
||||||
|
browsers: [
|
||||||
|
'chrome >= 58',
|
||||||
|
'firefox >= 56.2',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'@babel/preset-react',
|
||||||
|
],
|
||||||
|
plugins: [
|
||||||
|
'@babel/plugin-transform-runtime',
|
||||||
|
'@babel/plugin-proposal-class-properties',
|
||||||
|
'@babel/plugin-proposal-object-rest-spread',
|
||||||
|
'@babel/plugin-proposal-optional-chaining',
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,12 +14,12 @@ To use this class, simply take your form component (the component that renders `
|
||||||
|
|
||||||
You can see an example of this in use in `ui/app/first-time/restore-vault.js`.
|
You can see an example of this in use in `ui/app/first-time/restore-vault.js`.
|
||||||
|
|
||||||
Additionally, any field whose value should be persisted, should have a `persistentFormId` attribute, which needs to be assigned under a `dataset` key on the main `attributes` hash. For example:
|
Additionally, any field whose value should be persisted, should have a `persistentFormid` attribute, which needs to be assigned under a `dataset` key on the main `attributes` hash. For example:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
return h('textarea.twelve-word-phrase.letter-spacey', {
|
return h('textarea.twelve-word-phrase.letter-spacey', {
|
||||||
dataset: {
|
dataset: {
|
||||||
persistentFormId: 'wallet-seed',
|
persistentFormid: 'wallet-seed',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
|
@ -5,7 +5,19 @@ import classnames from 'classnames'
|
||||||
import LoadingScreen from './loading-screen'
|
import LoadingScreen from './loading-screen'
|
||||||
import {importNewAccount, hideWarning} from '../../../../ui/app/actions'
|
import {importNewAccount, hideWarning} from '../../../../ui/app/actions'
|
||||||
|
|
||||||
const Input = ({ label, placeholder, onChange, errorMessage, type = 'text' }) => (
|
class Input extends Component {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
label: PropTypes.string.isRequired,
|
||||||
|
placeholder: PropTypes.string.isRequired,
|
||||||
|
type: PropTypes.string.isRequired,
|
||||||
|
errorMessage: PropTypes.string.isRequired,
|
||||||
|
onChange: PropTypes.func.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const {label, type, placeholder, errorMessage, onChange} = this.props
|
||||||
|
return (
|
||||||
<div className="import-account__input-wrapper">
|
<div className="import-account__input-wrapper">
|
||||||
<div className="import-account__input-label">{label}</div>
|
<div className="import-account__input-label">{label}</div>
|
||||||
<input
|
<input
|
||||||
|
@ -19,14 +31,8 @@ const Input = ({ label, placeholder, onChange, errorMessage, type = 'text' }) =>
|
||||||
<div className="import-account__input-error-message">{errorMessage}</div>
|
<div className="import-account__input-error-message">{errorMessage}</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
Input.prototype.propTypes = {
|
|
||||||
label: PropTypes.string.isRequired,
|
|
||||||
placeholder: PropTypes.string.isRequired,
|
|
||||||
type: PropTypes.string.isRequired,
|
|
||||||
errorMessage: PropTypes.string.isRequired,
|
|
||||||
onChange: PropTypes.func.isRequired,
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class ImportAccountScreen extends Component {
|
class ImportAccountScreen extends Component {
|
||||||
static OPTIONS = {
|
static OPTIONS = {
|
||||||
|
|
|
@ -6,8 +6,6 @@ When you log in to Nifty Wallet, your current account's address is visible to ev
|
||||||
|
|
||||||
For your privacy, for now, please sign out of Nifty Wallet when you're done using a site.
|
For your privacy, for now, please sign out of Nifty Wallet when you're done using a site.
|
||||||
|
|
||||||
There have been several instances of high-profile legitimate websites such as BTC Manager and Games Workshop that have had their websites temporarily compromised. This involves showing a fake Nifty Wallet window on the page asking for user's seed phrases. Nifty Wallet will never open itself in this way.
|
|
||||||
|
|
||||||
## Related Links ##
|
## Related Links ##
|
||||||
|
|
||||||
**[Terms of Service](https://github.com/poanetwork/metamask-extension/wiki/Terms-of-Service)**
|
**[Terms of Service](https://github.com/poanetwork/metamask-extension/wiki/Terms-of-Service)**
|
|
@ -54,7 +54,7 @@ class AccountsDropdownItemView extends Component {
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
this.props.actions.showDeleteImportedAccount(identity)
|
this.props.actions.showDeleteImportedAccount(identity, keyring)
|
||||||
this.props.closeMenu()
|
this.props.closeMenu()
|
||||||
}}
|
}}
|
||||||
/>) : null
|
/>) : null
|
||||||
|
@ -157,7 +157,7 @@ const mapDispatchToProps = (dispatch) => {
|
||||||
return {
|
return {
|
||||||
actions: {
|
actions: {
|
||||||
showAccountDetail: (address) => dispatch(actions.showAccountDetail(address)),
|
showAccountDetail: (address) => dispatch(actions.showAccountDetail(address)),
|
||||||
showDeleteImportedAccount: (identity) => dispatch(actions.showDeleteImportedAccount(identity)),
|
showDeleteImportedAccount: (identity, keyring) => dispatch(actions.showDeleteImportedAccount(identity, keyring)),
|
||||||
getContract: (addr) => dispatch(actions.getContract(addr)),
|
getContract: (addr) => dispatch(actions.getContract(addr)),
|
||||||
connectHardwareAndUnlockAddress: (deviceName, hdPath, address) => {
|
connectHardwareAndUnlockAddress: (deviceName, hdPath, address) => {
|
||||||
return dispatch(actions.connectHardwareAndUnlockAddress(deviceName, hdPath, address))
|
return dispatch(actions.connectHardwareAndUnlockAddress(deviceName, hdPath, address))
|
||||||
|
|
|
@ -39,6 +39,7 @@ export default class AddTokenScreen extends Component {
|
||||||
address: PropTypes.string,
|
address: PropTypes.string,
|
||||||
dispatch: PropTypes.func,
|
dispatch: PropTypes.func,
|
||||||
network: PropTypes.string,
|
network: PropTypes.string,
|
||||||
|
addToken: PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
|
|
|
@ -17,6 +17,8 @@ class NetworksMenu extends Component {
|
||||||
provider: PropTypes.any.isRequired,
|
provider: PropTypes.any.isRequired,
|
||||||
frequentRpcList: PropTypes.array.isRequired,
|
frequentRpcList: PropTypes.array.isRequired,
|
||||||
isNetworkMenuOpen: PropTypes.bool,
|
isNetworkMenuOpen: PropTypes.bool,
|
||||||
|
setProviderType: PropTypes.function,
|
||||||
|
showDeleteRPC: PropTypes.function,
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
|
|
|
@ -14,6 +14,11 @@ import PropTypes from 'prop-types'
|
||||||
import { getMetaMaskAccounts } from '../../../ui/app/selectors'
|
import { getMetaMaskAccounts } from '../../../ui/app/selectors'
|
||||||
|
|
||||||
class BuyButtonSubview extends Component {
|
class BuyButtonSubview extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
isSubLoading: PropTypes.bool,
|
||||||
|
identity: PropTypes.object,
|
||||||
|
account: PropTypes.object,
|
||||||
|
}
|
||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<div style={{ width: '100%' }}>
|
<div style={{ width: '100%' }}>
|
||||||
|
|
|
@ -2,34 +2,58 @@ import ConfirmScreen from './confirm'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import actions from '../../../ui/app/actions'
|
import actions from '../../../ui/app/actions'
|
||||||
|
import { ifContractAcc } from '../util'
|
||||||
|
|
||||||
class DeleteImportedAccount extends ConfirmScreen {
|
class DeleteImportedAccount extends ConfirmScreen {
|
||||||
|
static propTypes = {
|
||||||
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
|
const withDescription = !ifContractAcc(this.props.keyring)
|
||||||
return (
|
return (
|
||||||
<ConfirmScreen
|
<ConfirmScreen
|
||||||
subtitle="Delete Imported Account"
|
subtitle="Delete Imported Account"
|
||||||
withDescription={true}
|
withDescription={withDescription}
|
||||||
description="Be sure, that you saved a private key or JSON keystore file of this account in a safe place. Otherwise, you will not be able to restore this account."
|
description="Be sure, that you saved a private key or JSON keystore file of this account in a safe place. Otherwise, you will not be able to restore this account."
|
||||||
question={`Are you sure to delete imported ${this.props.identity.name} (${this.props.identity.address})?`}
|
question={`Are you sure to delete imported ${this.props.identity.name} (${this.props.identity.address})?`}
|
||||||
onCancelClick={() => this.props.dispatch(actions.showConfigPage())}
|
onCancelClick={() => this.onCancelClick()}
|
||||||
onNoClick={() => this.props.dispatch(actions.showConfigPage())}
|
onNoClick={() => this.onNoClick()}
|
||||||
onYesClick={() => {
|
onYesClick={() => this.onYesClick()}
|
||||||
this.props.dispatch(actions.removeAccount(this.props.identity.address, this.props.metamask.network))
|
|
||||||
.then(() => {
|
|
||||||
this.props.dispatch(actions.showConfigPage())
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onCancelClick () {
|
||||||
|
this.props.showAccountsPage()
|
||||||
|
}
|
||||||
|
|
||||||
|
onNoClick () {
|
||||||
|
this.props.showAccountsPage()
|
||||||
|
}
|
||||||
|
|
||||||
|
onYesClick () {
|
||||||
|
this.props.removeAccount(this.props.identity.address, this.props.metamask.network)
|
||||||
|
.then(() => {
|
||||||
|
this.props.showAccountsPage()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
function mapStateToProps (state) {
|
||||||
return {
|
return {
|
||||||
metamask: state.metamask,
|
metamask: state.metamask,
|
||||||
identity: state.appState.identity,
|
identity: state.appState.identity,
|
||||||
|
keyring: state.appState.keyring,
|
||||||
provider: state.metamask.provider,
|
provider: state.metamask.provider,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(DeleteImportedAccount)
|
const mapDispatchToProps = dispatch => {
|
||||||
|
return {
|
||||||
|
removeAccount: (address, network) => dispatch(actions.removeAccount(address, network)),
|
||||||
|
showAccountsPage: () => dispatch(actions.showAccountsPage()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = connect(mapStateToProps, mapDispatchToProps)(DeleteImportedAccount)
|
||||||
|
|
|
@ -4,6 +4,11 @@ import PropTypes from 'prop-types'
|
||||||
import { DAI_CODE, POA_SOKOL_CODE, RSK_TESTNET_CODE, GOERLI_TESTNET_CODE } from '../../../app/scripts/controllers/network/enums'
|
import { DAI_CODE, POA_SOKOL_CODE, RSK_TESTNET_CODE, GOERLI_TESTNET_CODE } from '../../../app/scripts/controllers/network/enums'
|
||||||
|
|
||||||
class FiatValue extends Component {
|
class FiatValue extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
value: PropTypes.number,
|
||||||
|
valueStyle: PropTypes.object,
|
||||||
|
dimStyle: PropTypes.object,
|
||||||
|
}
|
||||||
render = () => {
|
render = () => {
|
||||||
const props = this.props
|
const props = this.props
|
||||||
let { conversionRate } = props
|
let { conversionRate } = props
|
||||||
|
|
|
@ -1,7 +1,15 @@
|
||||||
import React, {Component} from 'react'
|
import React, {Component} from 'react'
|
||||||
import AccountPanel from './account-panel'
|
import AccountPanel from './account-panel'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
export default class PendingMsgDetails extends Component {
|
export default class PendingMsgDetails extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
txData: PropTypes.object,
|
||||||
|
selectedAddress: PropTypes.string,
|
||||||
|
identities: PropTypes.object,
|
||||||
|
accounts: PropTypes.array,
|
||||||
|
imageifyIdenticons: PropTypes.any,
|
||||||
|
}
|
||||||
render () {
|
render () {
|
||||||
var state = this.props
|
var state = this.props
|
||||||
var msgData = state.txData
|
var msgData = state.txData
|
||||||
|
|
|
@ -1,7 +1,14 @@
|
||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import PendingTxDetails from './pending-msg-details'
|
import PendingTxDetails from './pending-msg-details'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
export default class PendingMsg extends Component {
|
export default class PendingMsg extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
txData: PropTypes.object,
|
||||||
|
cancelMessage: PropTypes.function,
|
||||||
|
signMessage: PropTypes.function,
|
||||||
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
var state = this.props
|
var state = this.props
|
||||||
var msgData = state.txData
|
var msgData = state.txData
|
||||||
|
|
|
@ -1,8 +1,17 @@
|
||||||
import React, {Component} from 'react'
|
import React, {Component} from 'react'
|
||||||
import AccountPanel from './account-panel'
|
import AccountPanel from './account-panel'
|
||||||
import BinaryRenderer from './binary-renderer'
|
import BinaryRenderer from './binary-renderer'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
export default class PendingMsgDetails extends Component {
|
export default class PendingMsgDetails extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
txData: PropTypes.object,
|
||||||
|
selectedAddress: PropTypes.string,
|
||||||
|
identities: PropTypes.object,
|
||||||
|
accounts: PropTypes.object,
|
||||||
|
imageifyIdenticons: PropTypes.object,
|
||||||
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
var state = this.props
|
var state = this.props
|
||||||
var msgData = state.txData
|
var msgData = state.txData
|
||||||
|
|
|
@ -1,7 +1,14 @@
|
||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import PendingTxDetails from './pending-personal-msg-details'
|
import PendingTxDetails from './pending-personal-msg-details'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
export default class PendingMsg extends Component {
|
export default class PendingMsg extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
txData: PropTypes.object,
|
||||||
|
cancelPersonalMessage: PropTypes.function,
|
||||||
|
signPersonalMessage: PropTypes.function,
|
||||||
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
var state = this.props
|
var state = this.props
|
||||||
var msgData = state.txData
|
var msgData = state.txData
|
||||||
|
|
|
@ -1,8 +1,17 @@
|
||||||
import React, {Component} from 'react'
|
import React, {Component} from 'react'
|
||||||
import AccountPanel from './account-panel'
|
import AccountPanel from './account-panel'
|
||||||
import TypedMessageRenderer from './typed-message-renderer'
|
import TypedMessageRenderer from './typed-message-renderer'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
export default class PendingMsgDetails extends Component {
|
export default class PendingMsgDetails extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
txData: PropTypes.object,
|
||||||
|
selectedAddress: PropTypes.string,
|
||||||
|
identities: PropTypes.object,
|
||||||
|
accounts: PropTypes.array,
|
||||||
|
imageifyIdenticons: PropTypes.any,
|
||||||
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
var state = this.props
|
var state = this.props
|
||||||
var msgData = state.txData
|
var msgData = state.txData
|
||||||
|
|
|
@ -1,7 +1,14 @@
|
||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import PendingTxDetails from './pending-typed-msg-details'
|
import PendingTxDetails from './pending-typed-msg-details'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
export default class PendingMsg extends Component {
|
export default class PendingMsg extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
txData: PropTypes.object,
|
||||||
|
cancelTypedMessage: PropTypes.function,
|
||||||
|
signTypedMessage: PropTypes.function,
|
||||||
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
var state = this.props
|
var state = this.props
|
||||||
var msgData = state.txData
|
var msgData = state.txData
|
||||||
|
|
|
@ -8,11 +8,10 @@ import ErrorComponent from '../error'
|
||||||
import ToastComponent from '../toast'
|
import ToastComponent from '../toast'
|
||||||
import Select from 'react-select'
|
import Select from 'react-select'
|
||||||
import actions from '../../../../ui/app/actions'
|
import actions from '../../../../ui/app/actions'
|
||||||
import { AbiCoder } from 'web3-eth-abi'
|
import abi from 'web3-eth-abi'
|
||||||
import Web3 from 'web3'
|
import Web3 from 'web3'
|
||||||
import copyToClipboard from 'copy-to-clipboard'
|
import copyToClipboard from 'copy-to-clipboard'
|
||||||
import CopyButton from '../copy/copy-button'
|
import CopyButton from '../copy/copy-button'
|
||||||
const abiEncoder = new AbiCoder()
|
|
||||||
|
|
||||||
class SendTransactionField extends Component {
|
class SendTransactionField extends Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
|
@ -430,7 +429,7 @@ class SendTransactionScreen extends PersistentForm {
|
||||||
const inputValuesArray = Object.keys(inputValues).map(key => inputValues[key])
|
const inputValuesArray = Object.keys(inputValues).map(key => inputValues[key])
|
||||||
let txData
|
let txData
|
||||||
try {
|
try {
|
||||||
txData = abiEncoder.encodeFunctionCall(methodABI, inputValuesArray)
|
txData = abi.encodeFunctionCall(methodABI, inputValuesArray)
|
||||||
this.props.hideWarning()
|
this.props.hideWarning()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.props.hideToast()
|
this.props.hideToast()
|
||||||
|
|
|
@ -5,8 +5,20 @@ import { addressSummary } from '../../util'
|
||||||
import EthBalance from '../eth-balance'
|
import EthBalance from '../eth-balance'
|
||||||
import TokenBalance from '../token-balance'
|
import TokenBalance from '../token-balance'
|
||||||
import { getMetaMaskAccounts } from '../../../../ui/app/selectors'
|
import { getMetaMaskAccounts } from '../../../../ui/app/selectors'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
class SendProfile extends Component {
|
class SendProfile extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
address: PropTypes.string,
|
||||||
|
account: PropTypes.object,
|
||||||
|
identity: PropTypes.object,
|
||||||
|
network: PropTypes.string,
|
||||||
|
conversionRate: PropTypes.number,
|
||||||
|
currentCurrency: PropTypes.string,
|
||||||
|
isToken: PropTypes.bool,
|
||||||
|
token: PropTypes.any,
|
||||||
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const props = this.props
|
const props = this.props
|
||||||
const {
|
const {
|
||||||
|
|
|
@ -103,7 +103,7 @@ SendTransactionScreen.prototype.render = function () {
|
||||||
marginRight: '6px',
|
marginRight: '6px',
|
||||||
},
|
},
|
||||||
dataset: {
|
dataset: {
|
||||||
persistentFormId: 'tx-amount',
|
persistentFormid: 'tx-amount',
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ SendTransactionScreen.prototype.render = function () {
|
||||||
resize: 'none',
|
resize: 'none',
|
||||||
},
|
},
|
||||||
dataset: {
|
dataset: {
|
||||||
persistentFormId: 'tx-data',
|
persistentFormid: 'tx-data',
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
|
|
|
@ -63,7 +63,7 @@ ShapeshiftForm.prototype.renderMain = function () {
|
||||||
list: 'coinList',
|
list: 'coinList',
|
||||||
autoFocus: true,
|
autoFocus: true,
|
||||||
dataset: {
|
dataset: {
|
||||||
persistentFormId: 'input-coin',
|
persistentFormid: 'input-coin',
|
||||||
},
|
},
|
||||||
style: {
|
style: {
|
||||||
boxSizing: 'border-box',
|
boxSizing: 'border-box',
|
||||||
|
@ -149,7 +149,7 @@ ShapeshiftForm.prototype.renderRefundAddressForCoin = function (coin) {
|
||||||
type: 'text',
|
type: 'text',
|
||||||
placeholder: `Your ${coin} Refund Address`,
|
placeholder: `Your ${coin} Refund Address`,
|
||||||
dataset: {
|
dataset: {
|
||||||
persistentFormId: 'refund-address',
|
persistentFormid: 'refund-address',
|
||||||
|
|
||||||
},
|
},
|
||||||
style: {
|
style: {
|
||||||
|
|
|
@ -1,8 +1,16 @@
|
||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import ReactTooltip from 'react-tooltip'
|
import ReactTooltip from 'react-tooltip'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
class Tooltip extends Component {
|
class Tooltip extends Component {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
position: PropTypes.any,
|
||||||
|
title: PropTypes.string,
|
||||||
|
id: PropTypes.any,
|
||||||
|
children: PropTypes.any,
|
||||||
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const props = this.props
|
const props = this.props
|
||||||
const { position, title, children, id } = props
|
const { position, title, children, id } = props
|
||||||
|
|
|
@ -38,6 +38,7 @@ class ConfigScreen extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
dispatch: PropTypes.func,
|
dispatch: PropTypes.func,
|
||||||
metamask: PropTypes.object,
|
metamask: PropTypes.object,
|
||||||
|
warning: PropTypes.string,
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
|
|
|
@ -70,7 +70,7 @@ RestoreVaultScreen.prototype.render = function () {
|
||||||
id: 'password-box',
|
id: 'password-box',
|
||||||
placeholder: 'New Password (min 8 chars)',
|
placeholder: 'New Password (min 8 chars)',
|
||||||
dataset: {
|
dataset: {
|
||||||
persistentFormId: 'password',
|
persistentFormid: 'password',
|
||||||
},
|
},
|
||||||
style: {
|
style: {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
|
@ -86,7 +86,7 @@ RestoreVaultScreen.prototype.render = function () {
|
||||||
placeholder: 'Confirm Password',
|
placeholder: 'Confirm Password',
|
||||||
onKeyPress: this.createOnEnter.bind(this),
|
onKeyPress: this.createOnEnter.bind(this),
|
||||||
dataset: {
|
dataset: {
|
||||||
persistentFormId: 'password-confirmation',
|
persistentFormid: 'password-confirmation',
|
||||||
},
|
},
|
||||||
style: {
|
style: {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
123
package.json
123
package.json
|
@ -8,7 +8,6 @@
|
||||||
"mascara": "gulp dev:mascara & node ./mascara/example/server",
|
"mascara": "gulp dev:mascara & node ./mascara/example/server",
|
||||||
"dist": "gulp dist",
|
"dist": "gulp dist",
|
||||||
"doc": "jsdoc -c development/tools/.jsdoc.json",
|
"doc": "jsdoc -c development/tools/.jsdoc.json",
|
||||||
"publish-docs": "gh-pages -d docs/jsdocs",
|
|
||||||
"test": "npm run test:unit && npm run test:integration && npm run lint",
|
"test": "npm run test:unit && npm run test:integration && npm run lint",
|
||||||
"watch:test:unit": "nodemon --exec \"npm run test:unit\" ./test ./app ./ui",
|
"watch:test:unit": "nodemon --exec \"npm run test:unit\" ./test ./app ./ui",
|
||||||
"test:unit": "cross-env METAMASK_ENV=test mocha --exit --require test/setup.js --recursive \"test/unit/**/*.js\"",
|
"test:unit": "cross-env METAMASK_ENV=test mocha --exit --require test/setup.js --recursive \"test/unit/**/*.js\"",
|
||||||
|
@ -58,43 +57,44 @@
|
||||||
{
|
{
|
||||||
"presets": [
|
"presets": [
|
||||||
[
|
[
|
||||||
"env",
|
"@babel/preset-env",
|
||||||
{
|
{
|
||||||
"browsers": [
|
"targets": {
|
||||||
">0.25%",
|
"browsers": [
|
||||||
"not ie 11",
|
"chrome >= 58",
|
||||||
"not op_mini all"
|
"firefox >= 56.2"
|
||||||
]
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"stage-0"
|
"@babel/preset-react"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"transform-class-properties"
|
"@babel/plugin-transform-runtime",
|
||||||
|
"@babel/plugin-proposal-class-properties",
|
||||||
|
"@babel/plugin-proposal-object-rest-spread",
|
||||||
|
"@babel/plugin-proposal-optional-chaining"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"reactify",
|
|
||||||
"brfs"
|
"brfs"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "^7.5.0",
|
"@babel/runtime": "^7.5.5",
|
||||||
"@material-ui/core": "^4.1.1",
|
"@material-ui/core": "^4.1.1",
|
||||||
"@zxing/library": "^0.8.0",
|
"@zxing/library": "^0.8.0",
|
||||||
"abi-decoder": "^1.0.9",
|
"abi-decoder": "^1.2.0",
|
||||||
"asmcrypto.js": "0.22.0",
|
"asmcrypto.js": "0.22.0",
|
||||||
"async": "^2.5.0",
|
"async": "^2.5.0",
|
||||||
"await-semaphore": "^0.1.1",
|
"await-semaphore": "^0.1.1",
|
||||||
"babel-runtime": "^6.23.0",
|
|
||||||
"bignumber.js": "^4.1.0",
|
"bignumber.js": "^4.1.0",
|
||||||
"bip39": "^2.2.0",
|
"bip39": "^2.2.0",
|
||||||
"bluebird": "^3.5.0",
|
"bluebird": "^3.5.0",
|
||||||
"bn.js": "^4.11.7",
|
"bn.js": "^4.11.7",
|
||||||
"browser-passworder": "^2.0.3",
|
"browser-passworder": "^2.0.3",
|
||||||
"browserify-derequire": "^0.9.4",
|
|
||||||
"browserify-unibabel": "^3.0.0",
|
"browserify-unibabel": "^3.0.0",
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
"clone": "^2.1.1",
|
"clone": "^2.1.1",
|
||||||
|
@ -107,8 +107,7 @@
|
||||||
"detectrtc": "^1.3.6",
|
"detectrtc": "^1.3.6",
|
||||||
"disc": "^1.3.2",
|
"disc": "^1.3.2",
|
||||||
"dnode": "^1.2.2",
|
"dnode": "^1.2.2",
|
||||||
"end-of-stream": "^1.1.0",
|
"end-of-stream": "^1.4.4",
|
||||||
"eslint-plugin-react": "^7.4.0",
|
|
||||||
"eth-block-tracker": "^4.1.0",
|
"eth-block-tracker": "^4.1.0",
|
||||||
"eth-contract-metadata": "github:MetaMask/eth-contract-metadata#master",
|
"eth-contract-metadata": "github:MetaMask/eth-contract-metadata#master",
|
||||||
"eth-ens-namehash": "^2.0.8",
|
"eth-ens-namehash": "^2.0.8",
|
||||||
|
@ -137,10 +136,7 @@
|
||||||
"extensionizer": "^1.0.1",
|
"extensionizer": "^1.0.1",
|
||||||
"fast-json-patch": "^2.0.4",
|
"fast-json-patch": "^2.0.4",
|
||||||
"fast-levenshtein": "^2.0.6",
|
"fast-levenshtein": "^2.0.6",
|
||||||
"file-loader": "^1.1.11",
|
|
||||||
"fuse.js": "^3.2.0",
|
"fuse.js": "^3.2.0",
|
||||||
"gulp": "github:gulpjs/gulp#v4.0.0",
|
|
||||||
"gulp-autoprefixer": "^5.0.0",
|
|
||||||
"human-standard-token-abi": "^2.0.0",
|
"human-standard-token-abi": "^2.0.0",
|
||||||
"idb-global": "^2.1.0",
|
"idb-global": "^2.1.0",
|
||||||
"iframe-stream": "^3.0.0",
|
"iframe-stream": "^3.0.0",
|
||||||
|
@ -159,7 +155,7 @@
|
||||||
"nifty-wallet-inpage-provider": "git+ssh://git@github.com/poanetwork/nifty-wallet-inpage-provider.git#1.2.3",
|
"nifty-wallet-inpage-provider": "git+ssh://git@github.com/poanetwork/nifty-wallet-inpage-provider.git#1.2.3",
|
||||||
"number-to-bn": "^1.7.0",
|
"number-to-bn": "^1.7.0",
|
||||||
"obj-multiplex": "^1.0.0",
|
"obj-multiplex": "^1.0.0",
|
||||||
"obs-store": "^3.0.2",
|
"obs-store": "^4.0.3",
|
||||||
"percentile": "^1.2.0",
|
"percentile": "^1.2.0",
|
||||||
"pify": "^3.0.0",
|
"pify": "^3.0.0",
|
||||||
"ping-pong-stream": "^1.0.0",
|
"ping-pong-stream": "^1.0.0",
|
||||||
|
@ -173,14 +169,13 @@
|
||||||
"qrcode-npm": "0.0.3",
|
"qrcode-npm": "0.0.3",
|
||||||
"ramda": "^0.24.1",
|
"ramda": "^0.24.1",
|
||||||
"raven-js": "^3.24.2",
|
"raven-js": "^3.24.2",
|
||||||
"react": "^16.8.6",
|
"react": "^16.12.0",
|
||||||
"react-dom": "^16.8.6",
|
"react-dom": "^16.12.0",
|
||||||
"react-hyperscript": "^3.0.0",
|
"react-hyperscript": "^3.0.0",
|
||||||
"react-inspector": "^2.3.0",
|
"react-inspector": "^2.3.0",
|
||||||
"react-markdown": "^3.0.0",
|
"react-markdown": "^3.0.0",
|
||||||
"react-media": "^1.8.0",
|
"react-media": "^1.8.0",
|
||||||
"react-modal": "^3.8.1",
|
"react-modal": "^3.8.1",
|
||||||
"react-redux": "^7.1.0",
|
|
||||||
"react-router-dom": "^4.2.2",
|
"react-router-dom": "^4.2.2",
|
||||||
"react-select": "^1.0.0",
|
"react-select": "^1.0.0",
|
||||||
"react-simple-file-input": "^2.0.0",
|
"react-simple-file-input": "^2.0.0",
|
||||||
|
@ -189,10 +184,9 @@
|
||||||
"react-tooltip": "^3.10.0",
|
"react-tooltip": "^3.10.0",
|
||||||
"react-transition-group": "^1.2.1",
|
"react-transition-group": "^1.2.1",
|
||||||
"react-trigger-change": "^1.0.2",
|
"react-trigger-change": "^1.0.2",
|
||||||
"reactify": "^1.1.1",
|
|
||||||
"readable-stream": "^2.3.3",
|
"readable-stream": "^2.3.3",
|
||||||
"recompose": "^0.25.0",
|
"recompose": "^0.25.0",
|
||||||
"redux": "^3.0.5",
|
"redux": "^4.0.5",
|
||||||
"redux-logger": "^3.0.6",
|
"redux-logger": "^3.0.6",
|
||||||
"redux-thunk": "^2.2.0",
|
"redux-thunk": "^2.2.0",
|
||||||
"request-promise": "^4.2.1",
|
"request-promise": "^4.2.1",
|
||||||
|
@ -207,31 +201,34 @@
|
||||||
"url-parse": "^1.4.4",
|
"url-parse": "^1.4.4",
|
||||||
"valid-url": "^1.0.9",
|
"valid-url": "^1.0.9",
|
||||||
"vreme": "^3.0.2",
|
"vreme": "^3.0.2",
|
||||||
"web3": "^0.20.1",
|
"web3": "^0.20.7",
|
||||||
"web3-eth-abi": "^1.0.0-beta.55",
|
"web3-eth-abi": "^1.2.6",
|
||||||
"web3-stream-provider": "^3.0.1",
|
"web3-stream-provider": "^4.0.0",
|
||||||
"xtend": "^4.0.1"
|
"xtend": "^4.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sentry/cli": "^1.30.3",
|
"@babel/core": "^7.5.5",
|
||||||
|
"@babel/plugin-proposal-class-properties": "^7.5.5",
|
||||||
|
"@babel/plugin-proposal-object-rest-spread": "^7.5.5",
|
||||||
|
"@babel/plugin-proposal-optional-chaining": "^7.8.3",
|
||||||
|
"@babel/plugin-transform-runtime": "^7.5.5",
|
||||||
|
"@babel/polyfill": "^7.6.0",
|
||||||
|
"@babel/preset-env": "^7.5.5",
|
||||||
|
"@babel/preset-react": "^7.0.0",
|
||||||
|
"@babel/register": "^7.5.5",
|
||||||
|
"@sentry/cli": "^1.49.0",
|
||||||
"@storybook/addon-info": "^5.3.14",
|
"@storybook/addon-info": "^5.3.14",
|
||||||
"@storybook/addon-knobs": "^3.4.2",
|
"@storybook/addon-knobs": "^5.3.14",
|
||||||
"@storybook/react": "^5.2.6",
|
"@storybook/react": "^5.3.14",
|
||||||
"addons-linter": "^1.22.0",
|
"addons-linter": "^1.22.0",
|
||||||
"babel-core": "^6.24.1",
|
"babel-eslint": "^10.0.2",
|
||||||
"babel-eslint": "^8.0.0",
|
"babel-loader": "^8.0.6",
|
||||||
"babel-plugin-transform-async-to-generator": "^6.24.1",
|
"babelify": "^10.0.0",
|
||||||
"babel-plugin-transform-runtime": "^6.23.0",
|
|
||||||
"babel-polyfill": "^6.23.0",
|
|
||||||
"babel-preset-env": "^1.7.0",
|
|
||||||
"babel-preset-react": "^6.24.1",
|
|
||||||
"babel-preset-stage-0": "^6.24.1",
|
|
||||||
"babel-register": "^6.7.2",
|
|
||||||
"babelify": "^8.0.0",
|
|
||||||
"brfs": "^1.6.1",
|
"brfs": "^1.6.1",
|
||||||
"browserify": "^16.2.3",
|
"browserify": "^16.2.3",
|
||||||
|
"browserify-derequire": "^1.0.1",
|
||||||
"chai": "^4.1.0",
|
"chai": "^4.1.0",
|
||||||
"chromedriver": "^2.41.0",
|
"chromedriver": "^79.0.0",
|
||||||
"clipboardy": "^1.2.3",
|
"clipboardy": "^1.2.3",
|
||||||
"compression": "^1.7.1",
|
"compression": "^1.7.1",
|
||||||
"coveralls": "^3.0.0",
|
"coveralls": "^3.0.0",
|
||||||
|
@ -239,37 +236,37 @@
|
||||||
"css-loader": "^3.2.0",
|
"css-loader": "^3.2.0",
|
||||||
"deep-freeze-strict": "^1.1.1",
|
"deep-freeze-strict": "^1.1.1",
|
||||||
"del": "^3.0.0",
|
"del": "^3.0.0",
|
||||||
"envify": "^4.0.0",
|
"envify": "^4.1.0",
|
||||||
"enzyme": "^3.4.4",
|
"enzyme": "^3.10.0",
|
||||||
"enzyme-adapter-react-16": "^1.14.0",
|
"enzyme-adapter-react-16": "^1.15.1",
|
||||||
"eslint-plugin-chai": "0.0.1",
|
"eslint": "^6.0.1",
|
||||||
|
"eslint-plugin-babel": "^5.3.0",
|
||||||
"eslint-plugin-json": "^1.2.0",
|
"eslint-plugin-json": "^1.2.0",
|
||||||
"eslint-plugin-mocha": "^5.0.0",
|
"eslint-plugin-mocha": "^6.2.2",
|
||||||
"eslint-plugin-react": "^7.4.0",
|
"eslint-plugin-react": "^7.18.3",
|
||||||
"eth-json-rpc-middleware": "^3.1.3",
|
"eth-json-rpc-middleware": "^3.1.3",
|
||||||
"expect": "^25.0.0",
|
"expect": "^25.0.0",
|
||||||
"fetch-mock": "^6.5.2",
|
"fetch-mock": "^6.5.2",
|
||||||
"file-loader": "^1.1.11",
|
"file-loader": "^1.1.11",
|
||||||
"fs-extra": "^6.0.1",
|
"fs-extra": "^6.0.1",
|
||||||
"fs-promise": "^2.0.3",
|
|
||||||
"ganache-cli": "^6.7.0",
|
"ganache-cli": "^6.7.0",
|
||||||
"ganache-core": "^2.10.2",
|
"ganache-core": "^2.10.2",
|
||||||
"geckodriver": "^1.19.1",
|
"geckodriver": "^1.19.1",
|
||||||
"gh-pages": "^1.2.0",
|
|
||||||
"gifencoder": "^1.1.0",
|
"gifencoder": "^1.1.0",
|
||||||
"gulp": "github:gulpjs/gulp#v4.0.0",
|
"gulp": "^4.0.2",
|
||||||
"gulp-babel": "^7.0.0",
|
"gulp-autoprefixer": "^5.0.0",
|
||||||
|
"gulp-babel": "^8.0.0",
|
||||||
"gulp-json-editor": "^2.2.1",
|
"gulp-json-editor": "^2.2.1",
|
||||||
"gulp-livereload": "^4.0.0",
|
"gulp-livereload": "^4.0.0",
|
||||||
"gulp-multi-process": "^1.3.1",
|
"gulp-multi-process": "^1.3.1",
|
||||||
"gulp-replace": "^0.6.1",
|
"gulp-replace": "^1.0.0",
|
||||||
"gulp-sourcemaps": "^2.6.0",
|
"gulp-sourcemaps": "^2.6.0",
|
||||||
"gulp-stylefmt": "^1.1.0",
|
"gulp-stylefmt": "^1.1.0",
|
||||||
"gulp-stylelint": "^7.0.0",
|
"gulp-stylelint": "^7.0.0",
|
||||||
"gulp-uglify": "^3.0.0",
|
"gulp-uglify": "^3.0.0",
|
||||||
"gulp-uglify-es": "^1.0.1",
|
"gulp-uglify-es": "^1.0.1",
|
||||||
"gulp-util": "^3.0.7",
|
"gulp-util": "^3.0.7",
|
||||||
"gulp-watch": "^5.0.0",
|
"gulp-watch": "^5.0.1",
|
||||||
"gulp-zip": "^4.0.0",
|
"gulp-zip": "^4.0.0",
|
||||||
"http-server": "^0.12.1",
|
"http-server": "^0.12.1",
|
||||||
"image-size": "^0.6.2",
|
"image-size": "^0.6.2",
|
||||||
|
@ -289,36 +286,38 @@
|
||||||
"mocha-jsdom": "^1.1.0",
|
"mocha-jsdom": "^1.1.0",
|
||||||
"mocha-sinon": "^2.0.0",
|
"mocha-sinon": "^2.0.0",
|
||||||
"nock": "^9.0.14",
|
"nock": "^9.0.14",
|
||||||
"node-sass": "^4.9.2",
|
"node-sass": "^4.12.0",
|
||||||
"nyc": "^14.1.1",
|
"nyc": "^15.0.0",
|
||||||
"path": "^0.12.7",
|
"path": "^0.12.7",
|
||||||
"png-file-stream": "^1.1.0",
|
"png-file-stream": "^1.1.0",
|
||||||
"prepend-file": "^1.3.1",
|
"prepend-file": "^1.3.1",
|
||||||
"prompt": "^1.0.0",
|
"prompt": "^1.0.0",
|
||||||
"proxyquire": "2.0.1",
|
"proxyquire": "^2.1.3",
|
||||||
"qs": "^6.2.0",
|
"qs": "^6.2.0",
|
||||||
"qunitjs": "^2.4.1",
|
"qunitjs": "^2.4.1",
|
||||||
"radgrad-jsdoc-template": "^1.1.3",
|
"radgrad-jsdoc-template": "^1.1.3",
|
||||||
"react-test-renderer": "^16.8.6",
|
"react-redux": "^7.2.0",
|
||||||
|
"react-test-renderer": "^16.12.0",
|
||||||
"react-testutils-additions": "^16.0.2",
|
"react-testutils-additions": "^16.0.2",
|
||||||
"redux-mock-store": "^1.5.3",
|
"redux-mock-store": "^1.5.4",
|
||||||
"redux-test-utils": "^0.2.2",
|
"redux-test-utils": "^0.2.2",
|
||||||
"resolve-url-loader": "^2.3.0",
|
"resolve-url-loader": "^2.3.0",
|
||||||
"rimraf": "^2.6.2",
|
"rimraf": "^2.6.2",
|
||||||
"sass-loader": "^7.0.1",
|
"sass-loader": "^7.0.1",
|
||||||
"selenium-webdriver": "^4.0.0-alpha.4",
|
"selenium-webdriver": "^4.0.0-alpha.5",
|
||||||
"shell-parallel": "^1.0.3",
|
"shell-parallel": "^1.0.3",
|
||||||
"sinon": "^5.0.0",
|
"sinon": "^5.0.0",
|
||||||
"source-map": "^0.7.2",
|
"source-map": "^0.7.2",
|
||||||
"static-server": "^2.2.1",
|
"static-server": "^2.2.1",
|
||||||
"style-loader": "^0.21.0",
|
"style-loader": "^0.21.0",
|
||||||
|
"stylelint": "^9.10.1",
|
||||||
"stylelint-config-standard": "^18.2.0",
|
"stylelint-config-standard": "^18.2.0",
|
||||||
"tape": "^4.5.1",
|
"tape": "^4.5.1",
|
||||||
"testem": "^2.8.0",
|
"testem": "^2.16.0",
|
||||||
"through2": "^2.0.3",
|
"through2": "^2.0.3",
|
||||||
"vinyl-buffer": "^1.0.1",
|
"vinyl-buffer": "^1.0.1",
|
||||||
"vinyl-source-stream": "^2.0.0",
|
"vinyl-source-stream": "^2.0.0",
|
||||||
"watchify": "^3.11.0"
|
"watchify": "^3.11.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "12.15.0",
|
"node": "12.15.0",
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -35,14 +35,14 @@ module.exports = {
|
||||||
account2: By.css('#app-content > div > div.full-width > div.full-width > div > div:nth-child(2) > span > div > div > span > div > li:nth-child(3) > span'),
|
account2: By.css('#app-content > div > div.full-width > div.full-width > div > div:nth-child(2) > span > div > div > span > div > li:nth-child(3) > span'),
|
||||||
account3: By.css('#app-content > div > div.full-width > div.full-width > div > div:nth-child(2) > span > div > div > span > div > li:nth-child(4) > span'),
|
account3: By.css('#app-content > div > div.full-width > div.full-width > div > div:nth-child(2) > span > div > div > span > div > li:nth-child(4) > span'),
|
||||||
account4: By.css('#app-content > div > div.full-width > div.full-width > div > div:nth-child(2) > span > div > div > span > div > li:nth-child(5) > span'),
|
account4: By.css('#app-content > div > div.full-width > div.full-width > div > div:nth-child(2) > span > div > div > span > div > li:nth-child(5) > span'),
|
||||||
menu: By.css('#app-content > div > div.full-width > div.full-width > div > div:nth-child(2) > span > div'),
|
menu: By.css('#app-content > div > div.full-width > div.full-width > div > div.app-bar-right-menus-section > span > div'),
|
||||||
|
delete1: By.xpath('//*[@id="app-content"]/div/div[1]/div[1]/div/div[2]/span/div/div/span/div/li[5]/div[3]'),
|
||||||
delete: By.className('remove'),
|
delete: By.className('remove'),
|
||||||
createAccount: By.css('#app-content > div > div.full-width > div.full-width > div > div:nth-child(2) > span > div > div > span > div > li:nth-child(3) > span'),
|
createAccount: By.css('#app-content > div > div.full-width > div.full-width > div > div:nth-child(2) > span > div > div > span > div > li:nth-child(3) > span'),
|
||||||
// import: By.css('#app-content > div > div.full-width > div.full-width > div > div:nth-child(2) > span > div > div > span > div > li:nth-child(5) > span'),
|
// import: By.css('#app-content > div > div.full-width > div.full-width > div > div:nth-child(2) > span > div > div > span > div > li:nth-child(5) > span'),
|
||||||
import: By.css('li.dropdown-menu-item:nth-child(4) > span:nth-child(1)'),
|
import: By.css('li.dropdown-menu-item:nth-child(4) > span:nth-child(1)'),
|
||||||
// import22: By.css('#app-content > div > div.full-width > div.full-width > div > div.app-bar-right-menus-section > span > div > div > span > div > li:nth-child(4) > span'),
|
// import22: By.css('#app-content > div > div.full-width > div.full-width > div > div.app-bar-right-menus-section > span > div > div > span > div > li:nth-child(4) > span'),
|
||||||
import2: By.css('#app-content > div > div.full-width > div.full-width > div > div:nth-child(2) > span > div > div > span > div > li:nth-child(5)'),
|
import2: By.css('#app-content > div > div.full-width > div.full-width > div > div:nth-child(2) > span > div > div > span > div > li:nth-child(5)'),
|
||||||
// import3: By.css('#app-content > div > div.full-width > div.full-width > div > div.app-bar-right-menus-section > span > div > div > span > div > li:nth-child(5) > span'),
|
|
||||||
label: By.className('keyring-label'),
|
label: By.className('keyring-label'),
|
||||||
},
|
},
|
||||||
dot: {
|
dot: {
|
||||||
|
@ -240,11 +240,11 @@ module.exports = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
deleteImportedAccount: {
|
deleteImportedAccount: {
|
||||||
title: By.css('#app-content > div > div.app-primary.from-left > div > div.section-title.flex-row.flex-center > h2'),
|
title: By.className('page-subtitle'),
|
||||||
titleText: 'Delete Imported Account',
|
titleText: 'Delete Imported Account',
|
||||||
buttons: {
|
buttons: {
|
||||||
no: By.css('#app-content > div > div.app-primary.from-left > div > div.flex-row.flex-right > button.btn-violet'),
|
no: By.css('#app-content > div > div.app-primary.from-left > div > div.flex-row.flex-right > button.btn-violet'),
|
||||||
yes: By.css('div.flex-row:nth-child(4) > button:nth-child(2)'),
|
yes: By.css('#app-content > div > div.app-primary.from-right > div > div.flex-row.flex-right > button:nth-child(2)'),
|
||||||
arrow: By.className('fa fa-arrow-left fa-lg cursor-pointer'),
|
arrow: By.className('fa fa-arrow-left fa-lg cursor-pointer'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -289,6 +289,7 @@ module.exports = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
main: {
|
main: {
|
||||||
|
container: By.css('#app-content > div > div.app-primary.from-right > div'),
|
||||||
accountAddress: By.xpath('//*[@id="app-content"]/div/div[2]/div/div/div[1]/flex-column/div[2]/div/span'),
|
accountAddress: By.xpath('//*[@id="app-content"]/div/div[2]/div/div/div[1]/flex-column/div[2]/div/span'),
|
||||||
identicon: By.className('identicon-wrapper select-none'),
|
identicon: By.className('identicon-wrapper select-none'),
|
||||||
fieldAccountName: By.className('sizing-input'),
|
fieldAccountName: By.className('sizing-input'),
|
||||||
|
|
|
@ -6,10 +6,10 @@ const account2 = '0xd7b7AFeCa35e32594e29504771aC847E2a803742'
|
||||||
const testsFolder = './test-cases'
|
const testsFolder = './test-cases'
|
||||||
const setup = require(`${testsFolder}/setup.spec`)
|
const setup = require(`${testsFolder}/setup.spec`)
|
||||||
const login = require(`${testsFolder}/login.spec`)
|
const login = require(`${testsFolder}/login.spec`)
|
||||||
const { accountCreation, getCreatedAccounts } = require(`${testsFolder}/account-creation.spec`)
|
const { accountCreation } = require(`${testsFolder}/account-creation.spec`)
|
||||||
const connectHDWallet = require(`${testsFolder}/connect-hd-wallet.spec`)
|
const connectHDWallet = require(`${testsFolder}/connect-hd-wallet.spec`)
|
||||||
const importAccount = require(`${testsFolder}/import-account.spec`)
|
const importAccount = require(`${testsFolder}/import-account.spec`)
|
||||||
const importContractAccount = require(`${testsFolder}/import-contract-account.spec`)
|
// const importContractAccount = require(`${testsFolder}/import-contract-account.spec`)
|
||||||
const deleteImportedAccount = require(`${testsFolder}/delete-imported-account.spec`)
|
const deleteImportedAccount = require(`${testsFolder}/delete-imported-account.spec`)
|
||||||
const signData = require(`${testsFolder}/sign-data.spec`)
|
const signData = require(`${testsFolder}/sign-data.spec`)
|
||||||
const exportPrivateKey = require(`${testsFolder}/export-private-key.spec`)
|
const exportPrivateKey = require(`${testsFolder}/export-private-key.spec`)
|
||||||
|
@ -20,6 +20,7 @@ const checkEmittedEvents = require(`${testsFolder}/check-emitted-events.spec`)
|
||||||
const changePassword = require(`${testsFolder}/change-password.spec`)
|
const changePassword = require(`${testsFolder}/change-password.spec`)
|
||||||
// const addTokenFromSearch = require(`${testsFolder}/add-token-search.spec`)
|
// const addTokenFromSearch = require(`${testsFolder}/add-token-search.spec`)
|
||||||
const customRPC = require(`${testsFolder}/custom-rpc.spec`)
|
const customRPC = require(`${testsFolder}/custom-rpc.spec`)
|
||||||
|
const { buildWebDriver } = require(`./webdriver`)
|
||||||
|
|
||||||
describe('Metamask popup page', async function () {
|
describe('Metamask popup page', async function () {
|
||||||
|
|
||||||
|
@ -35,13 +36,13 @@ describe('Metamask popup page', async function () {
|
||||||
|
|
||||||
before(async function () {
|
before(async function () {
|
||||||
if (process.env.SELENIUM_BROWSER === 'chrome') {
|
if (process.env.SELENIUM_BROWSER === 'chrome') {
|
||||||
const extPath = path.resolve('dist/chrome')
|
const { driver: chromeDriver, extensionId: _extensionId } = await buildWebDriver({responsive: false})
|
||||||
driver = await Func.buildChromeWebDriver(extPath)
|
const extensionUrl = chromeDriver.extensionUrl
|
||||||
|
driver = chromeDriver.driver
|
||||||
|
extensionId = _extensionId
|
||||||
f.driver = driver
|
f.driver = driver
|
||||||
extensionId = await f.getExtensionIdChrome()
|
|
||||||
f.extensionId = extensionId
|
f.extensionId = extensionId
|
||||||
await driver.get(`chrome-extension://${extensionId}/popup.html`)
|
await f.driver.get(extensionUrl)
|
||||||
|
|
||||||
} else if (process.env.SELENIUM_BROWSER === 'firefox') {
|
} else if (process.env.SELENIUM_BROWSER === 'firefox') {
|
||||||
const extPath = path.resolve('dist/firefox')
|
const extPath = path.resolve('dist/firefox')
|
||||||
driver = await Func.buildFirefoxWebdriver()
|
driver = await Func.buildFirefoxWebdriver()
|
||||||
|
@ -74,7 +75,7 @@ describe('Metamask popup page', async function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
after(async function () {
|
after(async function () {
|
||||||
await driver.quit()
|
await f.driver.quit()
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('Setup', async () => {
|
describe('Setup', async () => {
|
||||||
|
@ -97,9 +98,9 @@ describe('Metamask popup page', async function () {
|
||||||
await importAccount(f)
|
await importAccount(f)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('Import Contract account', async () => {
|
// describe('Import Contract account', async () => {
|
||||||
await importContractAccount(f, account1, getCreatedAccounts)
|
// await importContractAccount(f, account1, getCreatedAccounts)
|
||||||
})
|
// })
|
||||||
|
|
||||||
describe('Delete Imported Account', async () => {
|
describe('Delete Imported Account', async () => {
|
||||||
await deleteImportedAccount(f)
|
await deleteImportedAccount(f)
|
||||||
|
|
|
@ -15,9 +15,10 @@ const checkEmittedEvents = async (f, account1, account2) => {
|
||||||
const item = await f.waitUntilShowUp(menus.account.account2)
|
const item = await f.waitUntilShowUp(menus.account.account2)
|
||||||
await item.click()
|
await item.click()
|
||||||
}
|
}
|
||||||
|
await f.driver.navigate().refresh()
|
||||||
|
|
||||||
const balanceField = await f.waitUntilShowUp(screens.main.balance)
|
const balanceField = await f.waitUntilShowUp(screens.main.balance)
|
||||||
await f.delay(2000)
|
await f.delay(5000)
|
||||||
const balance = await balanceField.getText()
|
const balance = await balanceField.getText()
|
||||||
console.log('Account = ' + account)
|
console.log('Account = ' + account)
|
||||||
console.log('Balance = ' + balance)
|
console.log('Balance = ' + balance)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
const assert = require('assert')
|
const assert = require('assert')
|
||||||
const { menus, screens } = require('../elements')
|
const { menus, screens } = require('../elements')
|
||||||
const { account } = menus
|
const { account } = menus
|
||||||
const { deleteImportedAccount: deleteImportedAccountScr, settings } = screens
|
const { deleteImportedAccount: deleteImportedAccountScr, main } = screens
|
||||||
|
|
||||||
const deleteImportedAccount = async (f) => {
|
const deleteImportedAccount = async (f) => {
|
||||||
it('Open delete imported account screen', async function () {
|
it('Open delete imported account screen', async function () {
|
||||||
|
@ -9,6 +9,7 @@ const deleteImportedAccount = async (f) => {
|
||||||
await menu.click()
|
await menu.click()
|
||||||
const item = await f.waitUntilShowUp(account.delete)
|
const item = await f.waitUntilShowUp(account.delete)
|
||||||
await item.click()
|
await item.click()
|
||||||
|
await f.delay(2000)
|
||||||
const deleteImportedAccountTitle = await f.waitUntilShowUp(deleteImportedAccountScr.title)
|
const deleteImportedAccountTitle = await f.waitUntilShowUp(deleteImportedAccountScr.title)
|
||||||
assert.equal(await deleteImportedAccountTitle.getText(), deleteImportedAccountScr.titleText)
|
assert.equal(await deleteImportedAccountTitle.getText(), deleteImportedAccountScr.titleText)
|
||||||
})
|
})
|
||||||
|
@ -17,8 +18,7 @@ const deleteImportedAccount = async (f) => {
|
||||||
const button = await f.waitUntilShowUp(deleteImportedAccountScr.buttons.no)
|
const button = await f.waitUntilShowUp(deleteImportedAccountScr.buttons.no)
|
||||||
assert.equal(await button.getText(), 'No', 'button has incorrect name')
|
assert.equal(await button.getText(), 'No', 'button has incorrect name')
|
||||||
await f.click(button)
|
await f.click(button)
|
||||||
const settingsTitle = await f.waitUntilShowUp(settings.title)
|
await f.driver.findElements(main.container)
|
||||||
assert.equal(await settingsTitle.getText(), 'Settings')
|
|
||||||
// check, that imported account still exists
|
// check, that imported account still exists
|
||||||
const menu = await f.waitUntilShowUp(account.menu)
|
const menu = await f.waitUntilShowUp(account.menu)
|
||||||
await menu.click()
|
await menu.click()
|
||||||
|
@ -43,8 +43,7 @@ const deleteImportedAccount = async (f) => {
|
||||||
assert.equal(await button.getText(), 'Yes', 'button has incorrect name')
|
assert.equal(await button.getText(), 'Yes', 'button has incorrect name')
|
||||||
await f.click(button)
|
await f.click(button)
|
||||||
await f.delay(2000)
|
await f.delay(2000)
|
||||||
const settingsTitle = await f.waitUntilShowUp(settings.title)
|
await f.driver.findElements(main.container)
|
||||||
assert.equal(await settingsTitle.getText(), 'Settings', "screen 'Settings' has incorrect title")
|
|
||||||
// check, that imported account is removed
|
// check, that imported account is removed
|
||||||
const menu = await f.waitUntilShowUp(account.menu)
|
const menu = await f.waitUntilShowUp(account.menu)
|
||||||
await menu.click()
|
await menu.click()
|
||||||
|
|
|
@ -13,7 +13,7 @@ const addrPrivKey = '76bd0ced0a47055bb5d060e1ae4a8cb3ece658d668823e250dae6e79d3a
|
||||||
const importAccount = async (f) => {
|
const importAccount = async (f) => {
|
||||||
it('Open import account menu', async () => {
|
it('Open import account menu', async () => {
|
||||||
await f.setProvider(NETWORKS.POA)
|
await f.setProvider(NETWORKS.POA)
|
||||||
await f.delay(2000)
|
await f.delay(5000)
|
||||||
const menu = await f.waitUntilShowUp(account.menu)
|
const menu = await f.waitUntilShowUp(account.menu)
|
||||||
await menu.click()
|
await menu.click()
|
||||||
await f.delay(2000)
|
await f.delay(2000)
|
||||||
|
@ -39,9 +39,9 @@ const importAccount = async (f) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Auto-detect tokens for POA ', async () => {
|
it('Auto-detect tokens for POA ', async () => {
|
||||||
// await setProvider(NETWORKS.POA)
|
|
||||||
const tab = await f.waitUntilShowUp(tokensEl.menu)
|
const tab = await f.waitUntilShowUp(tokensEl.menu)
|
||||||
await tab.click()
|
await tab.click()
|
||||||
|
await f.delay(15000)
|
||||||
const balance = await f.waitUntilShowUp(tokensEl.balance)
|
const balance = await f.waitUntilShowUp(tokensEl.balance)
|
||||||
console.log(await balance.getText())
|
console.log(await balance.getText())
|
||||||
assert.equal(await balance.getText(), '1 DOPR', 'token isnt\' auto-detected')
|
assert.equal(await balance.getText(), '1 DOPR', 'token isnt\' auto-detected')
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
const assert = require('assert')
|
const assert = require('assert')
|
||||||
const clipboardy = require('clipboardy')
|
const clipboardy = require('clipboardy')
|
||||||
const { menus, screens, elements, NETWORKS } = require('../elements')
|
const { menus, screens, elements, NETWORKS } = require('../elements')
|
||||||
|
const { main } = screens
|
||||||
let abiClipboard
|
let abiClipboard
|
||||||
|
|
||||||
const importContractAccount = async (f, account1, getCreatedAccounts) => {
|
const importContractAccount = async (f, account1, getCreatedAccounts) => {
|
||||||
|
@ -36,16 +37,16 @@ const importContractAccount = async (f, account1, getCreatedAccounts) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('ABI of Proxy + Implementation is fetched and matches the pattern', async () => {
|
it('ABI of Proxy + Implementation is fetched and matches the pattern', async () => {
|
||||||
await f.delay(5000)
|
await f.delay(10000)
|
||||||
const field = await f.waitUntilShowUp(screens.importAccounts.contractABI)
|
const field = await f.waitUntilShowUp(screens.importAccounts.contractABI)
|
||||||
abiClipboard = await field.getText()
|
abiClipboard = await field.getText()
|
||||||
console.log(abiClipboard)
|
|
||||||
assert.deepEqual(JSON.parse(abiClipboard), joinedABI, "ABI isn't fetched")
|
assert.deepEqual(JSON.parse(abiClipboard), joinedABI, "ABI isn't fetched")
|
||||||
})
|
})
|
||||||
|
|
||||||
it("Click button 'Import', main screen opens", async () => {
|
it("Click button 'Import', main screen opens", async () => {
|
||||||
const button = await f.waitUntilShowUp(screens.importAccounts.buttonImport)
|
const button = await f.waitUntilShowUp(screens.importAccounts.buttonImport)
|
||||||
await f.click(button)
|
await f.click(button)
|
||||||
|
await f.delay(7000)
|
||||||
const ident = await f.waitUntilShowUp(screens.main.identicon, 20)
|
const ident = await f.waitUntilShowUp(screens.main.identicon, 20)
|
||||||
assert.notEqual(ident, false, "main screen isn't opened")
|
assert.notEqual(ident, false, "main screen isn't opened")
|
||||||
})
|
})
|
||||||
|
@ -93,13 +94,11 @@ const importContractAccount = async (f, account1, getCreatedAccounts) => {
|
||||||
assert.equal(text1, 'PROXY', 'label incorrect')
|
assert.equal(text1, 'PROXY', 'label incorrect')
|
||||||
})
|
})
|
||||||
it('Delete imported account', async () => {
|
it('Delete imported account', async () => {
|
||||||
await f.waitUntilShowUp(menus.account.delete)
|
const deleteButton = await f.waitUntilShowUp(menus.account.delete)
|
||||||
const items = await f.driver.findElements(menus.account.delete)
|
await deleteButton.click()
|
||||||
await items[accountPosition].click()
|
const yesButton = await f.waitUntilShowUp(screens.deleteImportedAccount.buttons.yes)
|
||||||
const button = await f.waitUntilShowUp(screens.deleteImportedAccount.buttons.yes)
|
await yesButton.click()
|
||||||
await button.click()
|
await f.driver.findElements(main.container)
|
||||||
const buttonArrow = await f.waitUntilShowUp(screens.settings.buttons.arrow)
|
|
||||||
await buttonArrow.click()
|
|
||||||
const identicon = await f.waitUntilShowUp(screens.main.identicon)
|
const identicon = await f.waitUntilShowUp(screens.main.identicon)
|
||||||
assert.notEqual(identicon, false, 'main screen didn\'t opened')
|
assert.notEqual(identicon, false, 'main screen didn\'t opened')
|
||||||
})
|
})
|
||||||
|
@ -117,17 +116,12 @@ const importContractAccount = async (f, account1, getCreatedAccounts) => {
|
||||||
await f.setProvider(NETWORKS.ROPSTEN)
|
await f.setProvider(NETWORKS.ROPSTEN)
|
||||||
const menu = await f.waitUntilShowUp(menus.account.menu)
|
const menu = await f.waitUntilShowUp(menus.account.menu)
|
||||||
await menu.click()
|
await menu.click()
|
||||||
const item = await f.waitUntilShowUp(menus.account.import2)
|
const importItem = await f.waitUntilShowUp(menus.account.import2)
|
||||||
await item.click()
|
await importItem.click()
|
||||||
const importAccountTitle = await f.waitUntilShowUp(screens.importAccounts.title)
|
const importAccountTitle = await f.waitUntilShowUp(screens.importAccounts.title)
|
||||||
assert.equal(await importAccountTitle.getText(), screens.importAccounts.textTitle)
|
assert.equal(await importAccountTitle.getText(), screens.importAccounts.textTitle)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("Warning's text is correct", async () => {
|
|
||||||
const field = await f.waitUntilShowUp(screens.importAccounts.warning)
|
|
||||||
assert.equal(await field.getText(), 'Imported accounts will not be associated with your originally created Nifty Wallet account seedphrase.', "incorrect warning's text")
|
|
||||||
})
|
|
||||||
|
|
||||||
it("Select type 'Contract'", async () => {
|
it("Select type 'Contract'", async () => {
|
||||||
await f.delay(1000)
|
await f.delay(1000)
|
||||||
const field = await f.waitUntilShowUp(screens.importAccounts.selectArrow)
|
const field = await f.waitUntilShowUp(screens.importAccounts.selectArrow)
|
||||||
|
@ -208,6 +202,7 @@ const importContractAccount = async (f, account1, getCreatedAccounts) => {
|
||||||
it("Click button 'Import', main screen opens", async () => {
|
it("Click button 'Import', main screen opens", async () => {
|
||||||
const button = await f.waitUntilShowUp(screens.importAccounts.buttonImport)
|
const button = await f.waitUntilShowUp(screens.importAccounts.buttonImport)
|
||||||
await f.click(button)
|
await f.click(button)
|
||||||
|
await f.delay(5000)
|
||||||
const ident = await f.waitUntilShowUp(screens.main.identicon, 20)
|
const ident = await f.waitUntilShowUp(screens.main.identicon, 20)
|
||||||
assert.notEqual(ident, false, "main screen isn't opened")
|
assert.notEqual(ident, false, "main screen isn't opened")
|
||||||
})
|
})
|
||||||
|
@ -865,8 +860,7 @@ const importContractAccount = async (f, account1, getCreatedAccounts) => {
|
||||||
await items[1].click()
|
await items[1].click()
|
||||||
const button = await f.waitUntilShowUp(screens.deleteImportedAccount.buttons.yes)
|
const button = await f.waitUntilShowUp(screens.deleteImportedAccount.buttons.yes)
|
||||||
await button.click()
|
await button.click()
|
||||||
const buttonArrow = await f.waitUntilShowUp(screens.settings.buttons.arrow)
|
await f.driver.findElements(main.container)
|
||||||
await buttonArrow.click()
|
|
||||||
const identicon = await f.waitUntilShowUp(screens.main.identicon)
|
const identicon = await f.waitUntilShowUp(screens.main.identicon)
|
||||||
assert.notEqual(identicon, false, 'main screen didn\'t opened')
|
assert.notEqual(identicon, false, 'main screen didn\'t opened')
|
||||||
})
|
})
|
||||||
|
|
|
@ -11,7 +11,7 @@ const login = async (f, password) => {
|
||||||
await f.delay(5000)
|
await f.delay(5000)
|
||||||
const terms = await f.waitUntilShowUp(screens.TOU.agreement, 900)
|
const terms = await f.waitUntilShowUp(screens.TOU.agreement, 900)
|
||||||
const text = await terms.getText()
|
const text = await terms.getText()
|
||||||
assert.equal(text.length > 400, true, 'agreement is too short')
|
assert.equal(text.length > 100, true, 'agreement is too short')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('screen \'Terms of Use\' has correct title', async () => {
|
it('screen \'Terms of Use\' has correct title', async () => {
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
const { Builder } = require('selenium-webdriver')
|
||||||
|
const chrome = require('selenium-webdriver/chrome')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper around a {@code WebDriver} instance exposing Chrome-specific functionality
|
||||||
|
*/
|
||||||
|
class ChromeDriver {
|
||||||
|
static async build ({ extensionPath, responsive, port }) {
|
||||||
|
const args = [
|
||||||
|
`load-extension=${extensionPath}`,
|
||||||
|
]
|
||||||
|
if (responsive) {
|
||||||
|
args.push('--auto-open-devtools-for-tabs')
|
||||||
|
}
|
||||||
|
const options = new chrome.Options()
|
||||||
|
.addArguments(args)
|
||||||
|
const builder = new Builder()
|
||||||
|
.forBrowser('chrome')
|
||||||
|
.setChromeOptions(options)
|
||||||
|
if (port) {
|
||||||
|
const service = new chrome.ServiceBuilder()
|
||||||
|
.setPort(port)
|
||||||
|
builder.setChromeService(service)
|
||||||
|
}
|
||||||
|
const driver = builder.build()
|
||||||
|
const chromeDriver = new ChromeDriver(driver)
|
||||||
|
const extensionId = await chromeDriver.getExtensionIdByName('Nifty Wallet')
|
||||||
|
|
||||||
|
return {
|
||||||
|
driver,
|
||||||
|
extensionUrl: `chrome-extension://${extensionId}/popup.html`,
|
||||||
|
extensionId: extensionId,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @param {!ThenableWebDriver} driver - a {@code WebDriver} instance
|
||||||
|
*/
|
||||||
|
constructor (driver) {
|
||||||
|
this._driver = driver
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the extension ID for the given extension name
|
||||||
|
* @param {string} extensionName - the extension name
|
||||||
|
* @returns {Promise<string|undefined>} - the extension ID
|
||||||
|
*/
|
||||||
|
async getExtensionIdByName (extensionName) {
|
||||||
|
await this._driver.get('chrome://extensions')
|
||||||
|
return await this._driver.executeScript(`
|
||||||
|
const extensions = document.querySelector("extensions-manager").shadowRoot
|
||||||
|
.querySelector("extensions-item-list").shadowRoot
|
||||||
|
.querySelectorAll("extensions-item")
|
||||||
|
|
||||||
|
for (let i = 0; i < extensions.length; i++) {
|
||||||
|
const extension = extensions[i].shadowRoot
|
||||||
|
const name = extension.querySelector('#name').textContent
|
||||||
|
if (name === "${extensionName}") {
|
||||||
|
return extensions[i].getAttribute("id")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ChromeDriver
|
|
@ -0,0 +1,189 @@
|
||||||
|
const { promises: fs } = require('fs')
|
||||||
|
const { until, error: webdriverError } = require('selenium-webdriver')
|
||||||
|
const { strict: assert } = require('assert')
|
||||||
|
|
||||||
|
class Driver {
|
||||||
|
/**
|
||||||
|
* @param {!ThenableWebDriver} driver - A {@code WebDriver} instance
|
||||||
|
* @param {string} browser - The type of browser this driver is controlling
|
||||||
|
* @param {number} timeout
|
||||||
|
*/
|
||||||
|
constructor (driver, browser, extensionUrl, timeout = 10000) {
|
||||||
|
this.driver = driver
|
||||||
|
this.browser = browser
|
||||||
|
this.extensionUrl = extensionUrl
|
||||||
|
this.timeout = timeout
|
||||||
|
}
|
||||||
|
|
||||||
|
async delay (time) {
|
||||||
|
await new Promise(resolve => setTimeout(resolve, time))
|
||||||
|
}
|
||||||
|
|
||||||
|
async wait (condition, timeout = this.timeout) {
|
||||||
|
await this.driver.wait(condition, timeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
async quit () {
|
||||||
|
await this.driver.quit()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Element interactions
|
||||||
|
|
||||||
|
async findElement (locator) {
|
||||||
|
return await this.driver.wait(until.elementLocated(locator), this.timeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
async findVisibleElement (locator) {
|
||||||
|
const element = await this.findElement(locator)
|
||||||
|
await this.driver.wait(until.elementIsVisible(element), this.timeout)
|
||||||
|
return element
|
||||||
|
}
|
||||||
|
|
||||||
|
async findClickableElement (locator) {
|
||||||
|
const element = await this.findElement(locator)
|
||||||
|
await Promise.all([
|
||||||
|
this.driver.wait(until.elementIsVisible(element), this.timeout),
|
||||||
|
this.driver.wait(until.elementIsEnabled(element), this.timeout),
|
||||||
|
])
|
||||||
|
return element
|
||||||
|
}
|
||||||
|
|
||||||
|
async findElements (locator) {
|
||||||
|
return await this.driver.wait(until.elementsLocated(locator), this.timeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
async findClickableElements (locator) {
|
||||||
|
const elements = await this.findElements(locator)
|
||||||
|
await Promise.all(elements
|
||||||
|
.reduce((acc, element) => {
|
||||||
|
acc.push(
|
||||||
|
this.driver.wait(until.elementIsVisible(element), this.timeout),
|
||||||
|
this.driver.wait(until.elementIsEnabled(element), this.timeout),
|
||||||
|
)
|
||||||
|
return acc
|
||||||
|
}, [])
|
||||||
|
)
|
||||||
|
return elements
|
||||||
|
}
|
||||||
|
|
||||||
|
async clickElement (locator) {
|
||||||
|
const element = await this.findClickableElement(locator)
|
||||||
|
await element.click()
|
||||||
|
}
|
||||||
|
|
||||||
|
async scrollToElement (element) {
|
||||||
|
await this.driver.executeScript('arguments[0].scrollIntoView(true)', element)
|
||||||
|
}
|
||||||
|
|
||||||
|
async assertElementNotPresent (locator) {
|
||||||
|
let dataTab
|
||||||
|
try {
|
||||||
|
dataTab = await this.findElement(locator)
|
||||||
|
} catch (err) {
|
||||||
|
assert(err instanceof webdriverError.NoSuchElementError || err instanceof webdriverError.TimeoutError)
|
||||||
|
}
|
||||||
|
assert.ok(!dataTab, 'Found element that should not be present')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Navigation
|
||||||
|
|
||||||
|
async navigate (page = Driver.PAGES.HOME) {
|
||||||
|
return await this.driver.get(`${this.extensionUrl}/${page}.html`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Window management
|
||||||
|
|
||||||
|
async openNewPage (url) {
|
||||||
|
const newHandle = await this.driver.switchTo().newWindow()
|
||||||
|
await this.driver.get(url)
|
||||||
|
return newHandle
|
||||||
|
}
|
||||||
|
|
||||||
|
async switchToWindow (handle) {
|
||||||
|
await this.driver.switchTo().window(handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAllWindowHandles () {
|
||||||
|
return await this.driver.getAllWindowHandles()
|
||||||
|
}
|
||||||
|
|
||||||
|
async waitUntilXWindowHandles (x, delayStep = 1000, timeout = 5000) {
|
||||||
|
let timeElapsed = 0
|
||||||
|
while (timeElapsed <= timeout) {
|
||||||
|
const windowHandles = await this.driver.getAllWindowHandles()
|
||||||
|
if (windowHandles.length === x) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
await this.delay(delayStep)
|
||||||
|
timeElapsed += delayStep
|
||||||
|
}
|
||||||
|
throw new Error('waitUntilXWindowHandles timed out polling window handles')
|
||||||
|
}
|
||||||
|
|
||||||
|
async switchToWindowWithTitle (title, windowHandles) {
|
||||||
|
if (!windowHandles) {
|
||||||
|
windowHandles = await this.driver.getAllWindowHandles()
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const handle of windowHandles) {
|
||||||
|
await this.driver.switchTo().window(handle)
|
||||||
|
const handleTitle = await this.driver.getTitle()
|
||||||
|
if (handleTitle === title) {
|
||||||
|
return handle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('No window with title: ' + title)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes all windows except those in the given list of exceptions
|
||||||
|
* @param {Array<string>} exceptions - The list of window handle exceptions
|
||||||
|
* @param {Array} [windowHandles] - The full list of window handles
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async closeAllWindowHandlesExcept (exceptions, windowHandles) {
|
||||||
|
windowHandles = windowHandles || await this.driver.getAllWindowHandles()
|
||||||
|
|
||||||
|
for (const handle of windowHandles) {
|
||||||
|
if (!exceptions.includes(handle)) {
|
||||||
|
await this.driver.switchTo().window(handle)
|
||||||
|
await this.delay(1000)
|
||||||
|
await this.driver.close()
|
||||||
|
await this.delay(1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error handling
|
||||||
|
|
||||||
|
async verboseReportOnFailure (test) {
|
||||||
|
const artifactDir = `./test-artifacts/${this.browser}/${test.title}`
|
||||||
|
const filepathBase = `${artifactDir}/test-failure`
|
||||||
|
await fs.mkdir(artifactDir, { recursive: true })
|
||||||
|
const screenshot = await this.driver.takeScreenshot()
|
||||||
|
await fs.writeFile(`${filepathBase}-screenshot.png`, screenshot, { encoding: 'base64' })
|
||||||
|
const htmlSource = await this.driver.getPageSource()
|
||||||
|
await fs.writeFile(`${filepathBase}-dom.html`, htmlSource)
|
||||||
|
}
|
||||||
|
|
||||||
|
async checkBrowserForConsoleErrors () {
|
||||||
|
const ignoredLogTypes = ['WARNING']
|
||||||
|
const ignoredErrorMessages = [
|
||||||
|
// Third-party Favicon 404s show up as errors
|
||||||
|
'favicon.ico - Failed to load resource: the server responded with a status of 404 (Not Found)',
|
||||||
|
]
|
||||||
|
const browserLogs = await this.driver.manage().logs().get('browser')
|
||||||
|
const errorEntries = browserLogs.filter(entry => !ignoredLogTypes.includes(entry.level.toString()))
|
||||||
|
const errorObjects = errorEntries.map(entry => entry.toJSON())
|
||||||
|
return errorObjects.filter(entry => !ignoredErrorMessages.some(message => entry.message.includes(message)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Driver.PAGES = {
|
||||||
|
HOME: 'home',
|
||||||
|
NOTIFICATION: 'notification',
|
||||||
|
POPUP: 'popup',
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Driver
|
|
@ -0,0 +1,103 @@
|
||||||
|
const fs = require('fs')
|
||||||
|
const os = require('os')
|
||||||
|
const path = require('path')
|
||||||
|
const { Builder, By, until } = require('selenium-webdriver')
|
||||||
|
const firefox = require('selenium-webdriver/firefox')
|
||||||
|
const { Command } = require('selenium-webdriver/lib/command')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The prefix for temporary Firefox profiles. All Firefox profiles used for e2e tests
|
||||||
|
* will be created as random directories inside this.
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
const TEMP_PROFILE_PATH_PREFIX = path.join(os.tmpdir(), 'MetaMask-Fx-Profile')
|
||||||
|
|
||||||
|
const GeckoDriverCommand = {
|
||||||
|
INSTALL_ADDON: 'install addon',
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper around a {@code WebDriver} instance exposing Firefox-specific functionality
|
||||||
|
*/
|
||||||
|
class FirefoxDriver {
|
||||||
|
/**
|
||||||
|
* Builds a {@link FirefoxDriver} instance
|
||||||
|
* @param {{extensionPath: string}} options - the options for the build
|
||||||
|
* @returns {Promise<{driver: !ThenableWebDriver, extensionUrl: string, extensionId: string}>}
|
||||||
|
*/
|
||||||
|
static async build ({ extensionPath, responsive, port }) {
|
||||||
|
const templateProfile = fs.mkdtempSync(TEMP_PROFILE_PATH_PREFIX)
|
||||||
|
const options = new firefox.Options()
|
||||||
|
.setProfile(templateProfile)
|
||||||
|
const builder = new Builder()
|
||||||
|
.forBrowser('firefox')
|
||||||
|
.setFirefoxOptions(options)
|
||||||
|
if (port) {
|
||||||
|
const service = new firefox.ServiceBuilder()
|
||||||
|
.setPort(port)
|
||||||
|
builder.setFirefoxService(service)
|
||||||
|
}
|
||||||
|
const driver = builder.build()
|
||||||
|
const fxDriver = new FirefoxDriver(driver)
|
||||||
|
|
||||||
|
await fxDriver.init()
|
||||||
|
|
||||||
|
const extensionId = await fxDriver.installExtension(extensionPath)
|
||||||
|
const internalExtensionId = await fxDriver.getInternalId()
|
||||||
|
|
||||||
|
if (responsive) {
|
||||||
|
await driver.manage().window().setRect({ width: 320, height: 600 })
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
driver,
|
||||||
|
extensionId,
|
||||||
|
extensionUrl: `moz-extension://${internalExtensionId}`,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @param {!ThenableWebDriver} driver - a {@code WebDriver} instance
|
||||||
|
*/
|
||||||
|
constructor (driver) {
|
||||||
|
this._driver = driver
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the driver
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async init () {
|
||||||
|
await this._driver.getExecutor()
|
||||||
|
.defineCommand(
|
||||||
|
GeckoDriverCommand.INSTALL_ADDON,
|
||||||
|
'POST',
|
||||||
|
'/session/:sessionId/moz/addon/install',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installs the extension at the given path
|
||||||
|
* @param {string} addonPath - the path to the unpacked extension or XPI
|
||||||
|
* @returns {Promise<string>} - the extension ID
|
||||||
|
*/
|
||||||
|
async installExtension (addonPath) {
|
||||||
|
const cmd = new Command(GeckoDriverCommand.INSTALL_ADDON)
|
||||||
|
.setParameter('path', path.resolve(addonPath))
|
||||||
|
.setParameter('temporary', true)
|
||||||
|
|
||||||
|
return await this._driver.execute(cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Internal UUID for the given extension
|
||||||
|
* @returns {Promise<string>} - the Internal UUID for the given extension
|
||||||
|
*/
|
||||||
|
async getInternalId () {
|
||||||
|
await this._driver.get('about:debugging#addons')
|
||||||
|
return await this._driver.wait(until.elementLocated(By.xpath('//dl/div[contains(., \'Internal UUID\')]/dd')), 1000).getText()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = FirefoxDriver
|
|
@ -0,0 +1,69 @@
|
||||||
|
const { Browser } = require('selenium-webdriver')
|
||||||
|
const Driver = require('./driver')
|
||||||
|
const ChromeDriver = require('./chrome')
|
||||||
|
const FirefoxDriver = require('./firefox')
|
||||||
|
const fetchMockResponses = require('../../data/fetch-mocks.json')
|
||||||
|
|
||||||
|
async function buildWebDriver ({ responsive, port } = {}) {
|
||||||
|
const browser = process.env.SELENIUM_BROWSER
|
||||||
|
const extensionPath = `dist/${browser}`
|
||||||
|
|
||||||
|
const { driver: seleniumDriver, extensionId, extensionUrl } = await buildBrowserWebDriver(browser, { extensionPath, responsive, port })
|
||||||
|
setupFetchMocking(seleniumDriver)
|
||||||
|
const driver = new Driver(seleniumDriver, browser, extensionUrl)
|
||||||
|
|
||||||
|
return {
|
||||||
|
driver,
|
||||||
|
extensionId,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function buildBrowserWebDriver (browser, webDriverOptions) {
|
||||||
|
switch (browser) {
|
||||||
|
case Browser.CHROME: {
|
||||||
|
return await ChromeDriver.build(webDriverOptions)
|
||||||
|
}
|
||||||
|
case Browser.FIREFOX: {
|
||||||
|
return await FirefoxDriver.build(webDriverOptions)
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
throw new Error(`Unrecognized browser: ${browser}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setupFetchMocking (driver) {
|
||||||
|
// define fetchMocking script, to be evaluated in the browser
|
||||||
|
function fetchMocking (fetchMockResponses) {
|
||||||
|
window.origFetch = window.fetch.bind(window)
|
||||||
|
window.fetch = async (...args) => {
|
||||||
|
const url = args[0]
|
||||||
|
if (url === 'https://ethgasstation.info/json/ethgasAPI.json') {
|
||||||
|
return { json: async () => clone(fetchMockResponses.ethGasBasic) }
|
||||||
|
} else if (url === 'https://ethgasstation.info/json/predictTable.json') {
|
||||||
|
return { json: async () => clone(fetchMockResponses.ethGasPredictTable) }
|
||||||
|
} else if (url.match(/chromeextensionmm/)) {
|
||||||
|
return { json: async () => clone(fetchMockResponses.metametrics) }
|
||||||
|
}
|
||||||
|
return window.origFetch(...args)
|
||||||
|
}
|
||||||
|
if (window.chrome && window.chrome.webRequest) {
|
||||||
|
window.chrome.webRequest.onBeforeRequest.addListener(cancelInfuraRequest, { urls: ['https://*.infura.io/*'] }, ['blocking'])
|
||||||
|
}
|
||||||
|
function cancelInfuraRequest (requestDetails) {
|
||||||
|
console.log(`fetchMocking - Canceling request: "${requestDetails.url}"`)
|
||||||
|
return { cancel: true }
|
||||||
|
}
|
||||||
|
function clone (obj) {
|
||||||
|
return JSON.parse(JSON.stringify(obj))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// fetchMockResponses are parsed last minute to ensure that objects are uniquely instantiated
|
||||||
|
const fetchMockResponsesJson = JSON.stringify(fetchMockResponses)
|
||||||
|
// eval the fetchMocking script in the browser
|
||||||
|
await driver.executeScript(`(${fetchMocking})(${fetchMockResponsesJson})`)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
buildWebDriver,
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
require('babel-register')({
|
require('@babel/register')({
|
||||||
ignore: name => name.includes('node_modules') && !name.includes('obs-store'),
|
ignore: [(name) => name.includes('node_modules') && !name.includes('obs-store')],
|
||||||
})
|
})
|
||||||
|
|
||||||
require('./helper')
|
require('./helper')
|
||||||
|
|
|
@ -830,6 +830,7 @@ function reduceApp (state, action) {
|
||||||
context: appState.currentView.context,
|
context: appState.currentView.context,
|
||||||
},
|
},
|
||||||
identity: action.identity,
|
identity: action.identity,
|
||||||
|
keyring: action.keyring,
|
||||||
})
|
})
|
||||||
|
|
||||||
case actions.CONFIRM_CHANGE_PASSWORD:
|
case actions.CONFIRM_CHANGE_PASSWORD:
|
||||||
|
|
Loading…
Reference in New Issue