1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00

Merge remote-tracking branch 'origin/develop' into sync-master

* origin/develop: (107 commits)
  Clear Account Details in AppState (#9238)
  Permit all-caps addresses (#9227)
  Send web3 usage metrics once per origin/property (#9237)
  Fix import/no-extraneous-dependencies issues (#9232)
  Remove unused buyEth fn from bg (#9236)
  Fix max-statements-per-line issues (#9218)
  Consolidate ESLint config files (#9231)
  Delete page-container.component.test.js (#9229)
  Tidy up getAccountLink (#9223)
  Tidy ConnectHardwareForm#checkIfUnlocked (#9224)
  Fix require-unicode-regexp issues (#9212)
  Fix no-negated-condition issues (#9222)
  Fix no-empty-function issues (#9216)
  Fix import/extensions issues (#9217)
  Dedupe glob-parent versions (#9220)
  Fix no-template-curly-in-string issues (#9221)
  Fix no-process-exit issues (#9219)
  Fix prefer-rest-params issues (#9215)
  Fix no-prototype-builtins issues (#9213)
  Fix no-nested-ternary issues (#9214)
  ...
This commit is contained in:
Mark Stacey 2020-08-14 20:32:32 -03:00
commit 52fd72feac
326 changed files with 2503 additions and 3527 deletions

View File

@ -3,14 +3,9 @@
node_modules/** node_modules/**
dist/** dist/**
builds/** builds/**
test-builds/** test-*/**
docs/** docs/**
coverage/ coverage/
app/scripts/lib/extension-instance.js
app/scripts/chromereload.js app/scripts/chromereload.js
app/vendor/** app/vendor/**
ui/lib/blockies.js
package-lock.json

View File

@ -44,8 +44,32 @@ module.exports = {
/* TODO: Remove these when upgrading to `@metamask/eslint-config@2` */ /* TODO: Remove these when upgrading to `@metamask/eslint-config@2` */
'array-callback-return': 'error', 'array-callback-return': 'error',
'callback-return': 'error', 'callback-return': 'error',
'consistent-return': 'error',
'global-require': 'error', 'global-require': 'error',
'guard-for-in': 'error', 'guard-for-in': 'error',
'implicit-arrow-linebreak': 'error',
'import/extensions': ['error', 'never', { 'json': 'always' }],
'import/no-extraneous-dependencies': 'error',
'max-statements-per-line': ['error', { 'max': 1 }],
'no-case-declarations': 'error',
'no-constant-condition': 'error',
'no-dupe-else-if': 'error',
'no-empty': 'error',
'no-empty-function': 'error',
'no-eq-null': 'error',
'no-global-assign': 'error',
'no-loop-func': 'error',
'no-negated-condition': 'error',
'no-nested-ternary': 'error',
'no-plusplus': ['error', { 'allowForLoopAfterthoughts': true }],
'no-process-exit': 'error',
'no-prototype-builtins': 'error',
'no-template-curly-in-string': 'error',
'no-useless-catch': 'error',
'no-useless-concat': 'error',
'prefer-rest-params': 'error',
'prefer-spread': 'error',
'require-unicode-regexp': 'error',
/* End v2 rules */ /* End v2 rules */
'arrow-parens': 'error', 'arrow-parens': 'error',
'no-tabs': 'error', 'no-tabs': 'error',
@ -95,11 +119,22 @@ module.exports = {
'logical': 'parens-new-line', 'logical': 'parens-new-line',
'prop': 'parens-new-line', 'prop': 'parens-new-line',
}], }],
'no-invalid-this': 'off',
'babel/no-invalid-this': 'error',
'babel/semi': ['error', 'never'], 'babel/semi': ['error', 'never'],
'mocha/no-setup-in-describe': 'off', 'mocha/no-setup-in-describe': 'off',
}, },
overrides: [{ overrides: [{
files: [
'test/e2e/**/*.js',
],
rules: {
'mocha/no-hooks-for-single-case': 'off',
},
}, {
files: [ files: [
'app/scripts/migrations/*.js', 'app/scripts/migrations/*.js',
'*.stories.js', '*.stories.js',
@ -114,6 +149,24 @@ module.exports = {
rules: { rules: {
'global-require': 'off', 'global-require': 'off',
}, },
}, {
files: [
'test/**/*-test.js',
'test/**/*.spec.js',
],
rules: {
// Mocha will re-assign `this` in a test context
'babel/no-invalid-this': 'off',
},
}, {
files: [
'development/**/*.js',
'test/e2e/benchmark.js',
'test/helper.js',
],
rules: {
'no-process-exit': 'off',
},
}], }],
settings: { settings: {

View File

@ -1,5 +1,5 @@
module.exports = { module.exports = {
stories: ['../ui/app/components/**/*.stories.js'], stories: ['../ui/app/**/*.stories.js'],
addons: [ addons: [
'@storybook/addon-knobs', '@storybook/addon-knobs',
'@storybook/addon-actions', '@storybook/addon-actions',

View File

@ -29,11 +29,13 @@ module.exports = {
], ],
}, },
plugins: [ plugins: [
new CopyWebpackPlugin([ new CopyWebpackPlugin({
{ patterns: [
from: path.join('node_modules', '@fortawesome', 'fontawesome-free', 'webfonts'), {
to: path.join('fonts', 'fontawesome'), from: path.join('node_modules', '@fortawesome', 'fontawesome-free', 'webfonts'),
}, to: path.join('fonts', 'fontawesome'),
]), },
],
}),
], ],
} }

Binary file not shown.

Binary file not shown.

View File

@ -8,7 +8,7 @@ const accountImporter = {
importAccount (strategy, args) { importAccount (strategy, args) {
try { try {
const importer = this.strategies[strategy] const importer = this.strategies[strategy]
const privateKeyHex = importer.apply(null, args) const privateKeyHex = importer(...args)
return Promise.resolve(privateKeyHex) return Promise.resolve(privateKeyHex)
} catch (e) { } catch (e) {
return Promise.reject(e) return Promise.reject(e)

View File

@ -26,7 +26,7 @@ import Migrator from './lib/migrator'
import migrations from './migrations' import migrations from './migrations'
import PortStream from 'extension-port-stream' import PortStream from 'extension-port-stream'
import createStreamSink from './lib/createStreamSink' import createStreamSink from './lib/createStreamSink'
import NotificationManager from './lib/notification-manager.js' import NotificationManager from './lib/notification-manager'
import MetamaskController from './metamask-controller' import MetamaskController from './metamask-controller'
import rawFirstTimeState from './first-time-state' import rawFirstTimeState from './first-time-state'
import setupSentry from './lib/setupSentry' import setupSentry from './lib/setupSentry'
@ -327,7 +327,7 @@ function setupController (initState, initLangCode) {
const isMetaMaskInternalProcess = metamaskInternalProcessHash[processName] const isMetaMaskInternalProcess = metamaskInternalProcessHash[processName]
if (metamaskBlockedPorts.includes(remotePort.name)) { if (metamaskBlockedPorts.includes(remotePort.name)) {
return false return
} }
if (isMetaMaskInternalProcess) { if (isMetaMaskInternalProcess) {

View File

@ -155,8 +155,8 @@ function doctypeCheck () {
*/ */
function suffixCheck () { function suffixCheck () {
const prohibitedTypes = [ const prohibitedTypes = [
/\.xml$/, /\.xml$/u,
/\.pdf$/, /\.pdf$/u,
] ]
const currentUrl = window.location.pathname const currentUrl = window.location.pathname
for (let i = 0; i < prohibitedTypes.length; i++) { for (let i = 0; i < prohibitedTypes.length; i++) {
@ -202,7 +202,7 @@ function blockedDomainCheck () {
let currentRegex let currentRegex
for (let i = 0; i < blockedDomains.length; i++) { for (let i = 0; i < blockedDomains.length; i++) {
const blockedDomain = blockedDomains[i].replace('.', '\\.') const blockedDomain = blockedDomains[i].replace('.', '\\.')
currentRegex = new RegExp(`(?:https?:\\/\\/)(?:(?!${blockedDomain}).)*$`) currentRegex = new RegExp(`(?:https?:\\/\\/)(?:(?!${blockedDomain}).)*$`, 'u')
if (!currentRegex.test(currentUrl)) { if (!currentRegex.test(currentUrl)) {
return true return true
} }
@ -228,7 +228,7 @@ function redirectToPhishingWarning () {
async function domIsReady () { async function domIsReady () {
// already loaded // already loaded
if (['interactive', 'complete'].includes(document.readyState)) { if (['interactive', 'complete'].includes(document.readyState)) {
return return undefined
} }
// wait for load // wait for load
return new Promise((resolve) => window.addEventListener('DOMContentLoaded', resolve, { once: true })) return new Promise((resolve) => window.addEventListener('DOMContentLoaded', resolve, { once: true }))

View File

@ -19,7 +19,7 @@ export default class AppStateController extends EventEmitter {
super() super()
this.onInactiveTimeout = onInactiveTimeout || (() => {}) this.onInactiveTimeout = onInactiveTimeout || (() => undefined)
this.store = new ObservableStore(Object.assign({ this.store = new ObservableStore(Object.assign({
timeoutMinutes: 0, timeoutMinutes: 0,
connectedStatusPopoverHasBeenShown: true, connectedStatusPopoverHasBeenShown: true,

View File

@ -5,11 +5,13 @@ export function createPendingNonceMiddleware ({ getPendingNonce }) {
return createAsyncMiddleware(async (req, res, next) => { return createAsyncMiddleware(async (req, res, next) => {
const { method, params } = req const { method, params } = req
if (method !== 'eth_getTransactionCount') { if (method !== 'eth_getTransactionCount') {
return next() next()
return
} }
const [param, blockRef] = params const [param, blockRef] = params
if (blockRef !== 'pending') { if (blockRef !== 'pending') {
return next() next()
return
} }
res.result = await getPendingNonce(param) res.result = await getPendingNonce(param)
}) })
@ -19,12 +21,14 @@ export function createPendingTxMiddleware ({ getPendingTransactionByHash }) {
return createAsyncMiddleware(async (req, res, next) => { return createAsyncMiddleware(async (req, res, next) => {
const { method, params } = req const { method, params } = req
if (method !== 'eth_getTransactionByHash') { if (method !== 'eth_getTransactionByHash') {
return next() next()
return
} }
const [hash] = params const [hash] = params
const txMeta = getPendingTransactionByHash(hash) const txMeta = getPendingTransactionByHash(hash)
if (!txMeta) { if (!txMeta) {
return next() next()
return
} }
res.result = formatTxMetaForRpcResult(txMeta) res.result = formatTxMetaForRpcResult(txMeta)
}) })

View File

@ -93,7 +93,8 @@ export default class NetworkController extends EventEmitter {
setNetworkState (network, type) { setNetworkState (network, type) {
if (network === 'loading') { if (network === 'loading') {
return this.networkStore.putState(network) this.networkStore.putState(network)
return
} }
// type must be defined // type must be defined
@ -101,7 +102,7 @@ export default class NetworkController extends EventEmitter {
return return
} }
network = networks.networkList[type]?.chainId || network network = networks.networkList[type]?.chainId || network
return this.networkStore.putState(network) this.networkStore.putState(network)
} }
isNetworkLoading () { isNetworkLoading () {
@ -111,7 +112,8 @@ export default class NetworkController extends EventEmitter {
lookupNetwork () { lookupNetwork () {
// Prevent firing when provider is not defined. // Prevent firing when provider is not defined.
if (!this._provider) { if (!this._provider) {
return log.warn('NetworkController - lookupNetwork aborted due to missing provider') log.warn('NetworkController - lookupNetwork aborted due to missing provider')
return
} }
const { type } = this.providerStore.getState() const { type } = this.providerStore.getState()
const ethQuery = new EthQuery(this._provider) const ethQuery = new EthQuery(this._provider)
@ -120,7 +122,8 @@ export default class NetworkController extends EventEmitter {
const currentNetwork = this.getNetworkState() const currentNetwork = this.getNetworkState()
if (initialNetwork === currentNetwork) { if (initialNetwork === currentNetwork) {
if (err) { if (err) {
return this.setNetworkState('loading') this.setNetworkState('loading')
return
} }
log.info('web3.getNetwork returned ' + network) log.info('web3.getNetwork returned ' + network)
this.setNetworkState(network, type) this.setNetworkState(network, type)

View File

@ -132,7 +132,7 @@ export class PermissionsController {
const req = { method: 'eth_accounts' } const req = { method: 'eth_accounts' }
const res = {} const res = {}
this.permissions.providerMiddlewareFunction( this.permissions.providerMiddlewareFunction(
{ origin }, req, res, () => {}, _end, { origin }, req, res, () => undefined, _end,
) )
function _end () { function _end () {
@ -187,7 +187,7 @@ export class PermissionsController {
const res = {} const res = {}
this.permissions.providerMiddlewareFunction( this.permissions.providerMiddlewareFunction(
domain, req, res, () => {}, _end, domain, req, res, () => undefined, _end,
) )
function _end (_err) { function _end (_err) {

View File

@ -116,7 +116,8 @@ export default class PermissionsLogController {
requestedMethods = [ 'eth_accounts' ] requestedMethods = [ 'eth_accounts' ]
} else { } else {
// no-op // no-op
return next() next()
return
} }
// call next with a return handler for capturing the response // call next with a return handler for capturing the response

View File

@ -24,12 +24,13 @@ export default function createPermissionsMethodMiddleware ({
// Intercepting eth_accounts requests for backwards compatibility: // Intercepting eth_accounts requests for backwards compatibility:
// The getAccounts call below wraps the rpc-cap middleware, and returns // The getAccounts call below wraps the rpc-cap middleware, and returns
// an empty array in case of errors (such as 4100:unauthorized) // an empty array in case of errors (such as 4100:unauthorized)
case 'eth_accounts': case 'eth_accounts': {
res.result = await getAccounts() res.result = await getAccounts()
return return
}
case 'eth_requestAccounts': case 'eth_requestAccounts': {
if (isProcessingRequestAccounts) { if (isProcessingRequestAccounts) {
res.error = ethErrors.rpc.resourceUnavailable( res.error = ethErrors.rpc.resourceUnavailable(
@ -73,19 +74,21 @@ export default function createPermissionsMethodMiddleware ({
} }
return return
}
// custom method for getting metadata from the requesting domain, // custom method for getting metadata from the requesting domain,
// sent automatically by the inpage provider when it's initialized // sent automatically by the inpage provider when it's initialized
case 'wallet_sendDomainMetadata': case 'wallet_sendDomainMetadata': {
if (typeof req.domainMetadata?.name === 'string') { if (typeof req.domainMetadata?.name === 'string') {
addDomainMetadata(req.origin, req.domainMetadata) addDomainMetadata(req.origin, req.domainMetadata)
} }
res.result = true res.result = true
return return
}
// register return handler to send accountsChanged notification // register return handler to send accountsChanged notification
case 'wallet_requestPermissions': case 'wallet_requestPermissions': {
if ('eth_accounts' in req.params?.[0]) { if ('eth_accounts' in req.params?.[0]) {
@ -101,6 +104,7 @@ export default function createPermissionsMethodMiddleware ({
} }
} }
break break
}
default: default:
break break

View File

@ -198,7 +198,7 @@ export default class PreferencesController {
) { ) {
const { type, options } = req.params const { type, options } = req.params
switch (type) { switch (type) {
case 'ERC20': case 'ERC20': {
const result = await this._handleWatchAssetERC20(options) const result = await this._handleWatchAssetERC20(options)
if (result instanceof Error) { if (result instanceof Error) {
end(result) end(result)
@ -207,6 +207,7 @@ export default class PreferencesController {
end() end()
} }
return return
}
default: default:
end(new Error(`Asset of type ${type} not supported`)) end(new Error(`Asset of type ${type} not supported`))
return return

View File

@ -123,7 +123,7 @@ export default class ThreeBoxController {
const threeBoxConfig = await Box.getConfig(this.address) const threeBoxConfig = await Box.getConfig(this.address)
backupExists = threeBoxConfig.spaces && threeBoxConfig.spaces.metamask backupExists = threeBoxConfig.spaces && threeBoxConfig.spaces.metamask
} catch (e) { } catch (e) {
if (e.message.match(/^Error: Invalid response \(404\)/)) { if (e.message.match(/^Error: Invalid response \(404\)/u)) {
backupExists = false backupExists = false
} else { } else {
throw e throw e

View File

@ -16,7 +16,7 @@ import {
SEND_ETHER_ACTION_KEY, SEND_ETHER_ACTION_KEY,
DEPLOY_CONTRACT_ACTION_KEY, DEPLOY_CONTRACT_ACTION_KEY,
CONTRACT_INTERACTION_KEY, CONTRACT_INTERACTION_KEY,
} from '../../../../ui/app/helpers/constants/transactions.js' } from '../../../../ui/app/helpers/constants/transactions'
import TransactionStateManager from './tx-state-manager' import TransactionStateManager from './tx-state-manager'
import TxGasUtil from './tx-gas-utils' import TxGasUtil from './tx-gas-utils'
@ -287,11 +287,11 @@ export default class TransactionController extends EventEmitter {
/** /**
* Gets default gas price, or returns `undefined` if gas price is already set * Gets default gas price, or returns `undefined` if gas price is already set
* @param {Object} txMeta - The txMeta object * @param {Object} txMeta - The txMeta object
* @returns {Promise<string>} The default gas price * @returns {Promise<string|undefined>} The default gas price
*/ */
async _getDefaultGasPrice (txMeta) { async _getDefaultGasPrice (txMeta) {
if (txMeta.txParams.gasPrice) { if (txMeta.txParams.gasPrice) {
return return undefined
} }
const gasPrice = await this.query.gasPrice() const gasPrice = await this.query.gasPrice()
@ -560,9 +560,9 @@ export default class TransactionController extends EventEmitter {
// It seems that sometimes the numerical values being returned from // It seems that sometimes the numerical values being returned from
// this.query.getTransactionReceipt are BN instances and not strings. // this.query.getTransactionReceipt are BN instances and not strings.
const gasUsed = typeof txReceipt.gasUsed !== 'string' const gasUsed = typeof txReceipt.gasUsed === 'string'
? txReceipt.gasUsed.toString(16) ? txReceipt.gasUsed
: txReceipt.gasUsed : txReceipt.gasUsed.toString(16)
txMeta.txReceipt = { txMeta.txReceipt = {
...txReceipt, ...txReceipt,
@ -684,7 +684,7 @@ export default class TransactionController extends EventEmitter {
if (!('retryCount' in txMeta)) { if (!('retryCount' in txMeta)) {
txMeta.retryCount = 0 txMeta.retryCount = 0
} }
txMeta.retryCount++ txMeta.retryCount += 1
this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:retry') this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:retry')
}) })
} }

View File

@ -129,7 +129,7 @@ export default class PendingTransactionTracker extends EventEmitter {
// Exponential backoff to limit retries at publishing // Exponential backoff to limit retries at publishing
if (txBlockDistance <= Math.pow(2, retryCount) - 1) { if (txBlockDistance <= Math.pow(2, retryCount) - 1) {
return return undefined
} }
// Only auto-submit already-signed txs: // Only auto-submit already-signed txs:
@ -239,11 +239,11 @@ export default class PendingTransactionTracker extends EventEmitter {
async _checkIfNonceIsTaken (txMeta) { async _checkIfNonceIsTaken (txMeta) {
const address = txMeta.txParams.from const address = txMeta.txParams.from
const completed = this.getCompletedTransactions(address) const completed = this.getCompletedTransactions(address)
return completed.some((other) => return completed.some(
// This is called while the transaction is in-flight, so it is possible that the // This is called while the transaction is in-flight, so it is possible that the
// list of completed transactions now includes the transaction we were looking at // list of completed transactions now includes the transaction we were looking at
// and if that is the case, don't consider the transaction to have taken its own nonce // and if that is the case, don't consider the transaction to have taken its own nonce
!(other.id === txMeta.id) && other.txParams.nonce === txMeta.txParams.nonce, (other) => !(other.id === txMeta.id) && other.txParams.nonce === txMeta.txParams.nonce,
) )
} }
} }

View File

@ -164,10 +164,10 @@ export default class TransactionStateManager extends EventEmitter {
txMeta.txParams = this.normalizeAndValidateTxParams(txMeta.txParams) txMeta.txParams = this.normalizeAndValidateTxParams(txMeta.txParams)
} }
this.once(`${txMeta.id}:signed`, function () { this.once(`${txMeta.id}:signed`, () => {
this.removeAllListeners(`${txMeta.id}:rejected`) this.removeAllListeners(`${txMeta.id}:rejected`)
}) })
this.once(`${txMeta.id}:rejected`, function () { this.once(`${txMeta.id}:rejected`, () => {
this.removeAllListeners(`${txMeta.id}:signed`) this.removeAllListeners(`${txMeta.id}:signed`)
}) })
// initialize history // initialize history
@ -424,7 +424,7 @@ export default class TransactionStateManager extends EventEmitter {
@param {erroObject} err - error object @param {erroObject} err - error object
*/ */
setTxStatusFailed (txId, err) { setTxStatusFailed (txId, err) {
const error = !err ? new Error('Internal metamask failure') : err const error = err || new Error('Internal metamask failure')
const txMeta = this.getTx(txId) const txMeta = this.getTx(txId)
txMeta.err = { txMeta.err = {

View File

@ -35,7 +35,7 @@ import LocalMessageDuplexStream from 'post-message-stream'
import { initProvider } from '@metamask/inpage-provider' import { initProvider } from '@metamask/inpage-provider'
// TODO:deprecate:2020 // TODO:deprecate:2020
import setupWeb3 from './lib/setupWeb3.js' import setupWeb3 from './lib/setupWeb3'
restoreContextAfterImports() restoreContextAfterImports()

View File

@ -25,7 +25,7 @@ export default class ComposableObservableStore extends ObservableStore {
this.config = config this.config = config
this.removeAllListeners() this.removeAllListeners()
for (const key in config) { for (const key in config) {
if (config.hasOwnProperty(key)) { if (Object.prototype.hasOwnProperty.call(config, key)) {
config[key].subscribe((state) => { config[key].subscribe((state) => {
this.updateState({ [key]: state }) this.updateState({ [key]: state })
}) })
@ -42,7 +42,7 @@ export default class ComposableObservableStore extends ObservableStore {
getFlatState () { getFlatState () {
let flatState = {} let flatState = {}
for (const key in this.config) { for (const key in this.config) {
if (this.config.hasOwnProperty(key)) { if (Object.prototype.hasOwnProperty.call(this.config, key)) {
const controller = this.config[key] const controller = this.config[key]
const state = controller.getState ? controller.getState() : controller.state const state = controller.getState ? controller.getState() : controller.state
flatState = { ...flatState, ...state } flatState = { ...flatState, ...state }

View File

@ -256,7 +256,8 @@ export default class AccountTracker {
ethContract.balances(addresses, ethBalance, (error, result) => { ethContract.balances(addresses, ethBalance, (error, result) => {
if (error) { if (error) {
log.warn(`MetaMask - Account Tracker single call balance fetch failed`, error) log.warn(`MetaMask - Account Tracker single call balance fetch failed`, error)
return Promise.all(addresses.map(this._updateAccount.bind(this))) Promise.all(addresses.map(this._updateAccount.bind(this)))
return
} }
addresses.forEach((address, index) => { addresses.forEach((address, index) => {
const balance = bnToHex(result[index]) const balance = bnToHex(result[index])

View File

@ -2,9 +2,6 @@ import { getBackgroundMetaMetricState } from '../../../ui/app/selectors'
import { sendMetaMetricsEvent } from '../../../ui/app/helpers/utils/metametrics.util' import { sendMetaMetricsEvent } from '../../../ui/app/helpers/utils/metametrics.util'
export default function backgroundMetaMetricsEvent (metaMaskState, version, eventData) { export default function backgroundMetaMetricsEvent (metaMaskState, version, eventData) {
eventData.eventOpts['category'] = 'Background'
const stateEventData = getBackgroundMetaMetricState({ metamask: metaMaskState }) const stateEventData = getBackgroundMetaMetricState({ metamask: metaMaskState })
if (stateEventData.participateInMetaMetrics) { if (stateEventData.participateInMetaMetrics) {
sendMetaMetricsEvent({ sendMetaMetricsEvent({

View File

@ -14,7 +14,7 @@ export default function createMethodMiddleware ({ origin, sendMetrics }) {
return function methodMiddleware (req, res, next, end) { return function methodMiddleware (req, res, next, end) {
switch (req.method) { switch (req.method) {
case 'metamask_logInjectedWeb3Usage': case 'metamask_logInjectedWeb3Usage': {
const { action, name } = req.params[0] const { action, name } = req.params[0]
@ -32,6 +32,7 @@ export default function createMethodMiddleware ({ origin, sendMetrics }) {
res.result = true res.result = true
break break
}
default: default:
return next() return next()

View File

@ -5,7 +5,7 @@ import { ethErrors } from 'eth-json-rpc-errors'
import createId from './random-id' import createId from './random-id'
import { MESSAGE_TYPE } from './enums' import { MESSAGE_TYPE } from './enums'
const hexRe = /^[0-9A-Fa-f]+$/g const hexRe = /^[0-9A-Fa-f]+$/ug
import log from 'loglevel' import log from 'loglevel'
/** /**
@ -65,7 +65,8 @@ export default class DecryptMessageManager extends EventEmitter {
getUnapprovedMsgs () { getUnapprovedMsgs () {
return this.messages.filter((msg) => msg.status === 'unapproved') return this.messages.filter((msg) => msg.status === 'unapproved')
.reduce((result, msg) => { .reduce((result, msg) => {
result[msg.id] = msg; return result result[msg.id] = msg
return result
}, {}) }, {})
} }
@ -82,19 +83,24 @@ export default class DecryptMessageManager extends EventEmitter {
addUnapprovedMessageAsync (msgParams, req) { addUnapprovedMessageAsync (msgParams, req) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!msgParams.from) { if (!msgParams.from) {
return reject(new Error('MetaMask Decryption: from field is required.')) reject(new Error('MetaMask Decryption: from field is required.'))
return
} }
const msgId = this.addUnapprovedMessage(msgParams, req) const msgId = this.addUnapprovedMessage(msgParams, req)
this.once(`${msgId}:finished`, (data) => { this.once(`${msgId}:finished`, (data) => {
switch (data.status) { switch (data.status) {
case 'decrypted': case 'decrypted':
return resolve(data.rawData) resolve(data.rawData)
return
case 'rejected': case 'rejected':
return reject(ethErrors.provider.userRejectedRequest('MetaMask Decryption: User denied message decryption.')) reject(ethErrors.provider.userRejectedRequest('MetaMask Decryption: User denied message decryption.'))
return
case 'errored': case 'errored':
return reject(new Error('This message cannot be decrypted')) reject(new Error('This message cannot be decrypted'))
return
default: default:
return reject(new Error(`MetaMask Decryption: Unknown problem: ${JSON.stringify(msgParams)}`)) reject(new Error(`MetaMask Decryption: Unknown problem: ${JSON.stringify(msgParams)}`))
return
} }
}) })
}) })
@ -248,7 +254,7 @@ export default class DecryptMessageManager extends EventEmitter {
_setMsgStatus (msgId, status) { _setMsgStatus (msgId, status) {
const msg = this.getMsg(msgId) const msg = this.getMsg(msgId)
if (!msg) { if (!msg) {
throw new Error('DecryptMessageManager - Message not found for id: "${msgId}".') throw new Error(`DecryptMessageManager - Message not found for id: "${msgId}".`)
} }
msg.status = status msg.status = status
this._updateMsg(msg) this._updateMsg(msg)

View File

@ -62,7 +62,8 @@ export default class EncryptionPublicKeyManager extends EventEmitter {
getUnapprovedMsgs () { getUnapprovedMsgs () {
return this.messages.filter((msg) => msg.status === 'unapproved') return this.messages.filter((msg) => msg.status === 'unapproved')
.reduce((result, msg) => { .reduce((result, msg) => {
result[msg.id] = msg; return result result[msg.id] = msg
return result
}, {}) }, {})
} }
@ -79,17 +80,21 @@ export default class EncryptionPublicKeyManager extends EventEmitter {
addUnapprovedMessageAsync (address, req) { addUnapprovedMessageAsync (address, req) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!address) { if (!address) {
return reject(new Error('MetaMask Message: address field is required.')) reject(new Error('MetaMask Message: address field is required.'))
return
} }
const msgId = this.addUnapprovedMessage(address, req) const msgId = this.addUnapprovedMessage(address, req)
this.once(`${msgId}:finished`, (data) => { this.once(`${msgId}:finished`, (data) => {
switch (data.status) { switch (data.status) {
case 'received': case 'received':
return resolve(data.rawData) resolve(data.rawData)
return
case 'rejected': case 'rejected':
return reject(ethErrors.provider.userRejectedRequest('MetaMask EncryptionPublicKey: User denied message EncryptionPublicKey.')) reject(ethErrors.provider.userRejectedRequest('MetaMask EncryptionPublicKey: User denied message EncryptionPublicKey.'))
return
default: default:
return reject(new Error(`MetaMask EncryptionPublicKey: Unknown problem: ${JSON.stringify(address)}`)) reject(new Error(`MetaMask EncryptionPublicKey: Unknown problem: ${JSON.stringify(address)}`))
return
} }
}) })
}) })
@ -243,7 +248,7 @@ export default class EncryptionPublicKeyManager extends EventEmitter {
_setMsgStatus (msgId, status) { _setMsgStatus (msgId, status) {
const msg = this.getMsg(msgId) const msg = this.getMsg(msgId)
if (!msg) { if (!msg) {
throw new Error('EncryptionPublicKeyManager - Message not found for id: "${msgId}".') throw new Error(`EncryptionPublicKeyManager - Message not found for id: "${msgId}".`)
} }
msg.status = status msg.status = status
this._updateMsg(msg) this._updateMsg(msg)

View File

@ -1,6 +1,6 @@
import urlUtil from 'url' import urlUtil from 'url'
import extension from 'extensionizer' import extension from 'extensionizer'
import resolveEnsToIpfsContentId from './resolver.js' import resolveEnsToIpfsContentId from './resolver'
const supportedTopLevelDomains = ['eth'] const supportedTopLevelDomains = ['eth']

View File

@ -30,11 +30,11 @@ function freeze (target, key, value, enumerable = true) {
configurable: false, writable: false, configurable: false, writable: false,
} }
if (value !== undefined) { if (value === undefined) {
target[key] = deepFreeze(target[key])
} else {
opts.value = deepFreeze(value) opts.value = deepFreeze(value)
opts.enumerable = enumerable opts.enumerable = enumerable
} else {
target[key] = deepFreeze(target[key])
} }
Object.defineProperty(target, key, opts) Object.defineProperty(target, key, opts)

View File

@ -40,7 +40,7 @@ export default async function getFirstPreferredLangCode () {
const firstPreferredLangCode = userPreferredLocaleCodes const firstPreferredLangCode = userPreferredLocaleCodes
.map((code) => code.toLowerCase().replace('_', '-')) .map((code) => code.toLowerCase().replace('_', '-'))
.find((code) => existingLocaleCodes.hasOwnProperty(code)) .find((code) => Object.prototype.hasOwnProperty.call(existingLocaleCodes, code))
return existingLocaleCodes[firstPreferredLangCode] || 'en' return existingLocaleCodes[firstPreferredLangCode] || 'en'
} }

View File

@ -64,7 +64,8 @@ export default class MessageManager extends EventEmitter {
getUnapprovedMsgs () { getUnapprovedMsgs () {
return this.messages.filter((msg) => msg.status === 'unapproved') return this.messages.filter((msg) => msg.status === 'unapproved')
.reduce((result, msg) => { .reduce((result, msg) => {
result[msg.id] = msg; return result result[msg.id] = msg
return result
}, {}) }, {})
} }
@ -225,7 +226,7 @@ export default class MessageManager extends EventEmitter {
_setMsgStatus (msgId, status) { _setMsgStatus (msgId, status) {
const msg = this.getMsg(msgId) const msg = this.getMsg(msgId)
if (!msg) { if (!msg) {
throw new Error('MessageManager - Message not found for id: "${msgId}".') throw new Error(`MessageManager - Message not found for id: "${msgId}".`)
} }
msg.status = status msg.status = status
this._updateMsg(msg) this._updateMsg(msg)

View File

@ -15,9 +15,7 @@ const callbackNoop = function (err) {
* *
*/ */
export default function nodeify (fn, context) { export default function nodeify (fn, context) {
return function () { return function (...args) {
// parse arguments
const args = [].slice.call(arguments)
const lastArg = args[args.length - 1] const lastArg = args[args.length - 1]
const lastArgIsCallback = typeof lastArg === 'function' const lastArgIsCallback = typeof lastArg === 'function'
let callback let callback

View File

@ -5,7 +5,7 @@ import { ethErrors } from 'eth-json-rpc-errors'
import createId from './random-id' import createId from './random-id'
import { MESSAGE_TYPE } from './enums' import { MESSAGE_TYPE } from './enums'
const hexRe = /^[0-9A-Fa-f]+$/g const hexRe = /^[0-9A-Fa-f]+$/ug
import log from 'loglevel' import log from 'loglevel'
/** /**
@ -68,7 +68,8 @@ export default class PersonalMessageManager extends EventEmitter {
getUnapprovedMsgs () { getUnapprovedMsgs () {
return this.messages.filter((msg) => msg.status === 'unapproved') return this.messages.filter((msg) => msg.status === 'unapproved')
.reduce((result, msg) => { .reduce((result, msg) => {
result[msg.id] = msg; return result result[msg.id] = msg
return result
}, {}) }, {})
} }
@ -85,17 +86,21 @@ export default class PersonalMessageManager extends EventEmitter {
addUnapprovedMessageAsync (msgParams, req) { addUnapprovedMessageAsync (msgParams, req) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!msgParams.from) { if (!msgParams.from) {
return reject(new Error('MetaMask Message Signature: from field is required.')) reject(new Error('MetaMask Message Signature: from field is required.'))
return
} }
const msgId = this.addUnapprovedMessage(msgParams, req) const msgId = this.addUnapprovedMessage(msgParams, req)
this.once(`${msgId}:finished`, (data) => { this.once(`${msgId}:finished`, (data) => {
switch (data.status) { switch (data.status) {
case 'signed': case 'signed':
return resolve(data.rawSig) resolve(data.rawSig)
return
case 'rejected': case 'rejected':
return reject(ethErrors.provider.userRejectedRequest('MetaMask Message Signature: User denied message signature.')) reject(ethErrors.provider.userRejectedRequest('MetaMask Message Signature: User denied message signature.'))
return
default: default:
return reject(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`)) reject(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`))
return
} }
}) })
}) })

View File

@ -3,5 +3,6 @@ const MAX = Number.MAX_SAFE_INTEGER
let idCounter = Math.round(Math.random() * MAX) let idCounter = Math.round(Math.random() * MAX)
export default function createRandomId () { export default function createRandomId () {
idCounter = idCounter % MAX idCounter = idCounter % MAX
// eslint-disable-next-line no-plusplus
return idCounter++ return idCounter++
} }

View File

@ -72,7 +72,7 @@ export default function setupSentry ({ release, getState }) {
let sentryTarget let sentryTarget
if (METAMASK_DEBUG) { if (METAMASK_DEBUG) {
return return undefined
} else if (METAMASK_ENVIRONMENT === 'production') { } else if (METAMASK_ENVIRONMENT === 'production') {
if (!process.env.SENTRY_DSN) { if (!process.env.SENTRY_DSN) {
throw new Error(`Missing SENTRY_DSN environment variable in production environment`) throw new Error(`Missing SENTRY_DSN environment variable in production environment`)

View File

@ -3,7 +3,7 @@
// TODO:deprecate:2020 // TODO:deprecate:2020
// Delete this file // Delete this file
import 'web3/dist/web3.min.js' import 'web3/dist/web3.min'
const shouldLogUsage = !([ const shouldLogUsage = !([
'docs.metamask.io', 'docs.metamask.io',

View File

@ -61,7 +61,8 @@ export default class TypedMessageManager extends EventEmitter {
getUnapprovedMsgs () { getUnapprovedMsgs () {
return this.messages.filter((msg) => msg.status === 'unapproved') return this.messages.filter((msg) => msg.status === 'unapproved')
.reduce((result, msg) => { .reduce((result, msg) => {
result[msg.id] = msg; return result result[msg.id] = msg
return result
}, {}) }, {})
} }
@ -154,7 +155,7 @@ export default class TypedMessageManager extends EventEmitter {
}, 'Signing data must be valid EIP-712 typed data.') }, 'Signing data must be valid EIP-712 typed data.')
break break
case 'V3': case 'V3':
case 'V4': case 'V4': {
assert.equal(typeof params.data, 'string', '"params.data" must be a string.') assert.equal(typeof params.data, 'string', '"params.data" must be a string.')
let data let data
assert.doesNotThrow(() => { assert.doesNotThrow(() => {
@ -167,6 +168,7 @@ export default class TypedMessageManager extends EventEmitter {
const activeChainId = parseInt(this.networkController.getNetworkState()) const activeChainId = parseInt(this.networkController.getNetworkState())
chainId && assert.equal(chainId, activeChainId, `Provided chainId "${chainId}" must match the active chainId "${activeChainId}"`) chainId && assert.equal(chainId, activeChainId, `Provided chainId "${chainId}" must match the active chainId "${activeChainId}"`)
break break
}
default: default:
assert.fail(`Unknown typed data version "${params.version}"`) assert.fail(`Unknown typed data version "${params.version}"`)
} }
@ -291,7 +293,7 @@ export default class TypedMessageManager extends EventEmitter {
_setMsgStatus (msgId, status) { _setMsgStatus (msgId, status) {
const msg = this.getMsg(msgId) const msg = this.getMsg(msgId)
if (!msg) { if (!msg) {
throw new Error('TypedMessageManager - Message not found for id: "${msgId}".') throw new Error(`TypedMessageManager - Message not found for id: "${msgId}".`)
} }
msg.status = status msg.status = status
this._updateMsg(msg) this._updateMsg(msg)

View File

@ -55,19 +55,19 @@ const getEnvironmentType = (url = window.location.href) => getEnvironmentTypeMem
*/ */
const getPlatform = (_) => { const getPlatform = (_) => {
const ua = window.navigator.userAgent const ua = window.navigator.userAgent
if (ua.search('Firefox') !== -1) { if (ua.search('Firefox') === -1) {
return PLATFORM_FIREFOX
} else {
if (window && window.chrome && window.chrome.ipcRenderer) { if (window && window.chrome && window.chrome.ipcRenderer) {
return PLATFORM_BRAVE return PLATFORM_BRAVE
} else if (ua.search('Edge') !== -1) {
return PLATFORM_EDGE
} else if (ua.search('OPR') !== -1) {
return PLATFORM_OPERA
} else {
return PLATFORM_CHROME
} }
if (ua.search('Edge') !== -1) {
return PLATFORM_EDGE
}
if (ua.search('OPR') !== -1) {
return PLATFORM_OPERA
}
return PLATFORM_CHROME
} }
return PLATFORM_FIREFOX
} }
/** /**
@ -135,12 +135,12 @@ function BnMultiplyByFraction (targetBN, numerator, denominator) {
/** /**
* Returns an Error if extension.runtime.lastError is present * Returns an Error if extension.runtime.lastError is present
* this is a workaround for the non-standard error object that's used * this is a workaround for the non-standard error object that's used
* @returns {Error} * @returns {Error|undefined}
*/ */
function checkForError () { function checkForError () {
const lastError = extension.runtime.lastError const lastError = extension.runtime.lastError
if (!lastError) { if (!lastError) {
return return undefined
} }
// if it quacks like an Error, its an Error // if it quacks like an Error, its an Error
if (lastError.stack && lastError.message) { if (lastError.stack && lastError.message) {

View File

@ -24,7 +24,7 @@ import createOriginMiddleware from './lib/createOriginMiddleware'
import createTabIdMiddleware from './lib/createTabIdMiddleware' import createTabIdMiddleware from './lib/createTabIdMiddleware'
import createOnboardingMiddleware from './lib/createOnboardingMiddleware' import createOnboardingMiddleware from './lib/createOnboardingMiddleware'
import providerAsMiddleware from 'eth-json-rpc-middleware/providerAsMiddleware' import providerAsMiddleware from 'eth-json-rpc-middleware/providerAsMiddleware'
import { setupMultiplex } from './lib/stream-utils.js' import { setupMultiplex } from './lib/stream-utils'
import KeyringController from 'eth-keyring-controller' import KeyringController from 'eth-keyring-controller'
import EnsController from './controllers/ens' import EnsController from './controllers/ens'
import NetworkController from './controllers/network' import NetworkController from './controllers/network'
@ -47,7 +47,6 @@ import { PermissionsController } from './controllers/permissions'
import getRestrictedMethods from './controllers/permissions/restrictedMethods' import getRestrictedMethods from './controllers/permissions/restrictedMethods'
import nodeify from './lib/nodeify' import nodeify from './lib/nodeify'
import accountImporter from './account-import-strategies' import accountImporter from './account-import-strategies'
import getBuyEthUrl from './lib/buy-eth-url'
import selectChainId from './lib/select-chain-id' import selectChainId from './lib/select-chain-id'
import { Mutex } from 'await-semaphore' import { Mutex } from 'await-semaphore'
import { version } from '../manifest/_base.json' import { version } from '../manifest/_base.json'
@ -449,7 +448,6 @@ export default class MetamaskController extends EventEmitter {
setCurrentLocale: this.setCurrentLocale.bind(this), setCurrentLocale: this.setCurrentLocale.bind(this),
markPasswordForgotten: this.markPasswordForgotten.bind(this), markPasswordForgotten: this.markPasswordForgotten.bind(this),
unMarkPasswordForgotten: this.unMarkPasswordForgotten.bind(this), unMarkPasswordForgotten: this.unMarkPasswordForgotten.bind(this),
buyEth: this.buyEth.bind(this),
safelistPhishingDomain: this.safelistPhishingDomain.bind(this), safelistPhishingDomain: this.safelistPhishingDomain.bind(this),
getRequestAccountTabIds: (cb) => cb(null, this.getRequestAccountTabIds()), getRequestAccountTabIds: (cb) => cb(null, this.getRequestAccountTabIds()),
getOpenMetamaskTabsIds: (cb) => cb(null, this.getOpenMetamaskTabsIds()), getOpenMetamaskTabsIds: (cb) => cb(null, this.getOpenMetamaskTabsIds()),
@ -601,8 +599,6 @@ export default class MetamaskController extends EventEmitter {
this.selectFirstIdentity() this.selectFirstIdentity()
} }
return vault return vault
} catch (err) {
throw err
} finally { } finally {
releaseLock() releaseLock()
} }
@ -658,8 +654,6 @@ export default class MetamaskController extends EventEmitter {
this.preferencesController.setAddresses(accounts) this.preferencesController.setAddresses(accounts)
this.selectFirstIdentity() this.selectFirstIdentity()
return vault return vault
} catch (err) {
throw err
} finally { } finally {
releaseLock() releaseLock()
} }
@ -714,15 +708,16 @@ export default class MetamaskController extends EventEmitter {
Object.keys(accountTokens).forEach((address) => { Object.keys(accountTokens).forEach((address) => {
const checksummedAddress = ethUtil.toChecksumAddress(address) const checksummedAddress = ethUtil.toChecksumAddress(address)
filteredAccountTokens[checksummedAddress] = {} filteredAccountTokens[checksummedAddress] = {}
Object.keys(accountTokens[address]).forEach( Object.keys(accountTokens[address]).forEach((networkType) => {
(networkType) => (filteredAccountTokens[checksummedAddress][networkType] = networkType !== 'mainnet' ? filteredAccountTokens[checksummedAddress][networkType] = networkType === 'mainnet'
accountTokens[address][networkType] : ? (
accountTokens[address][networkType].filter(({ address }) => { accountTokens[address][networkType].filter(({ address }) => {
const tokenAddress = ethUtil.toChecksumAddress(address) const tokenAddress = ethUtil.toChecksumAddress(address)
return contractMap[tokenAddress] ? contractMap[tokenAddress].erc20 : true return contractMap[tokenAddress] ? contractMap[tokenAddress].erc20 : true
}) })
), )
) : accountTokens[address][networkType]
})
}) })
const preferences = { const preferences = {
@ -1349,7 +1344,7 @@ export default class MetamaskController extends EventEmitter {
* Triggers the callback in newUnsignedTypedMessage. * Triggers the callback in newUnsignedTypedMessage.
* *
* @param {Object} msgParams - The params passed to eth_signTypedData. * @param {Object} msgParams - The params passed to eth_signTypedData.
* @returns {Object} - Full state update. * @returns {Object|undefined} - Full state update.
*/ */
async signTypedMessage (msgParams) { async signTypedMessage (msgParams) {
log.info('MetaMaskController - eth_signTypedData') log.info('MetaMaskController - eth_signTypedData')
@ -1372,6 +1367,7 @@ export default class MetamaskController extends EventEmitter {
} catch (error) { } catch (error) {
log.info('MetaMaskController - eth_signTypedData failed.', error) log.info('MetaMaskController - eth_signTypedData failed.', error)
this.typedMessageManager.errorMessage(msgId, error) this.typedMessageManager.errorMessage(msgId, error)
return undefined
} }
} }
@ -1401,13 +1397,9 @@ export default class MetamaskController extends EventEmitter {
* @returns {Object} - MetaMask state * @returns {Object} - MetaMask state
*/ */
async createCancelTransaction (originalTxId, customGasPrice) { async createCancelTransaction (originalTxId, customGasPrice) {
try { await this.txController.createCancelTransaction(originalTxId, customGasPrice)
await this.txController.createCancelTransaction(originalTxId, customGasPrice) const state = await this.getState()
const state = await this.getState() return state
return state
} catch (error) {
throw error
}
} }
async createSpeedUpTransaction (originalTxId, customGasPrice, customGasLimit) { async createSpeedUpTransaction (originalTxId, customGasPrice, customGasLimit) {
@ -1526,7 +1518,7 @@ export default class MetamaskController extends EventEmitter {
const api = this.getApi() const api = this.getApi()
const dnode = Dnode(api) const dnode = Dnode(api)
// report new active controller connection // report new active controller connection
this.activeControllerConnections++ this.activeControllerConnections += 1
this.emit('controllerConnectionChanged', this.activeControllerConnections) this.emit('controllerConnectionChanged', this.activeControllerConnections)
// connect dnode api to remote connection // connect dnode api to remote connection
pump( pump(
@ -1535,7 +1527,7 @@ export default class MetamaskController extends EventEmitter {
outStream, outStream,
(err) => { (err) => {
// report new active controller connection // report new active controller connection
this.activeControllerConnections-- this.activeControllerConnections -= 1
this.emit('controllerConnectionChanged', this.activeControllerConnections) this.emit('controllerConnectionChanged', this.activeControllerConnections)
// report any error // report any error
if (err) { if (err) {
@ -1850,6 +1842,7 @@ export default class MetamaskController extends EventEmitter {
customVariables, customVariables,
eventOpts: { eventOpts: {
action, action,
category: 'Background',
name, name,
}, },
}, },
@ -1884,24 +1877,6 @@ export default class MetamaskController extends EventEmitter {
} }
} }
/**
* A method for forwarding the user to the easiest way to obtain ether,
* or the network "gas" currency, for the current selected network.
*
* @param {string} address - The address to fund.
* @param {string} amount - The amount of ether desired, as a base 10 string.
*/
buyEth (address, amount) {
if (!amount) {
amount = '5'
}
const network = this.networkController.getNetworkState()
const url = getBuyEthUrl({ network, address, amount })
if (url) {
this.platform.openTab({ url })
}
}
// network // network
/** /**
* A method for selecting a custom URL for an ethereum RPC provider and updating it * A method for selecting a custom URL for an ethereum RPC provider and updating it

View File

@ -14,7 +14,9 @@ export default {
versionedData.data.config.provider.type = 'rpc' versionedData.data.config.provider.type = 'rpc'
versionedData.data.config.provider.rpcTarget = 'https://rpc.metamask.io/' versionedData.data.config.provider.rpcTarget = 'https://rpc.metamask.io/'
} }
} catch (e) {} } catch (_) {
// empty
}
return Promise.resolve(versionedData) return Promise.resolve(versionedData)
}, },
} }

View File

@ -14,7 +14,9 @@ export default {
if (versionedData.data.config.provider.rpcTarget === oldTestRpc) { if (versionedData.data.config.provider.rpcTarget === oldTestRpc) {
versionedData.data.config.provider.rpcTarget = newTestRpc versionedData.data.config.provider.rpcTarget = newTestRpc
} }
} catch (e) {} } catch (_) {
// empty
}
return Promise.resolve(versionedData) return Promise.resolve(versionedData)
}, },
} }

View File

@ -25,7 +25,9 @@ export default {
break break
// No default // No default
} }
} catch (_) {} } catch (_) {
// empty
}
return Promise.resolve(safeVersionedData) return Promise.resolve(safeVersionedData)
}, },
} }

View File

@ -72,7 +72,7 @@ function getHighestContinuousFrom (txList, startPoint) {
let highest = startPoint let highest = startPoint
while (nonces.includes(highest)) { while (nonces.includes(highest)) {
highest++ highest += 1
} }
return highest return highest

View File

@ -3,7 +3,7 @@ import dnode from 'dnode'
import { EventEmitter } from 'events' import { EventEmitter } from 'events'
import PortStream from 'extension-port-stream' import PortStream from 'extension-port-stream'
import extension from 'extensionizer' import extension from 'extensionizer'
import { setupMultiplex } from './lib/stream-utils.js' import { setupMultiplex } from './lib/stream-utils'
import { getEnvironmentType } from './lib/util' import { getEnvironmentType } from './lib/util'
import ExtensionPlatform from './platforms/extension' import ExtensionPlatform from './platforms/extension'

View File

@ -24,7 +24,7 @@ import Eth from 'ethjs'
import EthQuery from 'eth-query' import EthQuery from 'eth-query'
import launchMetaMaskUi from '../../ui' import launchMetaMaskUi from '../../ui'
import StreamProvider from 'web3-stream-provider' import StreamProvider from 'web3-stream-provider'
import { setupMultiplex } from './lib/stream-utils.js' import { setupMultiplex } from './lib/stream-utils'
import log from 'loglevel' import log from 'loglevel'
start().catch(log.error) start().catch(log.error)
@ -62,7 +62,8 @@ async function start () {
const container = document.getElementById('app-content') const container = document.getElementById('app-content')
initializeUi(tab, container, connectionStream, (err, store) => { initializeUi(tab, container, connectionStream, (err, store) => {
if (err) { if (err) {
return displayCriticalError(container, err) displayCriticalError(container, err)
return
} }
const state = store.getState() const state = store.getState()
@ -102,7 +103,8 @@ async function queryCurrentActiveTab (windowType) {
function initializeUi (activeTab, container, connectionStream, cb) { function initializeUi (activeTab, container, connectionStream, cb) {
connectToAccountManager(connectionStream, (err, backgroundConnection) => { connectToAccountManager(connectionStream, (err, backgroundConnection) => {
if (err) { if (err) {
return cb(err) cb(err)
return
} }
launchMetaMaskUi({ launchMetaMaskUi({

View File

@ -25,7 +25,7 @@ module.exports = createScriptTasks
const dependencies = Object.keys((packageJSON && packageJSON.dependencies) || {}) const dependencies = Object.keys((packageJSON && packageJSON.dependencies) || {})
const materialUIDependencies = ['@material-ui/core'] const materialUIDependencies = ['@material-ui/core']
const reactDepenendencies = dependencies.filter((dep) => dep.match(/react/)) const reactDepenendencies = dependencies.filter((dep) => dep.match(/react/u))
const d3Dependencies = ['c3', 'd3'] const d3Dependencies = ['c3', 'd3']
const externalDependenciesMap = { const externalDependenciesMap = {
@ -365,7 +365,7 @@ function getEnvironment ({ devMode, test }) {
return 'testing' return 'testing'
} else if (process.env.CIRCLE_BRANCH === 'master') { } else if (process.env.CIRCLE_BRANCH === 'master') {
return 'production' return 'production'
} else if (/^Version-v(\d+)[.](\d+)[.](\d+)/.test(process.env.CIRCLE_BRANCH)) { } else if (/^Version-v(\d+)[.](\d+)[.](\d+)/u.test(process.env.CIRCLE_BRANCH)) {
return 'release-candidate' return 'release-candidate'
} else if (process.env.CIRCLE_BRANCH === 'develop') { } else if (process.env.CIRCLE_BRANCH === 'develop') {
return 'staging' return 'staging'

View File

@ -81,10 +81,7 @@ async function start () {
const summaryPlatform = 'chrome' const summaryPlatform = 'chrome'
const summaryPage = 'home' const summaryPage = 'home'
let commentBody let commentBody
if (!benchmarkResults[summaryPlatform]) { if (benchmarkResults[summaryPlatform]) {
console.log(`No results for ${summaryPlatform} found; skipping benchmark`)
commentBody = artifactsBody
} else {
try { try {
const summaryPageLoad = Math.round(parseFloat(benchmarkResults[summaryPlatform][summaryPage].average.load)) const summaryPageLoad = Math.round(parseFloat(benchmarkResults[summaryPlatform][summaryPage].average.load))
const summaryPageLoadMarginOfError = Math.round(parseFloat(benchmarkResults[summaryPlatform][summaryPage].marginOfError.load)) const summaryPageLoadMarginOfError = Math.round(parseFloat(benchmarkResults[summaryPlatform][summaryPage].marginOfError.load))
@ -147,6 +144,9 @@ async function start () {
console.error(`Error constructing benchmark results: '${error}'`) console.error(`Error constructing benchmark results: '${error}'`)
commentBody = artifactsBody commentBody = artifactsBody
} }
} else {
console.log(`No results for ${summaryPlatform} found; skipping benchmark`)
commentBody = artifactsBody
} }
const JSON_PAYLOAD = JSON.stringify({ body: commentBody }) const JSON_PAYLOAD = JSON.stringify({ body: commentBody })

View File

@ -50,7 +50,7 @@ class Mock3Box {
}, },
} }
}, },
logout: () => {}, logout: () => undefined,
}) })
} }

View File

@ -25,12 +25,14 @@ async function start () {
// check if version has artifacts or not // check if version has artifacts or not
const versionHasArtifacts = versionAlreadyExists && await checkIfVersionHasArtifacts() const versionHasArtifacts = versionAlreadyExists && await checkIfVersionHasArtifacts()
if (!versionHasArtifacts) { if (versionHasArtifacts) {
// upload sentry source and sourcemaps
await exec(`./development/sentry-upload-artifacts.sh --release ${VERSION}`)
} else {
console.log(`Version "${VERSION}" already has artifacts on Sentry, skipping sourcemap upload`) console.log(`Version "${VERSION}" already has artifacts on Sentry, skipping sourcemap upload`)
return
} }
// upload sentry source and sourcemaps
await exec(`./development/sentry-upload-artifacts.sh --release ${VERSION}`)
} }
async function checkIfAuthWorks () { async function checkIfAuthWorks () {

View File

@ -49,7 +49,9 @@ async function validateSourcemapForFile ({ buildName }) {
try { try {
const filePath = path.join(__dirname, `/../dist/${platform}/`, `${buildName}`) const filePath = path.join(__dirname, `/../dist/${platform}/`, `${buildName}`)
rawBuild = await fsAsync.readFile(filePath, 'utf8') rawBuild = await fsAsync.readFile(filePath, 'utf8')
} catch (err) {} } catch (_) {
// empty
}
if (!rawBuild) { if (!rawBuild) {
throw new Error(`SourcemapValidator - failed to load source file for "${buildName}"`) throw new Error(`SourcemapValidator - failed to load source file for "${buildName}"`)
} }
@ -58,12 +60,16 @@ async function validateSourcemapForFile ({ buildName }) {
try { try {
const filePath = path.join(__dirname, `/../dist/sourcemaps/`, `${buildName}.map`) const filePath = path.join(__dirname, `/../dist/sourcemaps/`, `${buildName}.map`)
rawSourceMap = await fsAsync.readFile(filePath, 'utf8') rawSourceMap = await fsAsync.readFile(filePath, 'utf8')
} catch (err) {} } catch (_) {
// empty
}
// attempt to load in dev mode // attempt to load in dev mode
try { try {
const filePath = path.join(__dirname, `/../dist/${platform}/`, `${buildName}.map`) const filePath = path.join(__dirname, `/../dist/${platform}/`, `${buildName}.map`)
rawSourceMap = await fsAsync.readFile(filePath, 'utf8') rawSourceMap = await fsAsync.readFile(filePath, 'utf8')
} catch (err) {} } catch (_) {
// empty
}
if (!rawSourceMap) { if (!rawSourceMap) {
throw new Error(`SourcemapValidator - failed to load sourcemaps for "${buildName}"`) throw new Error(`SourcemapValidator - failed to load sourcemaps for "${buildName}"`)
} }
@ -85,7 +91,7 @@ async function validateSourcemapForFile ({ buildName }) {
const matchesPerLine = buildLines.map((line) => indicesOf(targetString, line)) const matchesPerLine = buildLines.map((line) => indicesOf(targetString, line))
matchesPerLine.forEach((matchIndices, lineIndex) => { matchesPerLine.forEach((matchIndices, lineIndex) => {
matchIndices.forEach((matchColumn) => { matchIndices.forEach((matchColumn) => {
sampleCount++ sampleCount += 1
const position = { line: lineIndex + 1, column: matchColumn } const position = { line: lineIndex + 1, column: matchColumn }
const result = consumer.originalPositionFor(position) const result = consumer.originalPositionFor(position)
// warn if source content is missing // warn if source content is missing

View File

@ -61,7 +61,7 @@ const main = async () => {
} }
while (args.length) { while (args.length) {
if (/^(--port|-p)$/i.test(args[0])) { if (/^(--port|-p)$/u.test(args[0])) {
if (args[1] === undefined) { if (args[1] === undefined) {
throw new Error('Missing port argument') throw new Error('Missing port argument')
} }

View File

@ -97,6 +97,7 @@ async function getLocale (code) {
log.error(`Error opening your locale ("${code}") file: `, e) log.error(`Error opening your locale ("${code}") file: `, e)
} }
process.exit(1) process.exit(1)
return undefined
} }
} }
@ -111,6 +112,7 @@ async function writeLocale (code, locale) {
log.error(`Error writing your locale ("${code}") file: `, e) log.error(`Error writing your locale ("${code}") file: `, e)
} }
process.exit(1) process.exit(1)
return undefined
} }
} }
@ -156,6 +158,8 @@ async function verifyLocale (code, fix = false) {
} }
return true return true
} }
return false
} }
async function verifyEnglishLocale (fix = false) { async function verifyEnglishLocale (fix = false) {
@ -165,11 +169,11 @@ async function verifyEnglishLocale (fix = false) {
// match "t(`...`)" because constructing message keys from template strings // match "t(`...`)" because constructing message keys from template strings
// prevents this script from finding the messages, and then inappropriately // prevents this script from finding the messages, and then inappropriately
// deletes them // deletes them
const templateStringRegex = /\bt\(`.*`\)/g const templateStringRegex = /\bt\(`.*`\)/ug
const templateUsage = [] const templateUsage = []
// match the keys from the locale file // match the keys from the locale file
const keyRegex = /'(\w+)'|"(\w+)"/g const keyRegex = /'(\w+)'|"(\w+)"/ug
const usedMessages = new Set() const usedMessages = new Set()
for await (const fileContents of getFileContents(javascriptFiles)) { for await (const fileContents of getFileContents(javascriptFiles)) {
for (const match of matchAll.call(fileContents, keyRegex)) { for (const match of matchAll.call(fileContents, keyRegex)) {

View File

@ -202,7 +202,7 @@
"chalk": "^3.0.0", "chalk": "^3.0.0",
"chromedriver": "^79.0.0", "chromedriver": "^79.0.0",
"concurrently": "^5.2.0", "concurrently": "^5.2.0",
"copy-webpack-plugin": "^5.1.1", "copy-webpack-plugin": "^6.0.3",
"coveralls": "^3.0.0", "coveralls": "^3.0.0",
"css-loader": "^2.1.1", "css-loader": "^2.1.1",
"del": "^3.0.0", "del": "^3.0.0",

View File

@ -1,5 +0,0 @@
module.exports = {
rules: {
'mocha/no-hooks-for-single-case': 'off',
},
}

View File

@ -152,7 +152,7 @@ describe('MetaMask', function () {
it('balance renders', async function () { it('balance renders', async function () {
const balance = await driver.findElement(By.css('[data-testid="wallet-balance"] .list-item__heading')) const balance = await driver.findElement(By.css('[data-testid="wallet-balance"] .list-item__heading'))
await driver.wait(until.elementTextMatches(balance, /25\s*ETH/)) await driver.wait(until.elementTextMatches(balance, /25\s*ETH/u))
await driver.delay(regularDelayMs) await driver.delay(regularDelayMs)
}) })
}) })
@ -202,7 +202,7 @@ describe('MetaMask', function () {
}, 10000) }, 10000)
const txValues = await driver.findElement(By.css('.transaction-list-item__primary-currency')) const txValues = await driver.findElement(By.css('.transaction-list-item__primary-currency'))
await driver.wait(until.elementTextMatches(txValues, /-1\s*ETH/), 10000) await driver.wait(until.elementTextMatches(txValues, /-1\s*ETH/u), 10000)
}) })
}) })
@ -239,7 +239,7 @@ describe('MetaMask', function () {
}, 10000) }, 10000)
const txValues = await driver.findElement(By.css('.transaction-list-item__primary-currency')) const txValues = await driver.findElement(By.css('.transaction-list-item__primary-currency'))
await driver.wait(until.elementTextMatches(txValues, /-2\s*ETH/), 10000) await driver.wait(until.elementTextMatches(txValues, /-2\s*ETH/u), 10000)
}) })
}) })
}) })

View File

@ -92,7 +92,7 @@ async function isWritable (directory) {
} }
async function getFirstParentDirectoryThatExists (directory) { async function getFirstParentDirectoryThatExists (directory) {
while (true) { for (;;) {
try { try {
await fs.access(directory, fsConstants.F_OK) await fs.access(directory, fsConstants.F_OK)
return directory return directory
@ -117,7 +117,7 @@ async function main () {
let existingParentDirectory let existingParentDirectory
while (args.length) { while (args.length) {
if (/^(--pages|-p)$/i.test(args[0])) { if (/^(--pages|-p)$/u.test(args[0])) {
if (args[1] === undefined) { if (args[1] === undefined) {
throw new Error('Missing pages argument') throw new Error('Missing pages argument')
} }
@ -128,7 +128,7 @@ async function main () {
} }
} }
args.splice(0, 2) args.splice(0, 2)
} else if (/^(--samples|-s)$/i.test(args[0])) { } else if (/^(--samples|-s)$/u.test(args[0])) {
if (args[1] === undefined) { if (args[1] === undefined) {
throw new Error('Missing number of samples') throw new Error('Missing number of samples')
} }
@ -137,7 +137,7 @@ async function main () {
throw new Error(`Invalid 'samples' argument given: '${args[1]}'`) throw new Error(`Invalid 'samples' argument given: '${args[1]}'`)
} }
args.splice(0, 2) args.splice(0, 2)
} else if (/^(--out|-o)$/i.test(args[0])) { } else if (/^(--out|-o)$/u.test(args[0])) {
if (args[1] === undefined) { if (args[1] === undefined) {
throw new Error('Missing output filename') throw new Error('Missing output filename')
} }

View File

@ -89,11 +89,11 @@ describe('MetaMask', function () {
}) })
it('gets the current accounts address', async function () { it('gets the current accounts address', async function () {
const addressInput = await driver.findElement(By.css('.qr-ellip-address')) const addressInput = await driver.findElement(By.css('.readonly-input__input'))
publicAddress = await addressInput.getAttribute('value') publicAddress = await addressInput.getAttribute('value')
const accountModal = await driver.findElement(By.css('span .modal')) const accountModal = await driver.findElement(By.css('span .modal'))
await driver.clickElement(By.css('.account-modal-close')) await driver.clickElement(By.css('.account-modal__close'))
await driver.wait(until.stalenessOf(accountModal)) await driver.wait(until.stalenessOf(accountModal))
await driver.delay(regularDelayMs) await driver.delay(regularDelayMs)

View File

@ -44,7 +44,7 @@ class FixtureServer {
return return
} }
return new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
this._server.close() this._server.close()
this._server.once('error', reject) this._server.once('error', reject)
this._server.once('close', resolve) this._server.once('close', resolve)

View File

@ -99,24 +99,24 @@ describe('Using MetaMask with an existing account', function () {
it('shows the correct account address', async function () { it('shows the correct account address', async function () {
await driver.clickElement(By.css('[data-testid="account-options-menu-button"]')) await driver.clickElement(By.css('[data-testid="account-options-menu-button"]'))
await driver.clickElement(By.css('[data-testid="account-options-menu__account-details"]')) await driver.clickElement(By.css('[data-testid="account-options-menu__account-details"]'))
await driver.findVisibleElement(By.css('.qr-wrapper')) await driver.findVisibleElement(By.css('.qr-code__wrapper'))
await driver.delay(regularDelayMs) await driver.delay(regularDelayMs)
const [address] = await driver.findElements(By.css('input.qr-ellip-address')) const [address] = await driver.findElements(By.css('.readonly-input__input'))
assert.equal(await address.getAttribute('value'), testAddress) assert.equal(await address.getAttribute('value'), testAddress)
await driver.clickElement(By.css('.account-modal-close')) await driver.clickElement(By.css('.account-modal__close'))
await driver.delay(largeDelayMs) await driver.delay(largeDelayMs)
}) })
it('shows a QR code for the account', async function () { it('shows a QR code for the account', async function () {
await driver.clickElement(By.css('[data-testid="account-options-menu-button"]')) await driver.clickElement(By.css('[data-testid="account-options-menu-button"]'))
await driver.clickElement(By.css('[data-testid="account-options-menu__account-details"]')) await driver.clickElement(By.css('[data-testid="account-options-menu__account-details"]'))
await driver.findVisibleElement(By.css('.qr-wrapper')) await driver.findVisibleElement(By.css('.qr-code__wrapper'))
const detailModal = await driver.findElement(By.css('span .modal')) const detailModal = await driver.findElement(By.css('span .modal'))
await driver.delay(regularDelayMs) await driver.delay(regularDelayMs)
await driver.clickElement(By.css('.account-modal-close')) await driver.clickElement(By.css('.account-modal__close'))
await driver.wait(until.stalenessOf(detailModal)) await driver.wait(until.stalenessOf(detailModal))
await driver.delay(regularDelayMs) await driver.delay(regularDelayMs)
}) })
@ -223,7 +223,7 @@ describe('Using MetaMask with an existing account', function () {
const txValues = await driver.findElements(By.css('.transaction-list-item__primary-currency')) const txValues = await driver.findElements(By.css('.transaction-list-item__primary-currency'))
assert.equal(txValues.length, 1) assert.equal(txValues.length, 1)
assert.ok(/-1\s*ETH/.test(await txValues[0].getText())) assert.ok(/-1\s*ETH/u.test(await txValues[0].getText()))
}) })
}) })

View File

@ -95,12 +95,12 @@ describe('MetaMask', function () {
}) })
it('gets the current accounts address', async function () { it('gets the current accounts address', async function () {
const addressInput = await driver.findElement(By.css('.qr-ellip-address')) const addressInput = await driver.findElement(By.css('.readonly-input__input'))
publicAddress = await addressInput.getAttribute('value') publicAddress = await addressInput.getAttribute('value')
const accountModal = await driver.findElement(By.css('span .modal')) const accountModal = await driver.findElement(By.css('span .modal'))
await driver.clickElement(By.css('.account-modal-close')) await driver.clickElement(By.css('.account-modal__close'))
await driver.wait(until.stalenessOf(accountModal)) await driver.wait(until.stalenessOf(accountModal))
await driver.delay(regularDelayMs) await driver.delay(regularDelayMs)
@ -127,7 +127,7 @@ describe('MetaMask', function () {
await driver.clickElement(By.css('#send')) await driver.clickElement(By.css('#send'))
const txStatus = await driver.findElement(By.css('#success')) const txStatus = await driver.findElement(By.css('#success'))
await driver.wait(until.elementTextMatches(txStatus, /Success/), 15000) await driver.wait(until.elementTextMatches(txStatus, /Success/u), 15000)
}) })
it('switches back to MetaMask', async function () { it('switches back to MetaMask', async function () {
@ -136,7 +136,7 @@ describe('MetaMask', function () {
it('should have the correct amount of eth', async function () { it('should have the correct amount of eth', async function () {
const balances = await driver.findElements(By.css('.currency-display-component__text')) const balances = await driver.findElements(By.css('.currency-display-component__text'))
await driver.wait(until.elementTextMatches(balances[0], /1/), 15000) await driver.wait(until.elementTextMatches(balances[0], /1/u), 15000)
const balance = await balances[0].getText() const balance = await balances[0].getText()
assert.equal(balance, '1') assert.equal(balance, '1')
@ -193,7 +193,7 @@ describe('MetaMask', function () {
it('should have the correct amount of eth', async function () { it('should have the correct amount of eth', async function () {
const balances = await driver.findElements(By.css('.currency-display-component__text')) const balances = await driver.findElements(By.css('.currency-display-component__text'))
await driver.wait(until.elementTextMatches(balances[0], /1/), 15000) await driver.wait(until.elementTextMatches(balances[0], /1/u), 15000)
const balance = await balances[0].getText() const balance = await balances[0].getText()
assert.equal(balance, '1') assert.equal(balance, '1')

View File

@ -167,7 +167,7 @@ describe('MetaMask', function () {
it('balance renders', async function () { it('balance renders', async function () {
const balance = await driver.findElement(By.css('[data-testid="eth-overview__primary-currency"]')) const balance = await driver.findElement(By.css('[data-testid="eth-overview__primary-currency"]'))
await driver.wait(until.elementTextMatches(balance, /100\s*ETH/)) await driver.wait(until.elementTextMatches(balance, /100\s*ETH/u))
await driver.delay(regularDelayMs) await driver.delay(regularDelayMs)
}) })
}) })
@ -218,7 +218,7 @@ describe('MetaMask', function () {
}, 10000) }, 10000)
const txValues = await driver.findElement(By.css('.transaction-list-item__primary-currency')) const txValues = await driver.findElement(By.css('.transaction-list-item__primary-currency'))
await driver.wait(until.elementTextMatches(txValues, /-1\s*ETH/), 10000) await driver.wait(until.elementTextMatches(txValues, /-1\s*ETH/u), 10000)
}) })
}) })
}) })

View File

@ -121,11 +121,11 @@ describe('MetaMask', function () {
it('shows the QR code for the account', async function () { it('shows the QR code for the account', async function () {
await driver.clickElement(By.css('[data-testid="account-options-menu-button"]')) await driver.clickElement(By.css('[data-testid="account-options-menu-button"]'))
await driver.clickElement(By.css('[data-testid="account-options-menu__account-details"]')) await driver.clickElement(By.css('[data-testid="account-options-menu__account-details"]'))
await driver.findVisibleElement(By.css('.qr-wrapper')) await driver.findVisibleElement(By.css('.qr-code__wrapper'))
await driver.delay(regularDelayMs) await driver.delay(regularDelayMs)
const accountModal = await driver.findElement(By.css('span .modal')) const accountModal = await driver.findElement(By.css('span .modal'))
await driver.clickElement(By.css('.account-modal-close')) await driver.clickElement(By.css('.account-modal__close'))
await driver.wait(until.stalenessOf(accountModal)) await driver.wait(until.stalenessOf(accountModal))
await driver.delay(regularDelayMs) await driver.delay(regularDelayMs)
@ -208,7 +208,7 @@ describe('MetaMask', function () {
it('balance renders', async function () { it('balance renders', async function () {
const balance = await driver.findElement(By.css('[data-testid="wallet-balance"] .list-item__heading')) const balance = await driver.findElement(By.css('[data-testid="wallet-balance"] .list-item__heading'))
await driver.wait(until.elementTextMatches(balance, /100\s*ETH/)) await driver.wait(until.elementTextMatches(balance, /100\s*ETH/u))
await driver.delay(regularDelayMs) await driver.delay(regularDelayMs)
}) })
}) })
@ -273,7 +273,7 @@ describe('MetaMask', function () {
}, 10000) }, 10000)
const txValues = await driver.findElement(By.css('.transaction-list-item__primary-currency')) const txValues = await driver.findElement(By.css('.transaction-list-item__primary-currency'))
await driver.wait(until.elementTextMatches(txValues, /-1\s*ETH/), 10000) await driver.wait(until.elementTextMatches(txValues, /-1\s*ETH/u), 10000)
}) })
}) })
@ -312,7 +312,7 @@ describe('MetaMask', function () {
}, 10000) }, 10000)
const txValues = await driver.findElement(By.css('.transaction-list-item__primary-currency')) const txValues = await driver.findElement(By.css('.transaction-list-item__primary-currency'))
await driver.wait(until.elementTextMatches(txValues, /-1\s*ETH/), 10000) await driver.wait(until.elementTextMatches(txValues, /-1\s*ETH/u), 10000)
}) })
}) })
@ -360,7 +360,7 @@ describe('MetaMask', function () {
}, 10000) }, 10000)
const txValues = await driver.findElement(By.css('.transaction-list-item__primary-currency')) const txValues = await driver.findElement(By.css('.transaction-list-item__primary-currency'))
await driver.wait(until.elementTextMatches(txValues, /-1\s*ETH/), 10000) await driver.wait(until.elementTextMatches(txValues, /-1\s*ETH/u), 10000)
}) })
}) })
@ -463,7 +463,7 @@ describe('MetaMask', function () {
}, 10000) }, 10000)
const txValue = await driver.findClickableElement(By.css('.transaction-list-item__primary-currency')) const txValue = await driver.findClickableElement(By.css('.transaction-list-item__primary-currency'))
await driver.wait(until.elementTextMatches(txValue, /-3\s*ETH/), 10000) await driver.wait(until.elementTextMatches(txValue, /-3\s*ETH/u), 10000)
}) })
it('the transaction has the expected gas price', async function () { it('the transaction has the expected gas price', async function () {
@ -471,7 +471,7 @@ describe('MetaMask', function () {
await txValue.click() await txValue.click()
const popoverCloseButton = await driver.findClickableElement(By.css('.popover-header__button')) const popoverCloseButton = await driver.findClickableElement(By.css('.popover-header__button'))
const txGasPrice = await driver.findElement(By.css('[data-testid="transaction-breakdown__gas-price"]')) const txGasPrice = await driver.findElement(By.css('[data-testid="transaction-breakdown__gas-price"]'))
await driver.wait(until.elementTextMatches(txGasPrice, /^10$/), 10000) await driver.wait(until.elementTextMatches(txGasPrice, /^10$/u), 10000)
await popoverCloseButton.click() await popoverCloseButton.click()
}) })
}) })
@ -654,7 +654,7 @@ describe('MetaMask', function () {
}, 10000) }, 10000)
const txAction = await driver.findElements(By.css('.list-item__heading')) const txAction = await driver.findElements(By.css('.list-item__heading'))
await driver.wait(until.elementTextMatches(txAction[0], /Contract\sDeployment/), 10000) await driver.wait(until.elementTextMatches(txAction[0], /Contract\sDeployment/u), 10000)
await driver.delay(regularDelayMs) await driver.delay(regularDelayMs)
}) })
@ -663,20 +663,20 @@ describe('MetaMask', function () {
await driver.delay(regularDelayMs) await driver.delay(regularDelayMs)
let contractStatus = await driver.findElement(By.css('#contractStatus')) let contractStatus = await driver.findElement(By.css('#contractStatus'))
await driver.wait(until.elementTextMatches(contractStatus, /Deployed/), 15000) await driver.wait(until.elementTextMatches(contractStatus, /Deployed/u), 15000)
await driver.clickElement(By.css('#depositButton')) await driver.clickElement(By.css('#depositButton'))
await driver.delay(largeDelayMs) await driver.delay(largeDelayMs)
contractStatus = await driver.findElement(By.css('#contractStatus')) contractStatus = await driver.findElement(By.css('#contractStatus'))
await driver.wait(until.elementTextMatches(contractStatus, /Deposit\sinitiated/), 10000) await driver.wait(until.elementTextMatches(contractStatus, /Deposit\sinitiated/u), 10000)
await driver.switchToWindow(extension) await driver.switchToWindow(extension)
await driver.delay(largeDelayMs * 2) await driver.delay(largeDelayMs * 2)
await driver.findElements(By.css('.transaction-list-item')) await driver.findElements(By.css('.transaction-list-item'))
const txListValue = await driver.findClickableElement(By.css('.transaction-list-item__primary-currency')) const txListValue = await driver.findClickableElement(By.css('.transaction-list-item__primary-currency'))
await driver.wait(until.elementTextMatches(txListValue, /-4\s*ETH/), 10000) await driver.wait(until.elementTextMatches(txListValue, /-4\s*ETH/u), 10000)
await txListValue.click() await txListValue.click()
await driver.delay(regularDelayMs) await driver.delay(regularDelayMs)
@ -718,7 +718,7 @@ describe('MetaMask', function () {
}, 10000) }, 10000)
const txValues = await driver.findElements(By.css('.transaction-list-item__primary-currency')) const txValues = await driver.findElements(By.css('.transaction-list-item__primary-currency'))
await driver.wait(until.elementTextMatches(txValues[0], /-4\s*ETH/), 10000) await driver.wait(until.elementTextMatches(txValues[0], /-4\s*ETH/u), 10000)
}) })
it('calls and confirms a contract method where ETH is received', async function () { it('calls and confirms a contract method where ETH is received', async function () {
@ -743,7 +743,7 @@ describe('MetaMask', function () {
}, 10000) }, 10000)
const txValues = await driver.findElement(By.css('.transaction-list-item__primary-currency')) const txValues = await driver.findElement(By.css('.transaction-list-item__primary-currency'))
await driver.wait(until.elementTextMatches(txValues, /-0\s*ETH/), 10000) await driver.wait(until.elementTextMatches(txValues, /-0\s*ETH/u), 10000)
await driver.closeAllWindowHandlesExcept([extension, dapp]) await driver.closeAllWindowHandlesExcept([extension, dapp])
await driver.switchToWindow(extension) await driver.switchToWindow(extension)
@ -752,9 +752,9 @@ describe('MetaMask', function () {
it('renders the correct ETH balance', async function () { it('renders the correct ETH balance', async function () {
const balance = await driver.findElement(By.css('[data-testid="eth-overview__primary-currency"]')) const balance = await driver.findElement(By.css('[data-testid="eth-overview__primary-currency"]'))
await driver.delay(regularDelayMs) await driver.delay(regularDelayMs)
await driver.wait(until.elementTextMatches(balance, /^87.*\s*ETH.*$/), 10000) await driver.wait(until.elementTextMatches(balance, /^87.*\s*ETH.*$/u), 10000)
const tokenAmount = await balance.getText() const tokenAmount = await balance.getText()
assert.ok(/^87.*\s*ETH.*$/.test(tokenAmount)) assert.ok(/^87.*\s*ETH.*$/u.test(tokenAmount))
await driver.delay(regularDelayMs) await driver.delay(regularDelayMs)
}) })
}) })
@ -797,7 +797,7 @@ describe('MetaMask', function () {
await driver.delay(tinyDelayMs) await driver.delay(tinyDelayMs)
const tokenContractAddress = await driver.findElement(By.css('#tokenAddress')) const tokenContractAddress = await driver.findElement(By.css('#tokenAddress'))
await driver.wait(until.elementTextMatches(tokenContractAddress, /0x/)) await driver.wait(until.elementTextMatches(tokenContractAddress, /0x/u))
tokenAddress = await tokenContractAddress.getText() tokenAddress = await tokenContractAddress.getText()
await driver.delay(regularDelayMs) await driver.delay(regularDelayMs)
@ -830,9 +830,9 @@ describe('MetaMask', function () {
it('renders the balance for the new token', async function () { it('renders the balance for the new token', async function () {
const balance = await driver.findElement(By.css('.wallet-overview .token-overview__primary-balance')) const balance = await driver.findElement(By.css('.wallet-overview .token-overview__primary-balance'))
await driver.wait(until.elementTextMatches(balance, /^10\s*TST\s*$/)) await driver.wait(until.elementTextMatches(balance, /^10\s*TST\s*$/u))
const tokenAmount = await balance.getText() const tokenAmount = await balance.getText()
assert.ok(/^10\s*TST\s*$/.test(tokenAmount)) assert.ok(/^10\s*TST\s*$/u.test(tokenAmount))
await driver.delay(regularDelayMs) await driver.delay(regularDelayMs)
}) })
}) })
@ -887,7 +887,7 @@ describe('MetaMask', function () {
const confirmDataText = await confirmDataDiv.getText() const confirmDataText = await confirmDataDiv.getText()
await driver.delay(regularDelayMs) await driver.delay(regularDelayMs)
assert(confirmDataText.match(/0xa9059cbb0000000000000000000000002f318c334780961fb129d2a6c30d0763d9a5c97/)) assert(confirmDataText.match(/0xa9059cbb0000000000000000000000002f318c334780961fb129d2a6c30d0763d9a5c97/u))
await driver.clickElement(By.xpath(`//li[contains(text(), 'Details')]`)) await driver.clickElement(By.xpath(`//li[contains(text(), 'Details')]`))
await driver.delay(regularDelayMs) await driver.delay(regularDelayMs)
@ -906,10 +906,10 @@ describe('MetaMask', function () {
const txValues = await driver.findElements(By.css('.transaction-list-item__primary-currency')) const txValues = await driver.findElements(By.css('.transaction-list-item__primary-currency'))
assert.equal(txValues.length, 1) assert.equal(txValues.length, 1)
await driver.wait(until.elementTextMatches(txValues[0], /-1\s*TST/), 10000) await driver.wait(until.elementTextMatches(txValues[0], /-1\s*TST/u), 10000)
const txStatuses = await driver.findElements(By.css('.list-item__heading')) const txStatuses = await driver.findElements(By.css('.list-item__heading'))
await driver.wait(until.elementTextMatches(txStatuses[0], /Send\sTST/i), 10000) await driver.wait(until.elementTextMatches(txStatuses[0], /Send\sTST/u), 10000)
}) })
}) })
@ -931,7 +931,7 @@ describe('MetaMask', function () {
await driver.findElements(By.css('.transaction-list__pending-transactions')) await driver.findElements(By.css('.transaction-list__pending-transactions'))
const txListValue = await driver.findClickableElement(By.css('.transaction-list-item__primary-currency')) const txListValue = await driver.findClickableElement(By.css('.transaction-list-item__primary-currency'))
await driver.wait(until.elementTextMatches(txListValue, /-1.5\s*TST/), 10000) await driver.wait(until.elementTextMatches(txListValue, /-1.5\s*TST/u), 10000)
await txListValue.click() await txListValue.click()
await driver.delay(regularDelayMs) await driver.delay(regularDelayMs)
@ -987,12 +987,12 @@ describe('MetaMask', function () {
}, 10000) }, 10000)
const txValues = await driver.findElements(By.css('.transaction-list-item__primary-currency')) const txValues = await driver.findElements(By.css('.transaction-list-item__primary-currency'))
await driver.wait(until.elementTextMatches(txValues[0], /-1.5\s*TST/)) await driver.wait(until.elementTextMatches(txValues[0], /-1.5\s*TST/u))
const txStatuses = await driver.findElements(By.css('.list-item__heading')) const txStatuses = await driver.findElements(By.css('.list-item__heading'))
await driver.wait(until.elementTextMatches(txStatuses[0], /Send\sTST/), 10000) await driver.wait(until.elementTextMatches(txStatuses[0], /Send\sTST/u), 10000)
const tokenBalanceAmount = await driver.findElements(By.css('.token-overview__primary-balance')) const tokenBalanceAmount = await driver.findElements(By.css('.token-overview__primary-balance'))
await driver.wait(until.elementTextMatches(tokenBalanceAmount[0], /7.5\s*TST/), 10000) await driver.wait(until.elementTextMatches(tokenBalanceAmount[0], /7.5\s*TST/u), 10000)
}) })
}) })
@ -1019,7 +1019,7 @@ describe('MetaMask', function () {
}, 10000) }, 10000)
const [txtListHeading] = await driver.findElements(By.css('.transaction-list-item .list-item__heading')) const [txtListHeading] = await driver.findElements(By.css('.transaction-list-item .list-item__heading'))
await driver.wait(until.elementTextMatches(txtListHeading, /Approve TST spend limit/)) await driver.wait(until.elementTextMatches(txtListHeading, /Approve TST spend limit/u))
await driver.clickElement(By.css('.transaction-list-item')) await driver.clickElement(By.css('.transaction-list-item'))
await driver.delay(regularDelayMs) await driver.delay(regularDelayMs)
}) })
@ -1034,7 +1034,7 @@ describe('MetaMask', function () {
const confirmDataDiv = await driver.findElement(By.css('.confirm-approve-content__data__data-block')) const confirmDataDiv = await driver.findElement(By.css('.confirm-approve-content__data__data-block'))
const confirmDataText = await confirmDataDiv.getText() const confirmDataText = await confirmDataDiv.getText()
assert(confirmDataText.match(/0x095ea7b30000000000000000000000009bc5baf874d2da8d216ae9f137804184ee5afef4/)) assert(confirmDataText.match(/0x095ea7b30000000000000000000000009bc5baf874d2da8d216ae9f137804184ee5afef4/u))
}) })
it('opens the gas edit modal', async function () { it('opens the gas edit modal', async function () {
@ -1105,7 +1105,7 @@ describe('MetaMask', function () {
}, 10000) }, 10000)
const txStatuses = await driver.findElements(By.css('.list-item__heading')) const txStatuses = await driver.findElements(By.css('.list-item__heading'))
await driver.wait(until.elementTextMatches(txStatuses[0], /Approve TST spend limit/)) await driver.wait(until.elementTextMatches(txStatuses[0], /Approve TST spend limit/u))
}) })
}) })
@ -1130,7 +1130,7 @@ describe('MetaMask', function () {
}, 10000) }, 10000)
const [txListValue] = await driver.findElements(By.css('.transaction-list-item__primary-currency')) const [txListValue] = await driver.findElements(By.css('.transaction-list-item__primary-currency'))
await driver.wait(until.elementTextMatches(txListValue, /-1.5\s*TST/)) await driver.wait(until.elementTextMatches(txListValue, /-1.5\s*TST/u))
await driver.clickElement(By.css('.transaction-list-item')) await driver.clickElement(By.css('.transaction-list-item'))
await driver.delay(regularDelayMs) await driver.delay(regularDelayMs)
}) })
@ -1148,9 +1148,9 @@ describe('MetaMask', function () {
}, 10000) }, 10000)
const txValues = await driver.findElements(By.css('.transaction-list-item__primary-currency')) const txValues = await driver.findElements(By.css('.transaction-list-item__primary-currency'))
await driver.wait(until.elementTextMatches(txValues[0], /-1.5\s*TST/)) await driver.wait(until.elementTextMatches(txValues[0], /-1.5\s*TST/u))
const txStatuses = await driver.findElements(By.css('.list-item__heading')) const txStatuses = await driver.findElements(By.css('.list-item__heading'))
await driver.wait(until.elementTextMatches(txStatuses[0], /Send TST/)) await driver.wait(until.elementTextMatches(txStatuses[0], /Send TST/u))
}) })
}) })
@ -1176,7 +1176,7 @@ describe('MetaMask', function () {
}, 10000) }, 10000)
const [txtListHeading] = await driver.findElements(By.css('.transaction-list-item .list-item__heading')) const [txtListHeading] = await driver.findElements(By.css('.transaction-list-item .list-item__heading'))
await driver.wait(until.elementTextMatches(txtListHeading, /Approve TST spend limit/)) await driver.wait(until.elementTextMatches(txtListHeading, /Approve TST spend limit/u))
await driver.clickElement(By.css('.transaction-list-item')) await driver.clickElement(By.css('.transaction-list-item'))
await driver.delay(regularDelayMs) await driver.delay(regularDelayMs)
}) })
@ -1203,7 +1203,7 @@ describe('MetaMask', function () {
}, 10000) }, 10000)
const txStatuses = await driver.findElements(By.css('.list-item__heading')) const txStatuses = await driver.findElements(By.css('.list-item__heading'))
await driver.wait(until.elementTextMatches(txStatuses[0], /Approve TST spend limit/)) await driver.wait(until.elementTextMatches(txStatuses[0], /Approve TST spend limit/u))
}) })
}) })
@ -1244,7 +1244,7 @@ describe('MetaMask', function () {
it('renders the balance for the chosen token', async function () { it('renders the balance for the chosen token', async function () {
const balance = await driver.findElement(By.css('.token-overview__primary-balance')) const balance = await driver.findElement(By.css('.token-overview__primary-balance'))
await driver.wait(until.elementTextMatches(balance, /0\s*BAT/)) await driver.wait(until.elementTextMatches(balance, /0\s*BAT/u))
await driver.delay(regularDelayMs) await driver.delay(regularDelayMs)
}) })
}) })

View File

@ -32,6 +32,7 @@ const server = http.createServer(requestHandler)
server.listen(port, (err) => { server.listen(port, (err) => {
if (err) { if (err) {
return console.log('mock 3box server error: ', err) console.log('mock 3box server error: ', err)
return
} }
}) })

View File

@ -90,11 +90,11 @@ describe('MetaMask', function () {
}) })
it('gets the current accounts address', async function () { it('gets the current accounts address', async function () {
const addressInput = await driver.findElement(By.css('.qr-ellip-address')) const addressInput = await driver.findElement(By.css('.readonly-input__input'))
publicAddress = await addressInput.getAttribute('value') publicAddress = await addressInput.getAttribute('value')
const accountModal = await driver.findElement(By.css('span .modal')) const accountModal = await driver.findElement(By.css('span .modal'))
await driver.clickElement(By.css('.account-modal-close')) await driver.clickElement(By.css('.account-modal__close'))
await driver.wait(until.stalenessOf(accountModal)) await driver.wait(until.stalenessOf(accountModal))
await driver.delay(regularDelayMs) await driver.delay(regularDelayMs)

View File

@ -205,7 +205,7 @@ describe('Using MetaMask with an existing account', function () {
const txValues = await driver.findElements(By.css('.transaction-list-item__primary-currency')) const txValues = await driver.findElements(By.css('.transaction-list-item__primary-currency'))
assert.equal(txValues.length, 1) assert.equal(txValues.length, 1)
assert.ok(/-2.2\s*ETH/.test(await txValues[0].getText())) assert.ok(/-2.2\s*ETH/u.test(await txValues[0].getText()))
}) })
}) })
}) })

View File

@ -124,11 +124,11 @@ describe('MetaMask', function () {
await driver.clickElement(By.css('[data-testid="account-options-menu__account-details"]')) await driver.clickElement(By.css('[data-testid="account-options-menu__account-details"]'))
await driver.delay(regularDelayMs) await driver.delay(regularDelayMs)
const addressInput = await driver.findElement(By.css('.qr-ellip-address')) const addressInput = await driver.findElement(By.css('.readonly-input__input'))
const newPublicAddress = await addressInput.getAttribute('value') const newPublicAddress = await addressInput.getAttribute('value')
const accountModal = await driver.findElement(By.css('span .modal')) const accountModal = await driver.findElement(By.css('span .modal'))
await driver.clickElement(By.css('.account-modal-close')) await driver.clickElement(By.css('.account-modal__close'))
await driver.wait(until.stalenessOf(accountModal)) await driver.wait(until.stalenessOf(accountModal))
await driver.delay(regularDelayMs) await driver.delay(regularDelayMs)

View File

@ -20,7 +20,7 @@ describe('Localization', function () {
await passwordField.sendKeys(Key.ENTER) await passwordField.sendKeys(Key.ENTER)
const secondaryBalance = await driver.findElement(By.css('[data-testid="eth-overview__secondary-currency"]')) const secondaryBalance = await driver.findElement(By.css('[data-testid="eth-overview__secondary-currency"]'))
const secondaryBalanceText = await secondaryBalance.getText() const secondaryBalanceText = await secondaryBalance.getText()
const [fiatAmount, fiatUnit] = secondaryBalanceText.trim().split(/\s+/) const [fiatAmount, fiatUnit] = secondaryBalanceText.trim().split(/\s+/u)
assert.ok(fiatAmount.startsWith('₱')) assert.ok(fiatAmount.startsWith('₱'))
assert.equal(fiatUnit, 'PHP') assert.equal(fiatUnit, 'PHP')
}, },

View File

@ -97,7 +97,7 @@ describe('MetaMask', function () {
it('balance renders', async function () { it('balance renders', async function () {
const balance = await driver.findElement(By.css('[data-testid="wallet-balance"] .list-item__heading')) const balance = await driver.findElement(By.css('[data-testid="wallet-balance"] .list-item__heading'))
await driver.wait(until.elementTextMatches(balance, /25\s*ETH/)) await driver.wait(until.elementTextMatches(balance, /25\s*ETH/u))
await driver.delay(regularDelayMs) await driver.delay(regularDelayMs)
}) })
}) })
@ -203,7 +203,7 @@ describe('MetaMask', function () {
it('balance renders', async function () { it('balance renders', async function () {
const balance = await driver2.findElement(By.css('[data-testid="wallet-balance"] .list-item__heading')) const balance = await driver2.findElement(By.css('[data-testid="wallet-balance"] .list-item__heading'))
await driver2.wait(until.elementTextMatches(balance, /25\s*ETH/)) await driver2.wait(until.elementTextMatches(balance, /25\s*ETH/u))
await driver2.delay(regularDelayMs) await driver2.delay(regularDelayMs)
}) })
}) })

View File

@ -180,7 +180,9 @@ class Driver {
await fs.writeFile(`${filepathBase}-screenshot.png`, screenshot, { encoding: 'base64' }) await fs.writeFile(`${filepathBase}-screenshot.png`, screenshot, { encoding: 'base64' })
const htmlSource = await this.driver.getPageSource() const htmlSource = await this.driver.getPageSource()
await fs.writeFile(`${filepathBase}-dom.html`, htmlSource) await fs.writeFile(`${filepathBase}-dom.html`, htmlSource)
const uiState = await this.driver.executeScript(() => window.getCleanAppState()) const uiState = await this.driver.executeScript(
() => window.getCleanAppState && window.getCleanAppState(),
)
await fs.writeFile(`${filepathBase}-state.json`, JSON.stringify(uiState, null, 2)) await fs.writeFile(`${filepathBase}-state.json`, JSON.stringify(uiState, null, 2))
} }

View File

@ -45,7 +45,7 @@ async function setupFetchMocking (driver) {
return { json: async () => clone(fetchMockResponses.ethGasBasic) } return { json: async () => clone(fetchMockResponses.ethGasBasic) }
} else if (url.match(/http(s?):\/\/ethgasstation\.info\/json\/predictTable.*/u)) { } else if (url.match(/http(s?):\/\/ethgasstation\.info\/json\/predictTable.*/u)) {
return { json: async () => clone(fetchMockResponses.ethGasPredictTable) } return { json: async () => clone(fetchMockResponses.ethGasPredictTable) }
} else if (url.match(/chromeextensionmm/)) { } else if (url.match(/chromeextensionmm/u)) {
return { json: async () => clone(fetchMockResponses.metametrics) } return { json: async () => clone(fetchMockResponses.metametrics) }
} }
return window.origFetch(...args) return window.origFetch(...args)

View File

@ -80,7 +80,7 @@ require('abortcontroller-polyfill/dist/polyfill-patch-fetch')
window.localStorage = {} window.localStorage = {}
// override metamask-logo // override metamask-logo
window.requestAnimationFrame = () => {} window.requestAnimationFrame = () => undefined
// crypto.getRandomValues // crypto.getRandomValues
if (!window.crypto) { if (!window.crypto) {

View File

@ -27,7 +27,7 @@ export function mountWithRouter (component, store = {}, pathname = '/') {
context: { context: {
router, router,
t: (str) => str, t: (str) => str,
metricsEvent: () => {}, metricsEvent: () => undefined,
store, store,
}, },
childContextTypes: { childContextTypes: {

View File

@ -1,7 +1,3 @@
/* eslint-disable no-native-reassign */
// this is what we're testing
import '../../app/scripts/lib/freezeGlobals' import '../../app/scripts/lib/freezeGlobals'
import assert from 'assert' import assert from 'assert'
@ -10,6 +6,7 @@ describe('Promise global is immutable', function () {
it('throws when reassinging promise (syntax 1)', function () { it('throws when reassinging promise (syntax 1)', function () {
try { try {
// eslint-disable-next-line no-global-assign,no-native-reassign
Promise = {} Promise = {}
assert.fail('did not throw error') assert.fail('did not throw error')
} catch (err) { } catch (err) {
@ -28,7 +25,7 @@ describe('Promise global is immutable', function () {
it('throws when mutating existing Promise property', function () { it('throws when mutating existing Promise property', function () {
try { try {
Promise.all = () => {} Promise.all = () => undefined
assert.fail('did not throw error') assert.fail('did not throw error')
} catch (err) { } catch (err) {
assert.ok(err, 'did throw error') assert.ok(err, 'did throw error')

View File

@ -9,7 +9,7 @@ describe('CachedBalancesController', function () {
getNetwork: () => Promise.resolve(17), getNetwork: () => Promise.resolve(17),
accountTracker: { accountTracker: {
store: { store: {
subscribe: () => {}, subscribe: () => undefined,
}, },
}, },
initState: { initState: {
@ -32,7 +32,7 @@ describe('CachedBalancesController', function () {
const controller = new CachedBalancesController({ const controller = new CachedBalancesController({
accountTracker: { accountTracker: {
store: { store: {
subscribe: () => {}, subscribe: () => undefined,
}, },
}, },
initState: { initState: {
@ -75,7 +75,7 @@ describe('CachedBalancesController', function () {
const controller = new CachedBalancesController({ const controller = new CachedBalancesController({
accountTracker: { accountTracker: {
store: { store: {
subscribe: () => {}, subscribe: () => undefined,
}, },
}, },
initState: { initState: {

View File

@ -14,7 +14,7 @@ describe('DetectTokensController', function () {
const sandbox = sinon.createSandbox() const sandbox = sinon.createSandbox()
let keyringMemStore, network, preferences let keyringMemStore, network, preferences
const noop = () => {} const noop = () => undefined
const networkControllerProviderConfig = { const networkControllerProviderConfig = {
getAccounts: noop, getAccounts: noop,
@ -24,7 +24,7 @@ describe('DetectTokensController', function () {
nock('https://api.infura.io') nock('https://api.infura.io')
.get(/.*/) .get(/.*/u)
.reply(200) .reply(200)
keyringMemStore = new ObservableStore({ isUnlocked: false }) keyringMemStore = new ObservableStore({ isUnlocked: false })

View File

@ -1,7 +1,6 @@
import assert from 'assert' import assert from 'assert'
import sinon from 'sinon' import sinon from 'sinon'
import ObservableStore from 'obs-store' import ObservableStore from 'obs-store'
import HttpProvider from 'ethjs-provider-http'
import EnsController from '../../../../app/scripts/controllers/ens' import EnsController from '../../../../app/scripts/controllers/ens'
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000' const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
@ -10,11 +9,10 @@ const ZERO_X_ERROR_ADDRESS = '0x'
describe('EnsController', function () { describe('EnsController', function () {
describe('#constructor', function () { describe('#constructor', function () {
it('should construct the controller given a provider and a network', async function () { it('should construct the controller given a provider and a network', async function () {
const provider = new HttpProvider('https://ropsten.infura.io')
const currentNetworkId = '3' const currentNetworkId = '3'
const networkStore = new ObservableStore(currentNetworkId) const networkStore = new ObservableStore(currentNetworkId)
const ens = new EnsController({ const ens = new EnsController({
provider, provider: { },
networkStore, networkStore,
}) })

View File

@ -19,7 +19,7 @@ import proxyquire from 'proxyquire'
class ThreeBoxControllerMock { class ThreeBoxControllerMock {
constructor () { constructor () {
this.store = { this.store = {
subscribe: () => {}, subscribe: () => undefined,
getState: () => ({}), getState: () => ({}),
} }
this.init = threeBoxSpies.init this.init = threeBoxSpies.init
@ -78,7 +78,7 @@ const CUSTOM_RPC_URL = 'http://localhost:8545'
describe('MetaMaskController', function () { describe('MetaMaskController', function () {
let metamaskController let metamaskController
const sandbox = sinon.createSandbox() const sandbox = sinon.createSandbox()
const noop = () => {} const noop = () => undefined
beforeEach(function () { beforeEach(function () {
@ -92,12 +92,12 @@ describe('MetaMaskController', function () {
nock('https://api.infura.io') nock('https://api.infura.io')
.persist() .persist()
.get(/.*/) .get(/.*/u)
.reply(200) .reply(200)
nock('https://min-api.cryptocompare.com') nock('https://min-api.cryptocompare.com')
.persist() .persist()
.get(/.*/) .get(/.*/u)
.reply(200, '{"JPY":12415.9}') .reply(200, '{"JPY":12415.9}')
metamaskController = new MetaMaskController({ metamaskController = new MetaMaskController({
@ -113,7 +113,7 @@ describe('MetaMaskController', function () {
}, },
}, },
initState: cloneDeep(firstTimeState), initState: cloneDeep(firstTimeState),
platform: { showTransactionNotification: () => {} }, platform: { showTransactionNotification: () => undefined },
}) })
// disable diagnostics // disable diagnostics
metamaskController.diagnostics = null metamaskController.diagnostics = null
@ -819,7 +819,8 @@ describe('MetaMaskController', function () {
const { promise, resolve } = deferredPromise() const { promise, resolve } = deferredPromise()
const streamTest = createThoughStream((chunk, _, cb) => { const streamTest = createThoughStream((chunk, _, cb) => {
if (chunk.name !== 'phishing') { if (chunk.name !== 'phishing') {
return cb() cb()
return
} }
assert.equal(chunk.data.hostname, (new URL(phishingMessageSender.url)).hostname) assert.equal(chunk.data.hostname, (new URL(phishingMessageSender.url)).hostname)
resolve() resolve()

View File

@ -6,7 +6,7 @@ import { getNetworkDisplayName } from '../../../../../app/scripts/controllers/ne
describe('NetworkController', function () { describe('NetworkController', function () {
describe('controller', function () { describe('controller', function () {
let networkController let networkController
const noop = () => {} const noop = () => undefined
const networkControllerProviderConfig = { const networkControllerProviderConfig = {
getAccounts: noop, getAccounts: noop,
} }

View File

@ -20,7 +20,7 @@ import {
* - Immutable mock values like Ethereum accounts and expected states * - Immutable mock values like Ethereum accounts and expected states
*/ */
export const noop = () => {} export const noop = () => undefined
/** /**
* Mock Permissions Controller and Middleware * Mock Permissions Controller and Middleware

View File

@ -372,7 +372,7 @@ describe('preferences controller', function () {
beforeEach(function () { beforeEach(function () {
req = { params: {} } req = { params: {} }
res = {} res = {}
asy = { next: () => {}, end: () => {} } asy = { next: () => undefined, end: () => undefined }
stubNext = sandbox.stub(asy, 'next') stubNext = sandbox.stub(asy, 'next')
stubEnd = sandbox.stub(asy, 'end').returns(0) stubEnd = sandbox.stub(asy, 'end').returns(0)
stubHandleWatchAssetERC20 = sandbox.stub(preferencesController, '_handleWatchAssetERC20') stubHandleWatchAssetERC20 = sandbox.stub(preferencesController, '_handleWatchAssetERC20')
@ -382,7 +382,7 @@ describe('preferences controller', function () {
}) })
it('shouldn not do anything if method not corresponds', async function () { it('shouldn not do anything if method not corresponds', async function () {
const asy = { next: () => {}, end: () => {} } const asy = { next: () => undefined, end: () => undefined }
const stubNext = sandbox.stub(asy, 'next') const stubNext = sandbox.stub(asy, 'next')
const stubEnd = sandbox.stub(asy, 'end').returns(0) const stubEnd = sandbox.stub(asy, 'end').returns(0)
req.method = 'metamask' req.method = 'metamask'
@ -391,7 +391,7 @@ describe('preferences controller', function () {
sandbox.assert.called(stubNext) sandbox.assert.called(stubNext)
}) })
it('should do something if method is supported', async function () { it('should do something if method is supported', async function () {
const asy = { next: () => {}, end: () => {} } const asy = { next: () => undefined, end: () => undefined }
const stubNext = sandbox.stub(asy, 'next') const stubNext = sandbox.stub(asy, 'next')
const stubEnd = sandbox.stub(asy, 'end').returns(0) const stubEnd = sandbox.stub(asy, 'end').returns(0)
req.method = 'metamask_watchAsset' req.method = 'metamask_watchAsset'
@ -415,7 +415,7 @@ describe('preferences controller', function () {
assert.deepEqual(res, {}) assert.deepEqual(res, {})
}) })
it('should trigger handle add asset if type supported', async function () { it('should trigger handle add asset if type supported', async function () {
const asy = { next: () => {}, end: () => {} } const asy = { next: () => undefined, end: () => undefined }
req.method = 'metamask_watchAsset' req.method = 'metamask_watchAsset'
req.params.type = 'ERC20' req.params.type = 'ERC20'
await preferencesController.requestWatchAsset(req, res, asy.next, asy.end) await preferencesController.requestWatchAsset(req, res, asy.next, asy.end)
@ -442,7 +442,7 @@ describe('preferences controller', function () {
req.params.options = { address, symbol, decimals, image } req.params.options = { address, symbol, decimals, image }
sandbox.stub(preferencesController, '_validateERC20AssetParams').returns(true) sandbox.stub(preferencesController, '_validateERC20AssetParams').returns(true)
preferencesController.openPopup = async () => {} preferencesController.openPopup = async () => undefined
await preferencesController._handleWatchAssetERC20(req.params.options) await preferencesController._handleWatchAssetERC20(req.params.options)
const suggested = preferencesController.getSuggestedTokens() const suggested = preferencesController.getSuggestedTokens()
@ -478,46 +478,16 @@ describe('preferences controller', function () {
assert.ok(assetImages[address], `set image correctly`) assert.ok(assetImages[address], `set image correctly`)
}) })
it('should validate ERC20 asset correctly', async function () { it('should validate ERC20 asset correctly', async function () {
const validateSpy = sandbox.spy(preferencesController._validateERC20AssetParams) const validate = preferencesController._validateERC20AssetParams
try {
validateSpy({ rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', symbol: 'ABC', decimals: 0 }) assert.doesNotThrow(() => validate({ rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', symbol: 'ABC', decimals: 0 }))
} catch (e) {} assert.throws(() => validate({ symbol: 'ABC', decimals: 0 }), 'missing address should fail')
assert.equal(validateSpy.threw(), false, 'correct options object') assert.throws(() => validate({ rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', decimals: 0 }), 'missing symbol should fail')
const validateSpyAddress = sandbox.spy(preferencesController._validateERC20AssetParams) assert.throws(() => validate({ rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', symbol: 'ABC' }), 'missing decimals should fail')
try { assert.throws(() => validate({ rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', symbol: 'ABCDEFGHI', decimals: 0 }), 'invalid symbol should fail')
validateSpyAddress({ symbol: 'ABC', decimals: 0 }) assert.throws(() => validate({ rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', symbol: 'ABC', decimals: -1 }), 'decimals < 0 should fail')
} catch (e) {} assert.throws(() => validate({ rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', symbol: 'ABC', decimals: 38 }), 'decimals > 36 should fail')
assert.equal(validateSpyAddress.threw(), true, 'options object with no address') assert.throws(() => validate({ rawAddress: '0x123', symbol: 'ABC', decimals: 0 }), 'invalid address should fail')
const validateSpySymbol = sandbox.spy(preferencesController._validateERC20AssetParams)
try {
validateSpySymbol({ rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', decimals: 0 })
} catch (e) {}
assert.equal(validateSpySymbol.threw(), true, 'options object with no symbol')
const validateSpyDecimals = sandbox.spy(preferencesController._validateERC20AssetParams)
try {
validateSpyDecimals({ rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', symbol: 'ABC' })
} catch (e) {}
assert.equal(validateSpyDecimals.threw(), true, 'options object with no decimals')
const validateSpyInvalidSymbol = sandbox.spy(preferencesController._validateERC20AssetParams)
try {
validateSpyInvalidSymbol({ rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', symbol: 'ABCDEFGHI', decimals: 0 })
} catch (e) {}
assert.equal(validateSpyInvalidSymbol.threw(), true, 'options object with invalid symbol')
const validateSpyInvalidDecimals1 = sandbox.spy(preferencesController._validateERC20AssetParams)
try {
validateSpyInvalidDecimals1({ rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', symbol: 'ABCDEFGHI', decimals: -1 })
} catch (e) {}
assert.equal(validateSpyInvalidDecimals1.threw(), true, 'options object with decimals less than zero')
const validateSpyInvalidDecimals2 = sandbox.spy(preferencesController._validateERC20AssetParams)
try {
validateSpyInvalidDecimals2({ rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', symbol: 'ABCDEFGHI', decimals: 38 })
} catch (e) {}
assert.equal(validateSpyInvalidDecimals2.threw(), true, 'options object with decimals more than 36')
const validateSpyInvalidAddress = sandbox.spy(preferencesController._validateERC20AssetParams)
try {
validateSpyInvalidAddress({ rawAddress: '0x123', symbol: 'ABC', decimals: 0 })
} catch (e) {}
assert.equal(validateSpyInvalidAddress.threw(), true, 'options object with address invalid')
}) })
}) })

View File

@ -147,15 +147,15 @@ describe('PendingTransactionTracker', function () {
}, },
nonceTracker: { nonceTracker: {
getGlobalLock: async () => { getGlobalLock: async () => {
return { releaseLock: () => {} } return { releaseLock: () => undefined }
}, },
}, },
getPendingTransactions: () => txList, getPendingTransactions: () => txList,
getCompletedTransactions: () => { getCompletedTransactions: () => {
return [] return []
}, },
publishTransaction: () => {}, publishTransaction: () => undefined,
confirmTransaction: () => {}, confirmTransaction: () => undefined,
}) })
const checkPendingTxStub = sinon.stub(pendingTxTracker, '_checkPendingTx').resolves() const checkPendingTxStub = sinon.stub(pendingTxTracker, '_checkPendingTx').resolves()

View File

@ -13,7 +13,7 @@ import {
SEND_ETHER_ACTION_KEY, SEND_ETHER_ACTION_KEY,
DEPLOY_CONTRACT_ACTION_KEY, DEPLOY_CONTRACT_ACTION_KEY,
CONTRACT_INTERACTION_KEY, CONTRACT_INTERACTION_KEY,
} from '../../../../../ui/app/helpers/constants/transactions.js' } from '../../../../../ui/app/helpers/constants/transactions'
import { createTestProviderTools, getTestAccounts } from '../../../../stub/provider' import { createTestProviderTools, getTestAccounts } from '../../../../stub/provider'
@ -47,7 +47,7 @@ describe('Transaction Controller', function () {
ethTx.sign(fromAccount.key) ethTx.sign(fromAccount.key)
resolve() resolve()
}), }),
getPermittedAccounts: () => {}, getPermittedAccounts: () => undefined,
}) })
txController.nonceTracker.getNonceLock = () => Promise.resolve({ nextNonce: 0, releaseLock: noop }) txController.nonceTracker.getNonceLock = () => Promise.resolve({ nextNonce: 0, releaseLock: noop })
}) })

View File

@ -9,7 +9,7 @@ describe('txUtils', function () {
before(function () { before(function () {
txUtils = new TxUtils(new Proxy({}, { txUtils = new TxUtils(new Proxy({}, {
get: () => { get: () => {
return () => {} return () => undefined
}, },
})) }))
}) })

View File

@ -14,9 +14,6 @@ describe('Message Manager', function () {
assert.ok(Array.isArray(result)) assert.ok(Array.isArray(result))
assert.equal(result.length, 0) assert.equal(result.length, 0)
}) })
it('should also return transactions from local storage if any', function () {
})
}) })
describe('#addMsg', function () { describe('#addMsg', function () {

View File

@ -16,9 +16,10 @@ describe('nodeify', function () {
if (!err) { if (!err) {
assert.equal(res, 'barbaz') assert.equal(res, 'barbaz')
done() done()
} else { return
done(new Error(err.toString()))
} }
done(new Error(err.toString()))
}) })
}) })
@ -37,7 +38,8 @@ describe('nodeify', function () {
try { try {
nodified((err, result) => { nodified((err, result) => {
if (err) { if (err) {
return done(new Error(`should not have thrown any error: ${err.message}`)) done(new Error(`should not have thrown any error: ${err.message}`))
return
} }
assert.equal(42, result, 'got expected result') assert.equal(42, result, 'got expected result')
}) })
@ -54,7 +56,8 @@ describe('nodeify', function () {
try { try {
nodified((err, result) => { nodified((err, result) => {
if (result) { if (result) {
return done(new Error('should not have returned any result')) done(new Error('should not have returned any result'))
return
} }
assert.ok(err, 'got expected error') assert.ok(err, 'got expected error')
assert.ok(err.message.includes('boom!'), 'got expected error message') assert.ok(err.message.includes('boom!'), 'got expected error message')

View File

@ -14,9 +14,6 @@ describe('Personal Message Manager', function () {
assert.ok(Array.isArray(result)) assert.ok(Array.isArray(result))
assert.equal(result.length, 0) assert.equal(result.length, 0)
}) })
it('should also return transactions from local storage if any', function () {
})
}) })
describe('#addMsg', function () { describe('#addMsg', function () {

View File

@ -38,8 +38,10 @@ let nonDeletableCount = 0
let status let status
while (transactions.length <= 100) { while (transactions.length <= 100) {
status = txStates[Math.floor(Math.random() * Math.floor(txStates.length - 1))] status = txStates[Math.floor(Math.random() * Math.floor(txStates.length - 1))]
// This is an old migration, let's allow it
// eslint-disable-next-line no-loop-func
if (!deletableTxStates.find((s) => s === status)) { if (!deletableTxStates.find((s) => s === status)) {
nonDeletableCount++ nonDeletableCount += 1
} }
transactions.push({ status }) transactions.push({ status })
} }
@ -65,7 +67,7 @@ describe('storage is migrated successfully and the proper transactions are remov
const migratedTransactions = migratedData.data.TransactionController.transactions const migratedTransactions = migratedData.data.TransactionController.transactions
migratedTransactions.forEach((tx) => { migratedTransactions.forEach((tx) => {
if (!deletableTxStates.find((s) => s === tx.status)) { if (!deletableTxStates.find((s) => s === tx.status)) {
leftoverNonDeletableTxCount++ leftoverNonDeletableTxCount += 1
} }
}) })
assert.equal(leftoverNonDeletableTxCount, nonDeletableCount, "migration shouldn't delete transactions we want to keep") assert.equal(leftoverNonDeletableTxCount, nonDeletableCount, "migration shouldn't delete transactions we want to keep")

View File

@ -1,5 +1,5 @@
import assert from 'assert' import assert from 'assert'
import migrationTemplate from '../../../app/scripts/migrations/030.js' import migrationTemplate from '../../../app/scripts/migrations/030'
const storage = { const storage = {
meta: {}, meta: {},

View File

@ -50,7 +50,7 @@ describe('migrations', function () {
migrationNumbers = fileNames migrationNumbers = fileNames
.reduce((acc, filename) => { .reduce((acc, filename) => {
const name = filename.split('.')[0] const name = filename.split('.')[0]
if (/^\d+$/.test(name)) { if (/^\d+$/u.test(name)) {
acc.push(name) acc.push(name)
} }
return acc return acc
@ -70,7 +70,7 @@ describe('migrations', function () {
const testNumbers = fileNames const testNumbers = fileNames
.reduce((acc, filename) => { .reduce((acc, filename) => {
const name = filename.split('-test.')[0] const name = filename.split('-test.')[0]
if (/^\d+$/.test(name)) { if (/^\d+$/u.test(name)) {
acc.push(name) acc.push(name)
} }
return acc return acc

View File

@ -19,7 +19,7 @@ const mockStore = (state = defaultState) => configureStore(middleware)(state)
describe('Actions', function () { describe('Actions', function () {
const noop = () => {} const noop = () => undefined
const currentNetworkId = '42' const currentNetworkId = '42'

View File

@ -167,6 +167,23 @@ describe('App State', function () {
}) })
it('clears account details', function () {
const exportPrivKeyModal = {
accountDetail: {
subview: 'export',
accountExport: 'completed',
privateKey: 'a-priv-key',
},
}
const state = { ...metamaskState, appState: { ...exportPrivKeyModal } }
const newState = reduceApp(state, {
type: actions.CLEAR_ACCOUNT_DETAILS,
})
assert.deepStrictEqual(newState.accountDetail, {})
})
it('shoes account page', function () { it('shoes account page', function () {
const state = reduceApp(metamaskState, { const state = reduceApp(metamaskState, {
type: actions.SHOW_ACCOUNTS_PAGE, type: actions.SHOW_ACCOUNTS_PAGE,

View File

@ -0,0 +1,51 @@
import React from 'react'
import PropTypes from 'prop-types'
import { checksumAddress } from '../../../helpers/utils/util'
import Identicon from '../../ui/identicon'
import AccountMismatchWarning from '../../ui/account-mismatch-warning/account-mismatch-warning.component'
export default function AccountListItem ({
account,
className,
displayAddress = false,
handleClick,
icon = null,
}) {
const { name, address, balance } = account || {}
return (
<div
className={`account-list-item ${className}`}
onClick={() => handleClick && handleClick({ name, address, balance })}
>
<div className="account-list-item__top-row">
<Identicon
address={address}
className="account-list-item__identicon"
diameter={18}
/>
<div className="account-list-item__account-name">{ name || address }</div>
{icon && <div className="account-list-item__icon">{ icon }</div>}
<AccountMismatchWarning address={address} />
</div>
{displayAddress && name && (
<div className="account-list-item__account-address">
{ checksumAddress(address) }
</div>
)}
</div>
)
}
AccountListItem.propTypes = {
account: PropTypes.object,
className: PropTypes.string,
displayAddress: PropTypes.bool,
handleClick: PropTypes.func,
icon: PropTypes.node,
}

View File

@ -0,0 +1 @@
export { default } from './account-list-item'

View File

@ -0,0 +1,26 @@
.account-list-item {
&__top-row {
display: flex;
margin-top: 10px;
margin-left: 8px;
position: relative;
}
&__account-name {
font-size: 16px;
margin-left: 8px;
}
&__icon {
position: absolute;
right: 12px;
top: 1px;
}
&__account-address {
margin-left: 35px;
width: 80%;
overflow: hidden;
text-overflow: ellipsis;
}
}

View File

@ -3,9 +3,8 @@ import assert from 'assert'
import { shallow } from 'enzyme' import { shallow } from 'enzyme'
import sinon from 'sinon' import sinon from 'sinon'
import * as utils from '../../../../helpers/utils/util' import * as utils from '../../../../helpers/utils/util'
import Identicon from '../../../../components/ui/identicon' import Identicon from '../../../ui/identicon'
import UserPreferencedCurrencyDisplay from '../../../../components/app/user-preferenced-currency-display' import AccountListItem from '../account-list-item'
import AccountListItem from '../account-list-item.component'
describe('AccountListItem Component', function () { describe('AccountListItem Component', function () {
let wrapper, propsMethodSpies, checksumAddressStub let wrapper, propsMethodSpies, checksumAddressStub
@ -22,11 +21,7 @@ describe('AccountListItem Component', function () {
<AccountListItem <AccountListItem
account={ { address: 'mockAddress', name: 'mockName', balance: 'mockBalance' } } account={ { address: 'mockAddress', name: 'mockName', balance: 'mockBalance' } }
className="mockClassName" className="mockClassName"
conversionRate={4}
currentCurrency="mockCurrentyCurrency"
nativeCurrency="ETH"
displayAddress={false} displayAddress={false}
displayBalance={false}
handleClick={propsMethodSpies.handleClick} handleClick={propsMethodSpies.handleClick}
icon={<i className="mockIcon" />} icon={<i className="mockIcon" />}
/> />
@ -113,36 +108,5 @@ describe('AccountListItem Component', function () {
wrapper.setProps({ account: { address: 'someAddressButNoName' } }) wrapper.setProps({ account: { address: 'someAddressButNoName' } })
assert.equal(wrapper.find('.account-list-item__account-address').length, 0) assert.equal(wrapper.find('.account-list-item__account-address').length, 0)
}) })
it('should render a CurrencyDisplay with the correct props if displayBalance is true', function () {
wrapper.setProps({ displayBalance: true })
assert.equal(wrapper.find(UserPreferencedCurrencyDisplay).length, 2)
assert.deepEqual(
wrapper.find(UserPreferencedCurrencyDisplay).at(0).props(),
{
type: 'PRIMARY',
value: 'mockBalance',
hideTitle: true,
},
)
})
it('should only render one CurrencyDisplay if showFiat is false', function () {
wrapper.setProps({ showFiat: false, displayBalance: true })
assert.equal(wrapper.find(UserPreferencedCurrencyDisplay).length, 1)
assert.deepEqual(
wrapper.find(UserPreferencedCurrencyDisplay).at(0).props(),
{
type: 'PRIMARY',
value: 'mockBalance',
hideTitle: true,
},
)
})
it('should not render a CurrencyDisplay if displayBalance is false', function () {
wrapper.setProps({ displayBalance: false })
assert.equal(wrapper.find(UserPreferencedCurrencyDisplay).length, 0)
})
}) })
}) })

View File

@ -1,63 +0,0 @@
import PropTypes from 'prop-types'
import React, { Component } from 'react'
import Identicon from '../ui/identicon'
import { addressSummary, formatBalance } from '../../helpers/utils/util'
export default class AccountPanel extends Component {
static propTypes = {
identity: PropTypes.object,
account: PropTypes.object,
isFauceting: PropTypes.bool,
}
static defaultProps = {
identity: {},
account: {},
isFauceting: false,
}
render () {
const { identity, account, isFauceting } = this.props
const panelState = {
key: `accountPanel${identity.address}`,
identiconKey: identity.address,
identiconLabel: identity.name || '',
attributes: [
{
key: 'ADDRESS',
value: addressSummary(identity.address),
},
balanceOrFaucetingIndication(account, isFauceting),
],
}
return (
<div
className="identity-panel flex-row flex-space-between"
style={{ flex: '1 0 auto', cursor: panelState.onClick ? 'pointer' : undefined }}
onClick={panelState.onClick}
>
<div className="identicon-wrapper flex-column select-none">
<Identicon address={panelState.identiconKey} />
<span className="font-small">{panelState.identiconLabel.substring(0, 7) + '...'}</span>
</div>
<div className="identity-data flex-column flex-justify-center flex-grow select-none">
{panelState.attributes.map((attr, index) => (
<div className="flex-row flex-space-between" key={index}>
<label className="font-small no-select">{attr.key}</label>
<span className="font-small">{attr.value}</span>
</div>
))}
</div>
</div>
)
}
}
function balanceOrFaucetingIndication (account) {
return {
key: 'BALANCE',
value: formatBalance(account.balance),
}
}

View File

@ -30,7 +30,7 @@ describe('App Header', function () {
<AppHeader.WrappedComponent {...props} />, { <AppHeader.WrappedComponent {...props} />, {
context: { context: {
t: (str) => str, t: (str) => str,
metricsEvent: () => {}, metricsEvent: () => undefined,
}, },
}, },
) )
@ -54,8 +54,8 @@ describe('App Header', function () {
const network = wrapper.find({ network: 'test' }) const network = wrapper.find({ network: 'test' })
network.simulate('click', { network.simulate('click', {
preventDefault: () => {}, preventDefault: () => undefined,
stopPropagation: () => {}, stopPropagation: () => undefined,
}) })
assert(props.showNetworkDropdown.calledOnce) assert(props.showNetworkDropdown.calledOnce)
@ -66,8 +66,8 @@ describe('App Header', function () {
const network = wrapper.find({ network: 'test' }) const network = wrapper.find({ network: 'test' })
network.simulate('click', { network.simulate('click', {
preventDefault: () => {}, preventDefault: () => undefined,
stopPropagation: () => {}, stopPropagation: () => undefined,
}) })
assert(props.hideNetworkDropdown.calledOnce) assert(props.hideNetworkDropdown.calledOnce)

View File

@ -60,7 +60,7 @@ const AssetListItem = ({
: null : null
const sendTokenButton = useMemo(() => { const sendTokenButton = useMemo(() => {
if (tokenAddress == null) { if (tokenAddress === null || tokenAddress === undefined) {
return null return null
} }
return ( return (

View File

@ -1 +1 @@
export { default } from './asset-list.js' export { default } from './asset-list'

Some files were not shown because too many files have changed in this diff Show More