mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-22 17:33:23 +01:00
Unit tests for containers, utils and selectors in send_/
This commit is contained in:
parent
e869d09c79
commit
7c49009854
@ -9,7 +9,7 @@
|
||||
"dist": "gulp dist",
|
||||
"doc": "jsdoc -c development/tools/.jsdoc.json",
|
||||
"test": "npm run test:unit && npm run test:integration && npm run lint",
|
||||
"test:unit": "cross-env METAMASK_ENV=test mocha --exit --require test/setup.js --recursive \"test/unit/**/*.js\"",
|
||||
"test:unit": "cross-env METAMASK_ENV=test mocha --exit --require test/setup.js --recursive \"test/unit/**/*.js\" \"ui/app/**/*.test.js\"",
|
||||
"test:single": "cross-env METAMASK_ENV=test mocha --require test/helper.js",
|
||||
"test:integration": "npm run test:integration:build && npm run test:flat && npm run test:mascara",
|
||||
"test:integration:build": "gulp build:scss",
|
||||
@ -258,6 +258,7 @@
|
||||
"open": "0.0.5",
|
||||
"png-file-stream": "^1.0.0",
|
||||
"prompt": "^1.0.0",
|
||||
"proxyquire": "2.0.1",
|
||||
"qs": "^6.2.0",
|
||||
"qunitjs": "^2.4.1",
|
||||
"radgrad-jsdoc-template": "^1.1.3",
|
||||
|
@ -16,11 +16,11 @@ const {
|
||||
MIN_GAS_PRICE_DEC,
|
||||
MIN_GAS_LIMIT_DEC,
|
||||
MIN_GAS_PRICE_GWEI,
|
||||
} = require('../send/send-constants')
|
||||
} = require('../send_/send.constants')
|
||||
|
||||
const {
|
||||
isBalanceSufficient,
|
||||
} = require('../send/send-utils')
|
||||
} = require('../send_/send.utils')
|
||||
|
||||
const {
|
||||
conversionUtil,
|
||||
|
@ -149,10 +149,10 @@ AddTokenScreen.prototype.validate = function () {
|
||||
errors.customAddress = this.context.t('invalidAddress')
|
||||
}
|
||||
|
||||
const validDecimals = customDecimals !== null
|
||||
&& customDecimals !== ''
|
||||
&& customDecimals >= 0
|
||||
&& customDecimals < 36
|
||||
const validDecimals = customDecimals !== null &&
|
||||
customDecimals !== '' &&
|
||||
customDecimals >= 0 &&
|
||||
customDecimals < 36
|
||||
if (!validDecimals) {
|
||||
errors.customDecimals = this.context.t('decimalsMustZerotoTen')
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ const { conversionUtil } = require('../../conversion-util')
|
||||
const SenderToRecipient = require('../sender-to-recipient')
|
||||
const NetworkDisplay = require('../network-display')
|
||||
|
||||
const { MIN_GAS_PRICE_HEX } = require('../send/send-constants')
|
||||
const { MIN_GAS_PRICE_HEX } = require('../send_/send.constants')
|
||||
|
||||
class ConfirmDeployContract extends Component {
|
||||
constructor (props) {
|
||||
|
@ -17,16 +17,16 @@ const {
|
||||
multiplyCurrencies,
|
||||
} = require('../../conversion-util')
|
||||
const {
|
||||
getGasTotal,
|
||||
calcGasTotal,
|
||||
isBalanceSufficient,
|
||||
} = require('../send/send-utils')
|
||||
} = require('../send_/send.utils')
|
||||
const GasFeeDisplay = require('../send/gas-fee-display-v2')
|
||||
const SenderToRecipient = require('../sender-to-recipient')
|
||||
const NetworkDisplay = require('../network-display')
|
||||
const currencyFormatter = require('currency-formatter')
|
||||
const currencies = require('currency-formatter/currencies')
|
||||
|
||||
const { MIN_GAS_PRICE_HEX } = require('../send/send-constants')
|
||||
const { MIN_GAS_PRICE_HEX } = require('../send_/send.constants')
|
||||
const { SEND_ROUTE, DEFAULT_ROUTE } = require('../../routes')
|
||||
|
||||
import {
|
||||
@ -590,7 +590,7 @@ ConfirmSendEther.prototype.isBalanceSufficient = function (txMeta) {
|
||||
value: amount,
|
||||
},
|
||||
} = txMeta
|
||||
const gasTotal = getGasTotal(gas, gasPrice)
|
||||
const gasTotal = calcGasTotal(gas, gasPrice)
|
||||
|
||||
return isBalanceSufficient({
|
||||
amount,
|
||||
|
@ -20,9 +20,9 @@ const {
|
||||
addCurrencies,
|
||||
} = require('../../conversion-util')
|
||||
const {
|
||||
getGasTotal,
|
||||
calcGasTotal,
|
||||
isBalanceSufficient,
|
||||
} = require('../send/send-utils')
|
||||
} = require('../send_/send.utils')
|
||||
const {
|
||||
calcTokenAmount,
|
||||
} = require('../../token-util')
|
||||
@ -30,7 +30,7 @@ const classnames = require('classnames')
|
||||
const currencyFormatter = require('currency-formatter')
|
||||
const currencies = require('currency-formatter/currencies')
|
||||
|
||||
const { MIN_GAS_PRICE_HEX } = require('../send/send-constants')
|
||||
const { MIN_GAS_PRICE_HEX } = require('../send_/send.constants')
|
||||
|
||||
const {
|
||||
getTokenExchangeRate,
|
||||
@ -580,7 +580,7 @@ ConfirmSendToken.prototype.isBalanceSufficient = function (txMeta) {
|
||||
gasPrice,
|
||||
},
|
||||
} = txMeta
|
||||
const gasTotal = getGasTotal(gas, gasPrice)
|
||||
const gasTotal = calcGasTotal(gas, gasPrice)
|
||||
|
||||
return isBalanceSufficient({
|
||||
amount: '0',
|
||||
|
@ -0,0 +1,32 @@
|
||||
import assert from 'assert'
|
||||
import proxyquire from 'proxyquire'
|
||||
|
||||
let mapStateToProps
|
||||
|
||||
proxyquire('../account-list-item.container.js', {
|
||||
'react-redux': {
|
||||
connect: (ms, md) => {
|
||||
mapStateToProps = ms
|
||||
return () => ({})
|
||||
},
|
||||
},
|
||||
'../send.selectors.js': {
|
||||
getConversionRate: (s) => `mockConversionRate:${s}`,
|
||||
getConvertedCurrency: (s) => `mockCurrentCurrency:${s}`,
|
||||
},
|
||||
})
|
||||
|
||||
describe('account-list-item container', () => {
|
||||
|
||||
describe('mapStateToProps()', () => {
|
||||
|
||||
it('should map the correct properties to props', () => {
|
||||
assert.deepEqual(mapStateToProps('mockState'), {
|
||||
conversionRate: 'mockConversionRate:mockState',
|
||||
currentCurrency: 'mockCurrentCurrency:mockState',
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
@ -0,0 +1,91 @@
|
||||
import assert from 'assert'
|
||||
import proxyquire from 'proxyquire'
|
||||
import sinon from 'sinon'
|
||||
|
||||
let mapStateToProps
|
||||
let mapDispatchToProps
|
||||
|
||||
const actionSpies = {
|
||||
setMaxModeTo: sinon.spy(),
|
||||
updateSendAmount: sinon.spy(),
|
||||
}
|
||||
const duckActionSpies = {
|
||||
updateSendErrors: sinon.spy(),
|
||||
}
|
||||
|
||||
proxyquire('../amount-max-button.container.js', {
|
||||
'react-redux': {
|
||||
connect: (ms, md) => {
|
||||
mapStateToProps = ms
|
||||
mapDispatchToProps = md
|
||||
return () => ({})
|
||||
},
|
||||
},
|
||||
'../../../send.selectors.js': {
|
||||
getGasTotal: (s) => `mockGasTotal:${s}`,
|
||||
getSelectedToken: (s) => `mockSelectedToken:${s}`,
|
||||
getSendFromBalance: (s) => `mockBalance:${s}`,
|
||||
getTokenBalance: (s) => `mockTokenBalance:${s}`,
|
||||
},
|
||||
'./amount-max-button.selectors.js': { getMaxModeOn: (s) => `mockMaxModeOn:${s}` },
|
||||
'./amount-max-button.utils.js': { calcMaxAmount: (mockObj) => mockObj.val + 1 },
|
||||
'../../../../../actions': actionSpies,
|
||||
'../../../../../ducks/send': duckActionSpies,
|
||||
})
|
||||
|
||||
describe('amount-max-button container', () => {
|
||||
|
||||
describe('mapStateToProps()', () => {
|
||||
|
||||
it('should map the correct properties to props', () => {
|
||||
assert.deepEqual(mapStateToProps('mockState'), {
|
||||
balance: 'mockBalance:mockState',
|
||||
gasTotal: 'mockGasTotal:mockState',
|
||||
maxModeOn: 'mockMaxModeOn:mockState',
|
||||
selectedToken: 'mockSelectedToken:mockState',
|
||||
tokenBalance: 'mockTokenBalance:mockState',
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('mapDispatchToProps()', () => {
|
||||
let dispatchSpy
|
||||
let mapDispatchToPropsObject
|
||||
|
||||
beforeEach(() => {
|
||||
dispatchSpy = sinon.spy()
|
||||
mapDispatchToPropsObject = mapDispatchToProps(dispatchSpy)
|
||||
})
|
||||
|
||||
describe('setAmountToMax()', () => {
|
||||
it('should dispatch an action', () => {
|
||||
mapDispatchToPropsObject.setAmountToMax({ val: 11, foo: 'bar' })
|
||||
assert(dispatchSpy.calledTwice)
|
||||
assert(duckActionSpies.updateSendErrors.calledOnce)
|
||||
assert.deepEqual(
|
||||
duckActionSpies.updateSendErrors.getCall(0).args[0],
|
||||
{ amount: null }
|
||||
)
|
||||
assert(actionSpies.updateSendAmount.calledOnce)
|
||||
assert.equal(
|
||||
actionSpies.updateSendAmount.getCall(0).args[0],
|
||||
12
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('setMaxModeTo()', () => {
|
||||
it('should dispatch an action', () => {
|
||||
mapDispatchToPropsObject.setMaxModeTo('mockVal')
|
||||
assert(dispatchSpy.calledOnce)
|
||||
assert.equal(
|
||||
actionSpies.setMaxModeTo.getCall(0).args[0],
|
||||
'mockVal'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
@ -0,0 +1,22 @@
|
||||
import assert from 'assert'
|
||||
import {
|
||||
getMaxModeOn,
|
||||
} from '../amount-max-button.selectors.js'
|
||||
|
||||
describe('amount-max-button selectors', () => {
|
||||
|
||||
describe('getMaxModeOn()', () => {
|
||||
it('should', () => {
|
||||
const state = {
|
||||
metamask: {
|
||||
send: {
|
||||
maxModeOn: null,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
assert.equal(getMaxModeOn(state), null)
|
||||
})
|
||||
})
|
||||
|
||||
})
|
@ -0,0 +1,27 @@
|
||||
import assert from 'assert'
|
||||
import {
|
||||
calcMaxAmount,
|
||||
} from '../amount-max-button.utils.js'
|
||||
|
||||
describe('amount-max-button utils', () => {
|
||||
|
||||
describe('calcMaxAmount()', () => {
|
||||
it('should calculate the correct amount when no selectedToken defined', () => {
|
||||
assert.deepEqual(calcMaxAmount({
|
||||
balance: 'ffffff',
|
||||
gasTotal: 'ff',
|
||||
selectedToken: false,
|
||||
}), 'ffff00')
|
||||
})
|
||||
|
||||
it('should calculate the correct amount when a selectedToken is defined', () => {
|
||||
assert.deepEqual(calcMaxAmount({
|
||||
selectedToken: {
|
||||
decimals: 10,
|
||||
},
|
||||
tokenBalance: 100,
|
||||
}), 'e8d4a51000')
|
||||
})
|
||||
})
|
||||
|
||||
})
|
@ -0,0 +1,109 @@
|
||||
import assert from 'assert'
|
||||
import proxyquire from 'proxyquire'
|
||||
import sinon from 'sinon'
|
||||
|
||||
let mapStateToProps
|
||||
let mapDispatchToProps
|
||||
|
||||
const actionSpies = {
|
||||
setMaxModeTo: sinon.spy(),
|
||||
updateSendAmount: sinon.spy(),
|
||||
}
|
||||
const duckActionSpies = {
|
||||
updateSendErrors: sinon.spy(),
|
||||
}
|
||||
|
||||
proxyquire('../send-amount-row.container.js', {
|
||||
'react-redux': {
|
||||
connect: (ms, md) => {
|
||||
mapStateToProps = ms
|
||||
mapDispatchToProps = md
|
||||
return () => ({})
|
||||
},
|
||||
},
|
||||
'../../send.selectors': {
|
||||
getAmountConversionRate: (s) => `mockAmountConversionRate:${s}`,
|
||||
getConversionRate: (s) => `mockConversionRate:${s}`,
|
||||
getConvertedCurrency: (s) => `mockConvertedCurrency:${s}`,
|
||||
getGasTotal: (s) => `mockGasTotal:${s}`,
|
||||
getPrimaryCurrency: (s) => `mockPrimaryCurrency:${s}`,
|
||||
getSelectedToken: (s) => `mockSelectedToken:${s}`,
|
||||
getSendAmount: (s) => `mockAmount:${s}`,
|
||||
getSendFromBalance: (s) => `mockBalance:${s}`,
|
||||
getTokenBalance: (s) => `mockTokenBalance:${s}`,
|
||||
},
|
||||
'./send-amount-row.selectors': { sendAmountIsInError: (s) => `mockInError:${s}` },
|
||||
'../../send.utils': { getAmountErrorObject: (mockDataObject) => ({ ...mockDataObject, mockChange: true }) },
|
||||
'../../../../actions': actionSpies,
|
||||
'../../../../ducks/send': duckActionSpies,
|
||||
})
|
||||
|
||||
describe('send-amount-row container', () => {
|
||||
|
||||
describe('mapStateToProps()', () => {
|
||||
|
||||
it('should map the correct properties to props', () => {
|
||||
assert.deepEqual(mapStateToProps('mockState'), {
|
||||
amount: 'mockAmount:mockState',
|
||||
amountConversionRate: 'mockAmountConversionRate:mockState',
|
||||
balance: 'mockBalance:mockState',
|
||||
conversionRate: 'mockConversionRate:mockState',
|
||||
convertedCurrency: 'mockConvertedCurrency:mockState',
|
||||
gasTotal: 'mockGasTotal:mockState',
|
||||
inError: 'mockInError:mockState',
|
||||
primaryCurrency: 'mockPrimaryCurrency:mockState',
|
||||
selectedToken: 'mockSelectedToken:mockState',
|
||||
tokenBalance: 'mockTokenBalance:mockState',
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('mapDispatchToProps()', () => {
|
||||
let dispatchSpy
|
||||
let mapDispatchToPropsObject
|
||||
|
||||
beforeEach(() => {
|
||||
dispatchSpy = sinon.spy()
|
||||
mapDispatchToPropsObject = mapDispatchToProps(dispatchSpy)
|
||||
})
|
||||
|
||||
describe('setMaxModeTo()', () => {
|
||||
it('should dispatch an action', () => {
|
||||
mapDispatchToPropsObject.setMaxModeTo('mockBool')
|
||||
assert(dispatchSpy.calledOnce)
|
||||
assert(actionSpies.setMaxModeTo.calledOnce)
|
||||
assert.equal(
|
||||
actionSpies.setMaxModeTo.getCall(0).args[0],
|
||||
'mockBool'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('updateSendAmount()', () => {
|
||||
it('should dispatch an action', () => {
|
||||
mapDispatchToPropsObject.updateSendAmount('mockAmount')
|
||||
assert(dispatchSpy.calledOnce)
|
||||
assert(actionSpies.updateSendAmount.calledOnce)
|
||||
assert.equal(
|
||||
actionSpies.updateSendAmount.getCall(0).args[0],
|
||||
'mockAmount'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('updateSendAmountError()', () => {
|
||||
it('should dispatch an action', () => {
|
||||
mapDispatchToPropsObject.updateSendAmountError({ some: 'data' })
|
||||
assert(dispatchSpy.calledOnce)
|
||||
assert(duckActionSpies.updateSendErrors.calledOnce)
|
||||
assert.deepEqual(
|
||||
duckActionSpies.updateSendErrors.getCall(0).args[0],
|
||||
{ some: 'data', mockChange: true }
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
@ -0,0 +1,34 @@
|
||||
import assert from 'assert'
|
||||
import {
|
||||
sendAmountIsInError,
|
||||
} from '../send-amount-row.selectors.js'
|
||||
|
||||
describe('send-amount-row selectors', () => {
|
||||
|
||||
describe('sendAmountIsInError()', () => {
|
||||
it('should return true if send.errors.amount is truthy', () => {
|
||||
const state = {
|
||||
send: {
|
||||
errors: {
|
||||
amount: 'abc',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
assert.equal(sendAmountIsInError(state), true)
|
||||
})
|
||||
|
||||
it('should return false if send.errors.amount is falsy', () => {
|
||||
const state = {
|
||||
send: {
|
||||
errors: {
|
||||
amount: null,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
assert.equal(sendAmountIsInError(state), false)
|
||||
})
|
||||
})
|
||||
|
||||
})
|
@ -8,7 +8,7 @@ import {
|
||||
import {
|
||||
getFromDropdownOpen,
|
||||
} from './send-from-row.selectors.js'
|
||||
import { calcTokenUpdateAmount } from './send-from-row.utils.js'
|
||||
import { calcTokenBalance } from '../../send.utils.js'
|
||||
import {
|
||||
updateSendFrom,
|
||||
setSendTokenBalance,
|
||||
@ -39,7 +39,7 @@ function mapDispatchToProps (dispatch) {
|
||||
setSendTokenBalance: (usersToken, selectedToken) => {
|
||||
if (!usersToken) return
|
||||
|
||||
const tokenBalance = calcTokenUpdateAmount(selectedToken, selectedToken)
|
||||
const tokenBalance = calcTokenBalance(usersToken, selectedToken)
|
||||
dispatch(setSendTokenBalance(tokenBalance))
|
||||
},
|
||||
}
|
||||
|
@ -1,12 +0,0 @@
|
||||
const {
|
||||
calcTokenAmount,
|
||||
} = require('../../../../token-util')
|
||||
|
||||
function calcTokenUpdateAmount (usersToken, selectedToken) {
|
||||
const { decimals } = selectedToken || {}
|
||||
return calcTokenAmount(usersToken.balance.toString(), decimals)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
calcTokenUpdateAmount,
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
import assert from 'assert'
|
||||
import proxyquire from 'proxyquire'
|
||||
import sinon from 'sinon'
|
||||
|
||||
let mapStateToProps
|
||||
let mapDispatchToProps
|
||||
|
||||
const actionSpies = {
|
||||
updateSendFrom: sinon.spy(),
|
||||
setSendTokenBalance: sinon.spy(),
|
||||
}
|
||||
const duckActionSpies = {
|
||||
closeFromDropdown: sinon.spy(),
|
||||
openFromDropdown: sinon.spy(),
|
||||
}
|
||||
|
||||
proxyquire('../send-from-row.container.js', {
|
||||
'react-redux': {
|
||||
connect: (ms, md) => {
|
||||
mapStateToProps = ms
|
||||
mapDispatchToProps = md
|
||||
return () => ({})
|
||||
},
|
||||
},
|
||||
'../../send.selectors.js': {
|
||||
accountsWithSendEtherInfoSelector: (s) => `mockFromAccounts:${s}`,
|
||||
getConversionRate: (s) => `mockConversionRate:${s}`,
|
||||
getSelectedTokenContract: (s) => `mockTokenContract:${s}`,
|
||||
getSendFromObject: (s) => `mockFrom:${s}`,
|
||||
},
|
||||
'./send-from-row.selectors.js': { getFromDropdownOpen: (s) => `mockFromDropdownOpen:${s}` },
|
||||
'../../send.utils.js': { calcTokenBalance: (a, b) => a + b },
|
||||
'../../../../actions': actionSpies,
|
||||
'../../../../ducks/send': duckActionSpies,
|
||||
})
|
||||
|
||||
describe('send-from-row container', () => {
|
||||
|
||||
describe('mapStateToProps()', () => {
|
||||
|
||||
it('should map the correct properties to props', () => {
|
||||
assert.deepEqual(mapStateToProps('mockState'), {
|
||||
conversionRate: 'mockConversionRate:mockState',
|
||||
from: 'mockFrom:mockState',
|
||||
fromAccounts: 'mockFromAccounts:mockState',
|
||||
fromDropdownOpen: 'mockFromDropdownOpen:mockState',
|
||||
tokenContract: 'mockTokenContract:mockState',
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('mapDispatchToProps()', () => {
|
||||
let dispatchSpy
|
||||
let mapDispatchToPropsObject
|
||||
|
||||
beforeEach(() => {
|
||||
dispatchSpy = sinon.spy()
|
||||
mapDispatchToPropsObject = mapDispatchToProps(dispatchSpy)
|
||||
})
|
||||
|
||||
describe('closeFromDropdown()', () => {
|
||||
it('should dispatch a closeFromDropdown action', () => {
|
||||
mapDispatchToPropsObject.closeFromDropdown()
|
||||
assert(dispatchSpy.calledOnce)
|
||||
assert(duckActionSpies.closeFromDropdown.calledOnce)
|
||||
assert.equal(
|
||||
duckActionSpies.closeFromDropdown.getCall(0).args[0],
|
||||
undefined
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('openFromDropdown()', () => {
|
||||
it('should dispatch a openFromDropdown action', () => {
|
||||
mapDispatchToPropsObject.openFromDropdown()
|
||||
assert(dispatchSpy.calledOnce)
|
||||
assert(duckActionSpies.openFromDropdown.calledOnce)
|
||||
assert.equal(
|
||||
duckActionSpies.openFromDropdown.getCall(0).args[0],
|
||||
undefined
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('updateSendFrom()', () => {
|
||||
it('should dispatch an updateSendFrom action', () => {
|
||||
mapDispatchToPropsObject.updateSendFrom('mockFrom')
|
||||
assert(dispatchSpy.calledOnce)
|
||||
assert.equal(
|
||||
actionSpies.updateSendFrom.getCall(0).args[0],
|
||||
'mockFrom'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('setSendTokenBalance()', () => {
|
||||
it('should dispatch an setSendTokenBalance action', () => {
|
||||
mapDispatchToPropsObject.setSendTokenBalance('mockUsersToken', 'mockSelectedToken')
|
||||
assert(dispatchSpy.calledOnce)
|
||||
assert.equal(
|
||||
actionSpies.setSendTokenBalance.getCall(0).args[0],
|
||||
'mockUsersTokenmockSelectedToken'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
@ -0,0 +1,20 @@
|
||||
import assert from 'assert'
|
||||
import {
|
||||
getFromDropdownOpen,
|
||||
} from '../send-from-row.selectors.js'
|
||||
|
||||
describe('send-from-row selectors', () => {
|
||||
|
||||
describe('getFromDropdownOpen()', () => {
|
||||
it('should get send.fromDropdownOpen', () => {
|
||||
const state = {
|
||||
send: {
|
||||
fromDropdownOpen: null,
|
||||
},
|
||||
}
|
||||
|
||||
assert.equal(getFromDropdownOpen(state), null)
|
||||
})
|
||||
})
|
||||
|
||||
})
|
@ -5,5 +5,5 @@ const selectors = {
|
||||
module.exports = selectors
|
||||
|
||||
function sendGasIsInError (state) {
|
||||
return state.metamask.send.errors.gasLoading
|
||||
return state.send.errors.gasLoading
|
||||
}
|
||||
|
@ -0,0 +1,66 @@
|
||||
import assert from 'assert'
|
||||
import proxyquire from 'proxyquire'
|
||||
import sinon from 'sinon'
|
||||
|
||||
let mapStateToProps
|
||||
let mapDispatchToProps
|
||||
|
||||
const actionSpies = {
|
||||
showModal: sinon.spy(),
|
||||
}
|
||||
|
||||
proxyquire('../send-gas-row.container.js', {
|
||||
'react-redux': {
|
||||
connect: (ms, md) => {
|
||||
mapStateToProps = ms
|
||||
mapDispatchToProps = md
|
||||
return () => ({})
|
||||
},
|
||||
},
|
||||
'../../send.selectors.js': {
|
||||
getConversionRate: (s) => `mockConversionRate:${s}`,
|
||||
getConvertedCurrency: (s) => `mockConvertedCurrency:${s}`,
|
||||
getGasTotal: (s) => `mockGasTotal:${s}`,
|
||||
},
|
||||
'./send-gas-row.selectors.js': { sendGasIsInError: (s) => `mockGasLoadingError:${s}` },
|
||||
'../../../../actions': actionSpies,
|
||||
})
|
||||
|
||||
describe('send-gas-row container', () => {
|
||||
|
||||
describe('mapStateToProps()', () => {
|
||||
|
||||
it('should map the correct properties to props', () => {
|
||||
assert.deepEqual(mapStateToProps('mockState'), {
|
||||
conversionRate: 'mockConversionRate:mockState',
|
||||
convertedCurrency: 'mockConvertedCurrency:mockState',
|
||||
gasTotal: 'mockGasTotal:mockState',
|
||||
gasLoadingError: 'mockGasLoadingError:mockState',
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('mapDispatchToProps()', () => {
|
||||
let dispatchSpy
|
||||
let mapDispatchToPropsObject
|
||||
|
||||
beforeEach(() => {
|
||||
dispatchSpy = sinon.spy()
|
||||
mapDispatchToPropsObject = mapDispatchToProps(dispatchSpy)
|
||||
})
|
||||
|
||||
describe('showCustomizeGasModal()', () => {
|
||||
it('should dispatch an action', () => {
|
||||
mapDispatchToPropsObject.showCustomizeGasModal()
|
||||
assert(dispatchSpy.calledOnce)
|
||||
assert.deepEqual(
|
||||
actionSpies.showModal.getCall(0).args[0],
|
||||
{ name: 'CUSTOMIZE_GAS' }
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
@ -0,0 +1,22 @@
|
||||
import assert from 'assert'
|
||||
import {
|
||||
sendGasIsInError,
|
||||
} from '../send-gas-row.selectors.js'
|
||||
|
||||
describe('send-gas-row selectors', () => {
|
||||
|
||||
describe('sendGasIsInError()', () => {
|
||||
it('should return send.errors.gasLoading', () => {
|
||||
const state = {
|
||||
send: {
|
||||
errors: {
|
||||
gasLoading: 'abc',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
assert.equal(sendGasIsInError(state), 'abc')
|
||||
})
|
||||
})
|
||||
|
||||
})
|
@ -0,0 +1,28 @@
|
||||
import assert from 'assert'
|
||||
import proxyquire from 'proxyquire'
|
||||
|
||||
let mapStateToProps
|
||||
|
||||
proxyquire('../send-row-error-message.container.js', {
|
||||
'react-redux': {
|
||||
connect: (ms, md) => {
|
||||
mapStateToProps = ms
|
||||
return () => ({})
|
||||
},
|
||||
},
|
||||
'../../../send.selectors': { getSendErrors: (s) => `mockErrors:${s}` },
|
||||
})
|
||||
|
||||
describe('send-row-error-message container', () => {
|
||||
|
||||
describe('mapStateToProps()', () => {
|
||||
|
||||
it('should map the correct properties to props', () => {
|
||||
assert.deepEqual(mapStateToProps('mockState', { errorType: 'someType' }), {
|
||||
errors: 'mockErrors:mockState',
|
||||
errorType: 'someType' })
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
@ -0,0 +1,114 @@
|
||||
import assert from 'assert'
|
||||
import proxyquire from 'proxyquire'
|
||||
import sinon from 'sinon'
|
||||
|
||||
let mapStateToProps
|
||||
let mapDispatchToProps
|
||||
|
||||
const actionSpies = {
|
||||
updateSendTo: sinon.spy(),
|
||||
}
|
||||
const duckActionSpies = {
|
||||
closeToDropdown: sinon.spy(),
|
||||
openToDropdown: sinon.spy(),
|
||||
updateSendErrors: sinon.spy(),
|
||||
}
|
||||
|
||||
proxyquire('../send-to-row.container.js', {
|
||||
'react-redux': {
|
||||
connect: (ms, md) => {
|
||||
mapStateToProps = ms
|
||||
mapDispatchToProps = md
|
||||
return () => ({})
|
||||
},
|
||||
},
|
||||
'../../send.selectors.js': {
|
||||
getCurrentNetwork: (s) => `mockNetwork:${s}`,
|
||||
getSendTo: (s) => `mockTo:${s}`,
|
||||
getSendToAccounts: (s) => `mockToAccounts:${s}`,
|
||||
},
|
||||
'./send-to-row.selectors.js': {
|
||||
getToDropdownOpen: (s) => `mockToDropdownOpen:${s}`,
|
||||
sendToIsInError: (s) => `mockInError:${s}`,
|
||||
},
|
||||
'./send-to-row.utils.js': { getToErrorObject: (t) => `mockError:${t}` },
|
||||
'../../../../actions': actionSpies,
|
||||
'../../../../ducks/send': duckActionSpies,
|
||||
})
|
||||
|
||||
describe('send-to-row container', () => {
|
||||
|
||||
describe('mapStateToProps()', () => {
|
||||
|
||||
it('should map the correct properties to props', () => {
|
||||
assert.deepEqual(mapStateToProps('mockState'), {
|
||||
inError: 'mockInError:mockState',
|
||||
network: 'mockNetwork:mockState',
|
||||
to: 'mockTo:mockState',
|
||||
toAccounts: 'mockToAccounts:mockState',
|
||||
toDropdownOpen: 'mockToDropdownOpen:mockState',
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('mapDispatchToProps()', () => {
|
||||
let dispatchSpy
|
||||
let mapDispatchToPropsObject
|
||||
|
||||
beforeEach(() => {
|
||||
dispatchSpy = sinon.spy()
|
||||
mapDispatchToPropsObject = mapDispatchToProps(dispatchSpy)
|
||||
})
|
||||
|
||||
describe('closeToDropdown()', () => {
|
||||
it('should dispatch an action', () => {
|
||||
mapDispatchToPropsObject.closeToDropdown()
|
||||
assert(dispatchSpy.calledOnce)
|
||||
assert(duckActionSpies.closeToDropdown.calledOnce)
|
||||
assert.equal(
|
||||
duckActionSpies.closeToDropdown.getCall(0).args[0],
|
||||
undefined
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('openToDropdown()', () => {
|
||||
it('should dispatch an action', () => {
|
||||
mapDispatchToPropsObject.openToDropdown()
|
||||
assert(dispatchSpy.calledOnce)
|
||||
assert(duckActionSpies.openToDropdown.calledOnce)
|
||||
assert.equal(
|
||||
duckActionSpies.openToDropdown.getCall(0).args[0],
|
||||
undefined
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('updateSendTo()', () => {
|
||||
it('should dispatch an action', () => {
|
||||
mapDispatchToPropsObject.updateSendTo('mockTo', 'mockNickname')
|
||||
assert(dispatchSpy.calledOnce)
|
||||
assert(actionSpies.updateSendTo.calledOnce)
|
||||
assert.deepEqual(
|
||||
actionSpies.updateSendTo.getCall(0).args,
|
||||
['mockTo', 'mockNickname']
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('updateSendToError()', () => {
|
||||
it('should dispatch an action', () => {
|
||||
mapDispatchToPropsObject.updateSendToError('mockTo')
|
||||
assert(dispatchSpy.calledOnce)
|
||||
assert(duckActionSpies.updateSendErrors.calledOnce)
|
||||
assert.equal(
|
||||
duckActionSpies.updateSendErrors.getCall(0).args[0],
|
||||
'mockError:mockTo'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
@ -0,0 +1,47 @@
|
||||
import assert from 'assert'
|
||||
import {
|
||||
getToDropdownOpen,
|
||||
sendToIsInError,
|
||||
} from '../send-to-row.selectors.js'
|
||||
|
||||
describe('send-to-row selectors', () => {
|
||||
|
||||
describe('getToDropdownOpen()', () => {
|
||||
it('should return send.getToDropdownOpen', () => {
|
||||
const state = {
|
||||
send: {
|
||||
toDropdownOpen: false,
|
||||
},
|
||||
}
|
||||
|
||||
assert.equal(getToDropdownOpen(state), false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('sendToIsInError()', () => {
|
||||
it('should return true if send.errors.to is truthy', () => {
|
||||
const state = {
|
||||
send: {
|
||||
errors: {
|
||||
to: 'abc',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
assert.equal(sendToIsInError(state), true)
|
||||
})
|
||||
|
||||
it('should return false if send.errors.to is falsy', () => {
|
||||
const state = {
|
||||
send: {
|
||||
errors: {
|
||||
to: null,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
assert.equal(sendToIsInError(state), false)
|
||||
})
|
||||
})
|
||||
|
||||
})
|
@ -0,0 +1,45 @@
|
||||
import assert from 'assert'
|
||||
import proxyquire from 'proxyquire'
|
||||
import sinon from 'sinon'
|
||||
|
||||
import {
|
||||
REQUIRED_ERROR,
|
||||
INVALID_RECIPIENT_ADDRESS_ERROR,
|
||||
} from '../../../send.constants'
|
||||
|
||||
const stubs = {
|
||||
isValidAddress: sinon.stub().callsFake(to => Boolean(to.match(/^[0xabcdef123456798]+$/))),
|
||||
}
|
||||
|
||||
const toRowUtils = proxyquire('../send-to-row.utils.js', {
|
||||
'../../../../util': {
|
||||
isValidAddress: stubs.isValidAddress,
|
||||
},
|
||||
})
|
||||
const {
|
||||
getToErrorObject,
|
||||
} = toRowUtils
|
||||
|
||||
describe('send-to-row utils', () => {
|
||||
|
||||
describe('getToErrorObject()', () => {
|
||||
it('should return a required error if to is falsy', () => {
|
||||
assert.deepEqual(getToErrorObject(null), {
|
||||
to: REQUIRED_ERROR,
|
||||
})
|
||||
})
|
||||
|
||||
it('should return an invalid recipient error if to is truthy but invalid', () => {
|
||||
assert.deepEqual(getToErrorObject('mockInvalidTo'), {
|
||||
to: INVALID_RECIPIENT_ADDRESS_ERROR,
|
||||
})
|
||||
})
|
||||
|
||||
it('should return null if to is truthy and valid', () => {
|
||||
assert.deepEqual(getToErrorObject('0xabc123'), {
|
||||
to: null,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
})
|
@ -20,10 +20,8 @@ import {
|
||||
getSendToAccounts,
|
||||
getTokenBalance,
|
||||
getUnapprovedTxs,
|
||||
} from '../send.selectors'
|
||||
import {
|
||||
isSendFormInError,
|
||||
} from './send-footer.selectors'
|
||||
} from '../send.selectors'
|
||||
import {
|
||||
addressIsNew,
|
||||
constructTxParams,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { getSendErrors } from '../send.selectors'
|
||||
const { getSendErrors } = require('../send.selectors')
|
||||
|
||||
const selectors = {
|
||||
isSendFormInError,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import ethAbi from 'ethereumjs-abi'
|
||||
import ethUtil from 'ethereumjs-util'
|
||||
import { TOKEN_TRANSFER_FUNCTION_SIGNATURE } from '../send.constants'
|
||||
const ethAbi = require('ethereumjs-abi')
|
||||
const ethUtil = require('ethereumjs-util')
|
||||
const { TOKEN_TRANSFER_FUNCTION_SIGNATURE } = require('../send.constants')
|
||||
|
||||
function formShouldBeDisabled ({ inError, selectedToken, tokenBalance, gasTotal }) {
|
||||
const missingTokenBalance = selectedToken && !tokenBalance
|
||||
@ -47,6 +47,7 @@ function constructUpdatedTx ({
|
||||
}
|
||||
|
||||
if (selectedToken) {
|
||||
console.log(`ethAbi.rawEncode`, ethAbi.rawEncode)
|
||||
const data = TOKEN_TRANSFER_FUNCTION_SIGNATURE + Array.prototype.map.call(
|
||||
ethAbi.rawEncode(['address', 'uint256'], [to, ethUtil.addHexPrefix(amount)]),
|
||||
x => ('00' + x.toString(16)).slice(-2)
|
||||
@ -70,6 +71,8 @@ function constructUpdatedTx ({
|
||||
delete editingTx.txParams.data
|
||||
}
|
||||
}
|
||||
|
||||
return editingTx
|
||||
}
|
||||
|
||||
function addressIsNew (toAccounts, newAddress) {
|
||||
@ -81,4 +84,5 @@ module.exports = {
|
||||
formShouldBeDisabled,
|
||||
constructTxParams,
|
||||
constructUpdatedTx,
|
||||
addHexPrefixToObjectValues,
|
||||
}
|
||||
|
@ -0,0 +1,202 @@
|
||||
import assert from 'assert'
|
||||
import proxyquire from 'proxyquire'
|
||||
import sinon from 'sinon'
|
||||
|
||||
let mapStateToProps
|
||||
let mapDispatchToProps
|
||||
|
||||
const actionSpies = {
|
||||
addToAddressBook: sinon.spy(),
|
||||
clearSend: sinon.spy(),
|
||||
signTokenTx: sinon.spy(),
|
||||
signTx: sinon.spy(),
|
||||
updateTransaction: sinon.spy(),
|
||||
}
|
||||
const utilsStubs = {
|
||||
addressIsNew: sinon.stub().returns(true),
|
||||
constructTxParams: sinon.stub().returns('mockConstructedTxParams'),
|
||||
constructUpdatedTx: sinon.stub().returns('mockConstructedUpdatedTxParams'),
|
||||
formShouldBeDisabled: sinon.stub().returns('mockFormShouldBeDisabled'),
|
||||
}
|
||||
|
||||
proxyquire('../send-footer.container.js', {
|
||||
'react-redux': {
|
||||
connect: (ms, md) => {
|
||||
mapStateToProps = ms
|
||||
mapDispatchToProps = md
|
||||
return () => ({})
|
||||
},
|
||||
},
|
||||
'../../../actions': actionSpies,
|
||||
'../send.selectors': {
|
||||
getGasLimit: (s) => `mockGasLimit:${s}`,
|
||||
getGasPrice: (s) => `mockGasPrice:${s}`,
|
||||
getGasTotal: (s) => `mockGasTotal:${s}`,
|
||||
getSelectedToken: (s) => `mockSelectedToken:${s}`,
|
||||
getSendAmount: (s) => `mockAmount:${s}`,
|
||||
getSendEditingTransactionId: (s) => `mockEditingTransactionId:${s}`,
|
||||
getSendFromObject: (s) => `mockFromObject:${s}`,
|
||||
getSendTo: (s) => `mockTo:${s}`,
|
||||
getSendToAccounts: (s) => `mockToAccounts:${s}`,
|
||||
getTokenBalance: (s) => `mockTokenBalance:${s}`,
|
||||
getUnapprovedTxs: (s) => `mockUnapprovedTxs:${s}`,
|
||||
isSendFormInError: (s) => `mockInError:${s}`,
|
||||
},
|
||||
'./send-footer.selectors': { isSendFormInError: () => {} },
|
||||
'./send-footer.utils': utilsStubs,
|
||||
})
|
||||
|
||||
describe('send-footer container', () => {
|
||||
|
||||
describe('mapStateToProps()', () => {
|
||||
|
||||
it('should map the correct properties to props', () => {
|
||||
assert.deepEqual(mapStateToProps('mockState'), {
|
||||
amount: 'mockAmount:mockState',
|
||||
disabled: 'mockFormShouldBeDisabled',
|
||||
selectedToken: 'mockSelectedToken:mockState',
|
||||
editingTransactionId: 'mockEditingTransactionId:mockState',
|
||||
from: 'mockFromObject:mockState',
|
||||
gasLimit: 'mockGasLimit:mockState',
|
||||
gasPrice: 'mockGasPrice:mockState',
|
||||
inError: 'mockInError:mockState',
|
||||
isToken: true,
|
||||
to: 'mockTo:mockState',
|
||||
toAccounts: 'mockToAccounts:mockState',
|
||||
unapprovedTxs: 'mockUnapprovedTxs:mockState',
|
||||
})
|
||||
assert.deepEqual(
|
||||
utilsStubs.formShouldBeDisabled.getCall(0).args[0],
|
||||
{
|
||||
inError: 'mockInError:mockState',
|
||||
selectedToken: 'mockSelectedToken:mockState',
|
||||
tokenBalance: 'mockTokenBalance:mockState',
|
||||
gasTotal: 'mockGasTotal:mockState',
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('mapDispatchToProps()', () => {
|
||||
let dispatchSpy
|
||||
let mapDispatchToPropsObject
|
||||
|
||||
beforeEach(() => {
|
||||
dispatchSpy = sinon.spy()
|
||||
mapDispatchToPropsObject = mapDispatchToProps(dispatchSpy)
|
||||
})
|
||||
|
||||
describe('clearSend()', () => {
|
||||
it('should dispatch an action', () => {
|
||||
mapDispatchToPropsObject.clearSend()
|
||||
assert(dispatchSpy.calledOnce)
|
||||
assert(actionSpies.clearSend.calledOnce)
|
||||
})
|
||||
})
|
||||
|
||||
describe('sign()', () => {
|
||||
it('should dispatch a signTokenTx action if selectedToken is defined', () => {
|
||||
mapDispatchToPropsObject.sign({
|
||||
selectedToken: {
|
||||
address: '0xabc',
|
||||
},
|
||||
to: 'mockTo',
|
||||
amount: 'mockAmount',
|
||||
from: 'mockFrom',
|
||||
gas: 'mockGas',
|
||||
gasPrice: 'mockGasPrice',
|
||||
})
|
||||
assert(dispatchSpy.calledOnce)
|
||||
assert.deepEqual(
|
||||
utilsStubs.constructTxParams.getCall(0).args[0],
|
||||
{
|
||||
selectedToken: {
|
||||
address: '0xabc',
|
||||
},
|
||||
to: 'mockTo',
|
||||
amount: 'mockAmount',
|
||||
from: 'mockFrom',
|
||||
gas: 'mockGas',
|
||||
gasPrice: 'mockGasPrice',
|
||||
}
|
||||
)
|
||||
assert.deepEqual(
|
||||
actionSpies.signTokenTx.getCall(0).args,
|
||||
[ '0xabc', 'mockTo', 'mockAmount', 'mockConstructedTxParams' ]
|
||||
)
|
||||
})
|
||||
|
||||
it('should dispatch a sign action if selectedToken is not defined', () => {
|
||||
utilsStubs.constructTxParams.resetHistory()
|
||||
mapDispatchToPropsObject.sign({
|
||||
to: 'mockTo',
|
||||
amount: 'mockAmount',
|
||||
from: 'mockFrom',
|
||||
gas: 'mockGas',
|
||||
gasPrice: 'mockGasPrice',
|
||||
})
|
||||
assert(dispatchSpy.calledOnce)
|
||||
assert.deepEqual(
|
||||
utilsStubs.constructTxParams.getCall(0).args[0],
|
||||
{
|
||||
selectedToken: undefined,
|
||||
to: 'mockTo',
|
||||
amount: 'mockAmount',
|
||||
from: 'mockFrom',
|
||||
gas: 'mockGas',
|
||||
gasPrice: 'mockGasPrice',
|
||||
}
|
||||
)
|
||||
assert.deepEqual(
|
||||
actionSpies.signTx.getCall(0).args,
|
||||
[ 'mockConstructedTxParams' ]
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('update()', () => {
|
||||
it('should dispatch an updateTransaction action', () => {
|
||||
mapDispatchToPropsObject.update({
|
||||
to: 'mockTo',
|
||||
amount: 'mockAmount',
|
||||
from: 'mockFrom',
|
||||
gas: 'mockGas',
|
||||
gasPrice: 'mockGasPrice',
|
||||
editingTransactionId: 'mockEditingTransactionId',
|
||||
selectedToken: 'mockSelectedToken',
|
||||
unapprovedTxs: 'mockUnapprovedTxs',
|
||||
})
|
||||
assert(dispatchSpy.calledOnce)
|
||||
assert.deepEqual(
|
||||
utilsStubs.constructUpdatedTx.getCall(0).args[0],
|
||||
{
|
||||
to: 'mockTo',
|
||||
amount: 'mockAmount',
|
||||
from: 'mockFrom',
|
||||
gas: 'mockGas',
|
||||
gasPrice: 'mockGasPrice',
|
||||
editingTransactionId: 'mockEditingTransactionId',
|
||||
selectedToken: 'mockSelectedToken',
|
||||
unapprovedTxs: 'mockUnapprovedTxs',
|
||||
}
|
||||
)
|
||||
assert.equal(actionSpies.updateTransaction.getCall(0).args[0], 'mockConstructedUpdatedTxParams')
|
||||
})
|
||||
})
|
||||
|
||||
describe('addToAddressBookIfNew()', () => {
|
||||
it('should dispatch an action', () => {
|
||||
mapDispatchToPropsObject.addToAddressBookIfNew('mockNewAddress', 'mockToAccounts', 'mockNickname')
|
||||
assert(dispatchSpy.calledOnce)
|
||||
assert.equal(utilsStubs.addressIsNew.getCall(0).args[0], 'mockToAccounts')
|
||||
assert.deepEqual(
|
||||
actionSpies.addToAddressBook.getCall(0).args,
|
||||
[ '0xmockNewAddress', 'mockNickname' ]
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
@ -0,0 +1,242 @@
|
||||
import assert from 'assert'
|
||||
import proxyquire from 'proxyquire'
|
||||
import sinon from 'sinon'
|
||||
const { TOKEN_TRANSFER_FUNCTION_SIGNATURE } = require('../../send.constants')
|
||||
|
||||
const stubs = {
|
||||
rawEncode: sinon.stub().callsFake((arr1, arr2) => {
|
||||
return [ ...arr1, ...arr2 ]
|
||||
}),
|
||||
}
|
||||
|
||||
const sendUtils = proxyquire('../send-footer.utils.js', {
|
||||
'ethereumjs-abi': {
|
||||
rawEncode: stubs.rawEncode,
|
||||
},
|
||||
})
|
||||
const {
|
||||
addressIsNew,
|
||||
formShouldBeDisabled,
|
||||
constructTxParams,
|
||||
constructUpdatedTx,
|
||||
addHexPrefixToObjectValues,
|
||||
} = sendUtils
|
||||
|
||||
describe('send-footer utils', () => {
|
||||
|
||||
describe('addHexPrefixToObjectValues()', () => {
|
||||
it('should return a new object with the same properties with a 0x prefix', () => {
|
||||
assert.deepEqual(
|
||||
addHexPrefixToObjectValues({
|
||||
prop1: '0x123',
|
||||
prop2: '456',
|
||||
prop3: 'x',
|
||||
}),
|
||||
{
|
||||
prop1: '0x123',
|
||||
prop2: '0x456',
|
||||
prop3: '0xx',
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('addressIsNew()', () => {
|
||||
it('should return false if the address exists in toAccounts', () => {
|
||||
assert.equal(
|
||||
addressIsNew([
|
||||
{ address: '0xabc' },
|
||||
{ address: '0xdef' },
|
||||
{ address: '0xghi' },
|
||||
], '0xdef'),
|
||||
false
|
||||
)
|
||||
})
|
||||
|
||||
it('should return true if the address does not exists in toAccounts', () => {
|
||||
assert.equal(
|
||||
addressIsNew([
|
||||
{ address: '0xabc' },
|
||||
{ address: '0xdef' },
|
||||
{ address: '0xghi' },
|
||||
], '0xxyz'),
|
||||
true
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('formShouldBeDisabled()', () => {
|
||||
const config = {
|
||||
'should return true if inError is truthy': {
|
||||
inError: true,
|
||||
expectedResult: true,
|
||||
},
|
||||
'should return true if gasTotal is falsy': {
|
||||
inError: false,
|
||||
gasTotal: false,
|
||||
expectedResult: true,
|
||||
},
|
||||
'should return true if selectedToken is truthy and tokenBalance is falsy': {
|
||||
selectedToken: true,
|
||||
tokenBalance: null,
|
||||
expectedResult: true,
|
||||
},
|
||||
'should return false if inError is false and all other params are truthy': {
|
||||
inError: false,
|
||||
gasTotal: '0x123',
|
||||
selectedToken: true,
|
||||
tokenBalance: 123,
|
||||
expectedResult: false,
|
||||
},
|
||||
}
|
||||
Object.entries(config).map(([description, obj]) => {
|
||||
it(description, () => {
|
||||
assert.equal(formShouldBeDisabled(obj), obj.expectedResult)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('constructTxParams()', () => {
|
||||
it('should return a new txParams object with value and to properties if there is no selectedToken', () => {
|
||||
assert.deepEqual(
|
||||
constructTxParams({
|
||||
selectedToken: false,
|
||||
to: 'mockTo',
|
||||
amount: 'mockAmount',
|
||||
from: 'mockFrom',
|
||||
gas: 'mockGas',
|
||||
gasPrice: 'mockGasPrice',
|
||||
}),
|
||||
{
|
||||
to: '0xmockTo',
|
||||
value: '0xmockAmount',
|
||||
from: '0xmockFrom',
|
||||
gas: '0xmockGas',
|
||||
gasPrice: '0xmockGasPrice',
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('should return a new txParams object without a to property and a 0 value if there is a selectedToken', () => {
|
||||
assert.deepEqual(
|
||||
constructTxParams({
|
||||
selectedToken: true,
|
||||
to: 'mockTo',
|
||||
amount: 'mockAmount',
|
||||
from: 'mockFrom',
|
||||
gas: 'mockGas',
|
||||
gasPrice: 'mockGasPrice',
|
||||
}),
|
||||
{
|
||||
value: '0x0',
|
||||
from: '0xmockFrom',
|
||||
gas: '0xmockGas',
|
||||
gasPrice: '0xmockGasPrice',
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('constructUpdatedTx()', () => {
|
||||
it('should return a new object with an updated txParams', () => {
|
||||
const result = constructUpdatedTx({
|
||||
amount: 'mockAmount',
|
||||
editingTransactionId: '0x456',
|
||||
from: 'mockFrom',
|
||||
gas: 'mockGas',
|
||||
gasPrice: 'mockGasPrice',
|
||||
selectedToken: false,
|
||||
to: 'mockTo',
|
||||
unapprovedTxs: {
|
||||
'0x123': {},
|
||||
'0x456': {
|
||||
unapprovedTxParam: 'someOtherParam',
|
||||
txParams: {
|
||||
data: 'someData',
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
assert.deepEqual(result, {
|
||||
unapprovedTxParam: 'someOtherParam',
|
||||
txParams: {
|
||||
from: '0xmockFrom',
|
||||
gas: '0xmockGas',
|
||||
gasPrice: '0xmockGasPrice',
|
||||
value: '0xmockAmount',
|
||||
to: '0xmockTo',
|
||||
data: '0xsomeData',
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('should not have data property if there is non in the original tx', () => {
|
||||
const result = constructUpdatedTx({
|
||||
amount: 'mockAmount',
|
||||
editingTransactionId: '0x456',
|
||||
from: 'mockFrom',
|
||||
gas: 'mockGas',
|
||||
gasPrice: 'mockGasPrice',
|
||||
selectedToken: false,
|
||||
to: 'mockTo',
|
||||
unapprovedTxs: {
|
||||
'0x123': {},
|
||||
'0x456': {
|
||||
unapprovedTxParam: 'someOtherParam',
|
||||
txParams: {
|
||||
from: 'oldFrom',
|
||||
gas: 'oldGas',
|
||||
gasPrice: 'oldGasPrice',
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
assert.deepEqual(result, {
|
||||
unapprovedTxParam: 'someOtherParam',
|
||||
txParams: {
|
||||
from: '0xmockFrom',
|
||||
gas: '0xmockGas',
|
||||
gasPrice: '0xmockGasPrice',
|
||||
value: '0xmockAmount',
|
||||
to: '0xmockTo',
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('should have token property values if selectedToken is truthy', () => {
|
||||
const result = constructUpdatedTx({
|
||||
amount: 'mockAmount',
|
||||
editingTransactionId: '0x456',
|
||||
from: 'mockFrom',
|
||||
gas: 'mockGas',
|
||||
gasPrice: 'mockGasPrice',
|
||||
selectedToken: {
|
||||
address: 'mockTokenAddress',
|
||||
},
|
||||
to: 'mockTo',
|
||||
unapprovedTxs: {
|
||||
'0x123': {},
|
||||
'0x456': {
|
||||
unapprovedTxParam: 'someOtherParam',
|
||||
txParams: {},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
assert.deepEqual(result, {
|
||||
unapprovedTxParam: 'someOtherParam',
|
||||
txParams: {
|
||||
from: '0xmockFrom',
|
||||
gas: '0xmockGas',
|
||||
gasPrice: '0xmockGasPrice',
|
||||
value: '0x0',
|
||||
to: '0xmockTokenAddress',
|
||||
data: `${TOKEN_TRANSFER_FUNCTION_SIGNATURE}ss56Tont`,
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
})
|
@ -0,0 +1,55 @@
|
||||
import assert from 'assert'
|
||||
import proxyquire from 'proxyquire'
|
||||
import sinon from 'sinon'
|
||||
|
||||
let mapStateToProps
|
||||
let mapDispatchToProps
|
||||
|
||||
const actionSpies = {
|
||||
clearSend: sinon.spy(),
|
||||
}
|
||||
|
||||
proxyquire('../send-header.container.js', {
|
||||
'react-redux': {
|
||||
connect: (ms, md) => {
|
||||
mapStateToProps = ms
|
||||
mapDispatchToProps = md
|
||||
return () => ({})
|
||||
},
|
||||
},
|
||||
'../../../actions': actionSpies,
|
||||
'../../../selectors': { getSelectedToken: (s) => `mockSelectedToken:${s}` },
|
||||
})
|
||||
|
||||
describe('send-header container', () => {
|
||||
|
||||
describe('mapStateToProps()', () => {
|
||||
|
||||
it('should map the correct properties to props', () => {
|
||||
assert.deepEqual(mapStateToProps('mockState'), {
|
||||
isToken: true,
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('mapDispatchToProps()', () => {
|
||||
let dispatchSpy
|
||||
let mapDispatchToPropsObject
|
||||
|
||||
beforeEach(() => {
|
||||
dispatchSpy = sinon.spy()
|
||||
mapDispatchToPropsObject = mapDispatchToProps(dispatchSpy)
|
||||
})
|
||||
|
||||
describe('clearSend()', () => {
|
||||
it('should dispatch an action', () => {
|
||||
mapDispatchToPropsObject.clearSend()
|
||||
assert(dispatchSpy.calledOnce)
|
||||
assert(actionSpies.clearSend.calledOnce)
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
@ -1,5 +1,4 @@
|
||||
import { connect } from 'react-redux'
|
||||
import abi from 'ethereumjs-abi'
|
||||
import SendEther from './send.component'
|
||||
import { withRouter } from 'react-router-dom'
|
||||
import { compose } from 'recompose'
|
||||
@ -46,7 +45,7 @@ function mapStateToProps (state) {
|
||||
amount: getSendAmount(state),
|
||||
amountConversionRate: getAmountConversionRate(state),
|
||||
conversionRate: getConversionRate(state),
|
||||
data: generateTokenTransferData(abi, selectedAddress, selectedToken),
|
||||
data: generateTokenTransferData(selectedAddress, selectedToken),
|
||||
editingTransactionId: getSendEditingTransactionId(state),
|
||||
from: getSendFromObject(state),
|
||||
gasLimit: getGasLimit(state),
|
||||
@ -72,6 +71,7 @@ function mapDispatchToProps (dispatch) {
|
||||
selectedAddress,
|
||||
selectedToken,
|
||||
}) => {
|
||||
console.log(`editingTransactionId`, editingTransactionId)
|
||||
!editingTransactionId
|
||||
? dispatch(updateGasTotal({ selectedAddress, selectedToken, data }))
|
||||
: dispatch(setGasTotal(calcGasTotal(gasLimit, gasPrice)))
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { valuesFor } from '../../util'
|
||||
import abi from 'human-standard-token-abi'
|
||||
import {
|
||||
const { valuesFor } = require('../../util')
|
||||
const abi = require('human-standard-token-abi')
|
||||
const {
|
||||
multiplyCurrencies,
|
||||
} from '../../conversion-util'
|
||||
} = require('../../conversion-util')
|
||||
|
||||
const selectors = {
|
||||
accountsWithSendEtherInfoSelector,
|
||||
autoAddToBetaUI,
|
||||
// autoAddToBetaUI,
|
||||
getAddressBook,
|
||||
getAmountConversionRate,
|
||||
getConversionRate,
|
||||
@ -58,22 +58,22 @@ function accountsWithSendEtherInfoSelector (state) {
|
||||
return accountsWithSendEtherInfo
|
||||
}
|
||||
|
||||
function autoAddToBetaUI (state) {
|
||||
const autoAddTransactionThreshold = 12
|
||||
const autoAddAccountsThreshold = 2
|
||||
const autoAddTokensThreshold = 1
|
||||
// function autoAddToBetaUI (state) {
|
||||
// const autoAddTransactionThreshold = 12
|
||||
// const autoAddAccountsThreshold = 2
|
||||
// const autoAddTokensThreshold = 1
|
||||
|
||||
const numberOfTransactions = state.metamask.selectedAddressTxList.length
|
||||
const numberOfAccounts = Object.keys(state.metamask.accounts).length
|
||||
const numberOfTokensAdded = state.metamask.tokens.length
|
||||
// const numberOfTransactions = state.metamask.selectedAddressTxList.length
|
||||
// const numberOfAccounts = Object.keys(state.metamask.accounts).length
|
||||
// const numberOfTokensAdded = state.metamask.tokens.length
|
||||
|
||||
const userPassesThreshold = (numberOfTransactions > autoAddTransactionThreshold) &&
|
||||
(numberOfAccounts > autoAddAccountsThreshold) &&
|
||||
(numberOfTokensAdded > autoAddTokensThreshold)
|
||||
const userIsNotInBeta = !state.metamask.featureFlags.betaUI
|
||||
// const userPassesThreshold = (numberOfTransactions > autoAddTransactionThreshold) &&
|
||||
// (numberOfAccounts > autoAddAccountsThreshold) &&
|
||||
// (numberOfTokensAdded > autoAddTokensThreshold)
|
||||
// const userIsNotInBeta = !state.metamask.featureFlags.betaUI
|
||||
|
||||
return userIsNotInBeta && userPassesThreshold
|
||||
}
|
||||
// return userIsNotInBeta && userPassesThreshold
|
||||
// }
|
||||
|
||||
function getAddressBook (state) {
|
||||
return state.metamask.addressBook
|
||||
@ -117,14 +117,14 @@ function getForceGasMin (state) {
|
||||
return state.metamask.send.forceGasMin
|
||||
}
|
||||
|
||||
function getGasPrice (state) {
|
||||
return state.metamask.send.gasPrice
|
||||
}
|
||||
|
||||
function getGasLimit (state) {
|
||||
return state.metamask.send.gasLimit
|
||||
}
|
||||
|
||||
function getGasPrice (state) {
|
||||
return state.metamask.send.gasPrice
|
||||
}
|
||||
|
||||
function getGasTotal (state) {
|
||||
return state.metamask.send.gasTotal
|
||||
}
|
||||
|
@ -3,18 +3,17 @@ const {
|
||||
conversionUtil,
|
||||
conversionGTE,
|
||||
multiplyCurrencies,
|
||||
conversionGreaterThan,
|
||||
} = require('../../conversion-util')
|
||||
const {
|
||||
calcTokenAmount,
|
||||
} = require('../../token-util')
|
||||
const {
|
||||
conversionGreaterThan,
|
||||
} = require('../../conversion-util')
|
||||
const {
|
||||
INSUFFICIENT_FUNDS_ERROR,
|
||||
INSUFFICIENT_TOKENS_ERROR,
|
||||
NEGATIVE_ETH_ERROR,
|
||||
} = require('./send.constants')
|
||||
const abi = require('ethereumjs-abi')
|
||||
|
||||
module.exports = {
|
||||
calcGasTotal,
|
||||
@ -179,8 +178,9 @@ function doesAmountErrorRequireUpdate ({
|
||||
return amountErrorRequiresUpdate
|
||||
}
|
||||
|
||||
function generateTokenTransferData (abi, selectedAddress, selectedToken) {
|
||||
function generateTokenTransferData (selectedAddress, selectedToken) {
|
||||
if (!selectedToken) return
|
||||
console.log(`abi.rawEncode`, abi.rawEncode)
|
||||
return Array.prototype.map.call(
|
||||
abi.rawEncode(['address', 'uint256'], [selectedAddress, '0x0']),
|
||||
x => ('00' + x.toString(16)).slice(-2)
|
||||
|
@ -0,0 +1,150 @@
|
||||
import assert from 'assert'
|
||||
import proxyquire from 'proxyquire'
|
||||
import sinon from 'sinon'
|
||||
|
||||
let mapStateToProps
|
||||
let mapDispatchToProps
|
||||
|
||||
const actionSpies = {
|
||||
updateSendTokenBalance: sinon.spy(),
|
||||
updateGasTotal: sinon.spy(),
|
||||
setGasTotal: sinon.spy(),
|
||||
}
|
||||
const duckActionSpies = {
|
||||
updateSendErrors: sinon.spy(),
|
||||
}
|
||||
|
||||
proxyquire('../send.container.js', {
|
||||
'react-redux': {
|
||||
connect: (ms, md) => {
|
||||
mapStateToProps = ms
|
||||
mapDispatchToProps = md
|
||||
return () => ({})
|
||||
},
|
||||
},
|
||||
'react-router-dom': { withRouter: () => {} },
|
||||
'recompose': { compose: (arg1, arg2) => () => arg2() },
|
||||
'./send.selectors': {
|
||||
getAmountConversionRate: (s) => `mockAmountConversionRate:${s}`,
|
||||
getConversionRate: (s) => `mockConversionRate:${s}`,
|
||||
getCurrentNetwork: (s) => `mockNetwork:${s}`,
|
||||
getGasLimit: (s) => `mockGasLimit:${s}`,
|
||||
getGasPrice: (s) => `mockGasPrice:${s}`,
|
||||
getGasTotal: (s) => `mockGasTotal:${s}`,
|
||||
getPrimaryCurrency: (s) => `mockPrimaryCurrency:${s}`,
|
||||
getSelectedAddress: (s) => `mockSelectedAddress:${s}`,
|
||||
getSelectedToken: (s) => `mockSelectedToken:${s}`,
|
||||
getSelectedTokenContract: (s) => `mockTokenContract:${s}`,
|
||||
getSelectedTokenToFiatRate: (s) => `mockTokenToFiatRate:${s}`,
|
||||
getSendAmount: (s) => `mockAmount:${s}`,
|
||||
getSendEditingTransactionId: (s) => `mockEditingTransactionId:${s}`,
|
||||
getSendFromObject: (s) => `mockFrom:${s}`,
|
||||
getTokenBalance: (s) => `mockTokenBalance:${s}`,
|
||||
},
|
||||
'../../actions': actionSpies,
|
||||
'../../ducks/send': duckActionSpies,
|
||||
'./send.utils.js': {
|
||||
calcGasTotal: (gasLimit, gasPrice) => gasLimit + gasPrice,
|
||||
generateTokenTransferData: (a, b) => `mockData:${a + b}`,
|
||||
},
|
||||
})
|
||||
|
||||
describe('send container', () => {
|
||||
|
||||
describe('mapStateToProps()', () => {
|
||||
|
||||
it('should map the correct properties to props', () => {
|
||||
assert.deepEqual(mapStateToProps('mockState'), {
|
||||
amount: 'mockAmount:mockState',
|
||||
amountConversionRate: 'mockAmountConversionRate:mockState',
|
||||
conversionRate: 'mockConversionRate:mockState',
|
||||
data: 'mockData:mockSelectedAddress:mockStatemockSelectedToken:mockState',
|
||||
editingTransactionId: 'mockEditingTransactionId:mockState',
|
||||
from: 'mockFrom:mockState',
|
||||
gasLimit: 'mockGasLimit:mockState',
|
||||
gasPrice: 'mockGasPrice:mockState',
|
||||
gasTotal: 'mockGasTotal:mockState',
|
||||
network: 'mockNetwork:mockState',
|
||||
primaryCurrency: 'mockPrimaryCurrency:mockState',
|
||||
selectedAddress: 'mockSelectedAddress:mockState',
|
||||
selectedToken: 'mockSelectedToken:mockState',
|
||||
tokenBalance: 'mockTokenBalance:mockState',
|
||||
tokenContract: 'mockTokenContract:mockState',
|
||||
tokenToFiatRate: 'mockTokenToFiatRate:mockState',
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('mapDispatchToProps()', () => {
|
||||
let dispatchSpy
|
||||
let mapDispatchToPropsObject
|
||||
|
||||
beforeEach(() => {
|
||||
dispatchSpy = sinon.spy()
|
||||
mapDispatchToPropsObject = mapDispatchToProps(dispatchSpy)
|
||||
})
|
||||
|
||||
describe('updateAndSetGasTotal()', () => {
|
||||
const mockProps = {
|
||||
data: '0x1',
|
||||
editingTransactionId: '0x2',
|
||||
gasLimit: '0x3',
|
||||
gasPrice: '0x4',
|
||||
selectedAddress: '0x4',
|
||||
selectedToken: { address: '0x1' },
|
||||
}
|
||||
|
||||
it('should dispatch a setGasTotal action when editingTransactionId is truthy', () => {
|
||||
mapDispatchToPropsObject.updateAndSetGasTotal(mockProps)
|
||||
assert(dispatchSpy.calledOnce)
|
||||
assert.equal(
|
||||
actionSpies.setGasTotal.getCall(0).args[0],
|
||||
'0x30x4'
|
||||
)
|
||||
})
|
||||
|
||||
it('should dispatch an updateGasTotal action when editingTransactionId is falsy', () => {
|
||||
const { selectedAddress, selectedToken, data } = mockProps
|
||||
mapDispatchToPropsObject.updateAndSetGasTotal(
|
||||
Object.assign(mockProps, {editingTransactionId: false})
|
||||
)
|
||||
assert(dispatchSpy.calledOnce)
|
||||
assert.deepEqual(
|
||||
actionSpies.updateGasTotal.getCall(0).args[0],
|
||||
{ selectedAddress, selectedToken, data }
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('updateSendTokenBalance()', () => {
|
||||
const mockProps = {
|
||||
address: '0x10',
|
||||
tokenContract: '0x00a',
|
||||
selectedToken: {address: '0x1'},
|
||||
}
|
||||
|
||||
it('should dispatch an action', () => {
|
||||
mapDispatchToPropsObject.updateSendTokenBalance(Object.assign({}, mockProps))
|
||||
assert(dispatchSpy.calledOnce)
|
||||
assert.deepEqual(
|
||||
actionSpies.updateSendTokenBalance.getCall(0).args[0],
|
||||
mockProps
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('updateSendErrors()', () => {
|
||||
it('should dispatch an action', () => {
|
||||
mapDispatchToPropsObject.updateSendErrors('mockError')
|
||||
assert(dispatchSpy.calledOnce)
|
||||
assert.equal(
|
||||
duckActionSpies.updateSendErrors.getCall(0).args[0],
|
||||
'mockError'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
191
ui/app/components/send_/tests/send-selectors-test-data.js
Normal file
191
ui/app/components/send_/tests/send-selectors-test-data.js
Normal file
@ -0,0 +1,191 @@
|
||||
module.exports = {
|
||||
'metamask': {
|
||||
'isInitialized': true,
|
||||
'isUnlocked': true,
|
||||
'featureFlags': {'betaUI': true},
|
||||
'rpcTarget': 'https://rawtestrpc.metamask.io/',
|
||||
'identities': {
|
||||
'0xfdea65c8e26263f6d9a1b5de9555d2931a33b825': {
|
||||
'address': '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825',
|
||||
'name': 'Send Account 1',
|
||||
},
|
||||
'0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb': {
|
||||
'address': '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb',
|
||||
'name': 'Send Account 2',
|
||||
},
|
||||
'0x2f8d4a878cfa04a6e60d46362f5644deab66572d': {
|
||||
'address': '0x2f8d4a878cfa04a6e60d46362f5644deab66572d',
|
||||
'name': 'Send Account 3',
|
||||
},
|
||||
'0xd85a4b6a394794842887b8284293d69163007bbb': {
|
||||
'address': '0xd85a4b6a394794842887b8284293d69163007bbb',
|
||||
'name': 'Send Account 4',
|
||||
},
|
||||
},
|
||||
'currentCurrency': 'USD',
|
||||
'conversionRate': 1200.88200327,
|
||||
'conversionDate': 1489013762,
|
||||
'noActiveNotices': true,
|
||||
'frequentRpcList': [],
|
||||
'network': '3',
|
||||
'accounts': {
|
||||
'0xfdea65c8e26263f6d9a1b5de9555d2931a33b825': {
|
||||
'code': '0x',
|
||||
'balance': '0x47c9d71831c76efe',
|
||||
'nonce': '0x1b',
|
||||
'address': '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825',
|
||||
},
|
||||
'0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb': {
|
||||
'code': '0x',
|
||||
'balance': '0x37452b1315889f80',
|
||||
'nonce': '0xa',
|
||||
'address': '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb',
|
||||
},
|
||||
'0x2f8d4a878cfa04a6e60d46362f5644deab66572d': {
|
||||
'code': '0x',
|
||||
'balance': '0x30c9d71831c76efe',
|
||||
'nonce': '0x1c',
|
||||
'address': '0x2f8d4a878cfa04a6e60d46362f5644deab66572d',
|
||||
},
|
||||
'0xd85a4b6a394794842887b8284293d69163007bbb': {
|
||||
'code': '0x',
|
||||
'balance': '0x0',
|
||||
'nonce': '0x0',
|
||||
'address': '0xd85a4b6a394794842887b8284293d69163007bbb',
|
||||
},
|
||||
},
|
||||
'addressBook': [
|
||||
{
|
||||
'address': '0x06195827297c7a80a443b6894d3bdb8824b43896',
|
||||
'name': 'Address Book Account 1',
|
||||
},
|
||||
],
|
||||
'tokens': [
|
||||
{
|
||||
'address': '0x1a195821297c7a80a433b6894d3bdb8824b43896',
|
||||
'decimals': 18,
|
||||
'symbol': 'ABC',
|
||||
},
|
||||
{
|
||||
'address': '0x8d6b81208414189a58339873ab429b6c47ab92d3',
|
||||
'decimals': 4,
|
||||
'symbol': 'DEF',
|
||||
},
|
||||
{
|
||||
'address': '0xa42084c8d1d9a2198631988579bb36b48433a72b',
|
||||
'decimals': 18,
|
||||
'symbol': 'GHI',
|
||||
},
|
||||
],
|
||||
'tokenExchangeRates': {
|
||||
'def_eth': {
|
||||
rate: 2.0,
|
||||
},
|
||||
'ghi_eth': {
|
||||
rate: 31.01,
|
||||
},
|
||||
},
|
||||
'transactions': {},
|
||||
'selectedAddressTxList': [],
|
||||
'selectedTokenAddress': '0x8d6b81208414189a58339873ab429b6c47ab92d3',
|
||||
'unapprovedMsgs': {},
|
||||
'unapprovedMsgCount': 0,
|
||||
'unapprovedPersonalMsgs': {},
|
||||
'unapprovedPersonalMsgCount': 0,
|
||||
'keyringTypes': [
|
||||
'Simple Key Pair',
|
||||
'HD Key Tree',
|
||||
],
|
||||
'keyrings': [
|
||||
{
|
||||
'type': 'HD Key Tree',
|
||||
'accounts': [
|
||||
'fdea65c8e26263f6d9a1b5de9555d2931a33b825',
|
||||
'c5b8dbac4c1d3f152cdeb400e2313f309c410acb',
|
||||
'2f8d4a878cfa04a6e60d46362f5644deab66572d',
|
||||
],
|
||||
},
|
||||
{
|
||||
'type': 'Simple Key Pair',
|
||||
'accounts': [
|
||||
'0xd85a4b6a394794842887b8284293d69163007bbb',
|
||||
],
|
||||
},
|
||||
],
|
||||
'selectedAddress': '0xd85a4b6a394794842887b8284293d69163007bbb',
|
||||
'provider': {
|
||||
'type': 'testnet',
|
||||
},
|
||||
'shapeShiftTxList': [],
|
||||
'lostAccounts': [],
|
||||
'send': {
|
||||
'gasLimit': '0xFFFF',
|
||||
'gasPrice': '0xaa',
|
||||
'gasTotal': '0xb451dc41b578',
|
||||
'tokenBalance': 3434,
|
||||
'from': {
|
||||
'address': '0xabcdefg',
|
||||
'balance': '0x5f4e3d2c1',
|
||||
},
|
||||
'to': '0x987fedabc',
|
||||
'amount': '0x080',
|
||||
'memo': '',
|
||||
'errors': {
|
||||
'someError': null,
|
||||
},
|
||||
'maxModeOn': false,
|
||||
'editingTransactionId': 97531,
|
||||
'forceGasMin': true,
|
||||
},
|
||||
'unapprovedTxs': {
|
||||
'4768706228115573': {
|
||||
'id': 4768706228115573,
|
||||
'time': 1487363153561,
|
||||
'status': 'unapproved',
|
||||
'gasMultiplier': 1,
|
||||
'metamaskNetworkId': '3',
|
||||
'txParams': {
|
||||
'from': '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb',
|
||||
'to': '0x18a3462427bcc9133bb46e88bcbe39cd7ef0e761',
|
||||
'value': '0xde0b6b3a7640000',
|
||||
'metamaskId': 4768706228115573,
|
||||
'metamaskNetworkId': '3',
|
||||
'gas': '0x5209',
|
||||
},
|
||||
'gasLimitSpecified': false,
|
||||
'estimatedGas': '0x5209',
|
||||
'txFee': '17e0186e60800',
|
||||
'txValue': 'de0b6b3a7640000',
|
||||
'maxCost': 'de234b52e4a0800',
|
||||
'gasPrice': '4a817c800',
|
||||
},
|
||||
},
|
||||
'currentLocale': 'en',
|
||||
},
|
||||
'appState': {
|
||||
'menuOpen': false,
|
||||
'currentView': {
|
||||
'name': 'accountDetail',
|
||||
'detailView': null,
|
||||
'context': '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc',
|
||||
},
|
||||
'accountDetail': {
|
||||
'subview': 'transactions',
|
||||
},
|
||||
'modal': {
|
||||
'modalState': {},
|
||||
'previousModalState': {},
|
||||
},
|
||||
'transForward': true,
|
||||
'isLoading': false,
|
||||
'warning': null,
|
||||
'scrollToBottom': false,
|
||||
'forgottenPassword': null,
|
||||
},
|
||||
'identities': {},
|
||||
'send': {
|
||||
'fromDropdownOpen': false,
|
||||
'toDropdownOpen': false,
|
||||
'errors': { 'someError': null },
|
||||
},
|
||||
}
|
@ -0,0 +1,572 @@
|
||||
import assert from 'assert'
|
||||
import selectors from '../send.selectors.js'
|
||||
const {
|
||||
accountsWithSendEtherInfoSelector,
|
||||
// autoAddToBetaUI,
|
||||
getAddressBook,
|
||||
getAmountConversionRate,
|
||||
getConversionRate,
|
||||
getConvertedCurrency,
|
||||
getCurrentAccountWithSendEtherInfo,
|
||||
getCurrentCurrency,
|
||||
getCurrentNetwork,
|
||||
getCurrentViewContext,
|
||||
getForceGasMin,
|
||||
getGasLimit,
|
||||
getGasPrice,
|
||||
getGasTotal,
|
||||
getPrimaryCurrency,
|
||||
getSelectedAccount,
|
||||
getSelectedAddress,
|
||||
getSelectedIdentity,
|
||||
getSelectedToken,
|
||||
// getSelectedTokenContract,
|
||||
getSelectedTokenExchangeRate,
|
||||
getSelectedTokenToFiatRate,
|
||||
getSendAmount,
|
||||
getSendEditingTransactionId,
|
||||
getSendErrors,
|
||||
getSendFrom,
|
||||
getSendFromBalance,
|
||||
getSendFromObject,
|
||||
getSendMaxModeState,
|
||||
getSendTo,
|
||||
getSendToAccounts,
|
||||
getTokenBalance,
|
||||
getTokenExchangeRate,
|
||||
getUnapprovedTxs,
|
||||
isSendFormInError,
|
||||
// transactionsSelector,
|
||||
} = selectors
|
||||
import mockState from './send-selectors-test-data'
|
||||
|
||||
describe('send selectors', () => {
|
||||
|
||||
describe('accountsWithSendEtherInfoSelector()', () => {
|
||||
it('should return an array of account objects with name info from identities', () => {
|
||||
assert.deepEqual(
|
||||
accountsWithSendEtherInfoSelector(mockState),
|
||||
[
|
||||
{
|
||||
'code': '0x',
|
||||
'balance': '0x47c9d71831c76efe',
|
||||
'nonce': '0x1b',
|
||||
'address': '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825',
|
||||
'name': 'Send Account 1',
|
||||
},
|
||||
{
|
||||
'code': '0x',
|
||||
'balance': '0x37452b1315889f80',
|
||||
'nonce': '0xa',
|
||||
'address': '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb',
|
||||
'name': 'Send Account 2',
|
||||
},
|
||||
{
|
||||
'code': '0x',
|
||||
'balance': '0x30c9d71831c76efe',
|
||||
'nonce': '0x1c',
|
||||
'address': '0x2f8d4a878cfa04a6e60d46362f5644deab66572d',
|
||||
'name': 'Send Account 3',
|
||||
},
|
||||
{
|
||||
'code': '0x',
|
||||
'balance': '0x0',
|
||||
'nonce': '0x0',
|
||||
'address': '0xd85a4b6a394794842887b8284293d69163007bbb',
|
||||
'name': 'Send Account 4',
|
||||
},
|
||||
]
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
// describe('autoAddToBetaUI()', () => {
|
||||
// it('should', () => {
|
||||
// assert.deepEqual(
|
||||
// autoAddToBetaUI(mockState),
|
||||
|
||||
// )
|
||||
// })
|
||||
// })
|
||||
|
||||
describe('getAddressBook()', () => {
|
||||
it('should return the address book', () => {
|
||||
assert.deepEqual(
|
||||
getAddressBook(mockState),
|
||||
[
|
||||
{
|
||||
'address': '0x06195827297c7a80a443b6894d3bdb8824b43896',
|
||||
'name': 'Address Book Account 1',
|
||||
},
|
||||
],
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getAmountConversionRate()', () => {
|
||||
it('should return the token conversion rate if a token is selected', () => {
|
||||
assert.equal(
|
||||
getAmountConversionRate(mockState),
|
||||
2401.76400654
|
||||
)
|
||||
})
|
||||
|
||||
it('should return the eth conversion rate if no token is selected', () => {
|
||||
const editedMockState = {
|
||||
metamask: Object.assign({}, mockState.metamask, { selectedTokenAddress: null }),
|
||||
}
|
||||
assert.equal(
|
||||
getAmountConversionRate(editedMockState),
|
||||
1200.88200327
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getConversionRate()', () => {
|
||||
it('should return the eth conversion rate', () => {
|
||||
assert.deepEqual(
|
||||
getConversionRate(mockState),
|
||||
1200.88200327
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getConvertedCurrency()', () => {
|
||||
it('should return the currently selected currency', () => {
|
||||
assert.equal(
|
||||
getConvertedCurrency(mockState),
|
||||
'USD'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getCurrentAccountWithSendEtherInfo()', () => {
|
||||
it('should return the currently selected account with identity info', () => {
|
||||
assert.deepEqual(
|
||||
getCurrentAccountWithSendEtherInfo(mockState),
|
||||
{
|
||||
'code': '0x',
|
||||
'balance': '0x0',
|
||||
'nonce': '0x0',
|
||||
'address': '0xd85a4b6a394794842887b8284293d69163007bbb',
|
||||
'name': 'Send Account 4',
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getCurrentCurrency()', () => {
|
||||
it('should return the currently selected currency', () => {
|
||||
assert.equal(
|
||||
getCurrentCurrency(mockState),
|
||||
'USD'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getCurrentNetwork()', () => {
|
||||
it('should return the id of the currently selected network', () => {
|
||||
assert.equal(
|
||||
getCurrentNetwork(mockState),
|
||||
'3'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getCurrentViewContext()', () => {
|
||||
it('should return the context of the current view', () => {
|
||||
assert.equal(
|
||||
getCurrentViewContext(mockState),
|
||||
'0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getForceGasMin()', () => {
|
||||
it('should get the send.forceGasMin property', () => {
|
||||
assert.equal(
|
||||
getForceGasMin(mockState),
|
||||
true
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getGasLimit()', () => {
|
||||
it('should return the send.gasLimit', () => {
|
||||
assert.equal(
|
||||
getGasLimit(mockState),
|
||||
'0xFFFF'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getGasPrice()', () => {
|
||||
it('should return the send.gasPrice', () => {
|
||||
assert.equal(
|
||||
getGasPrice(mockState),
|
||||
'0xaa'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getGasTotal()', () => {
|
||||
it('should return the send.gasTotal', () => {
|
||||
assert.equal(
|
||||
getGasTotal(mockState),
|
||||
'0xb451dc41b578'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getPrimaryCurrency()', () => {
|
||||
it('should return the symbol of the selected token', () => {
|
||||
assert.equal(
|
||||
getPrimaryCurrency(mockState),
|
||||
'DEF'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getSelectedAccount()', () => {
|
||||
it('should return the currently selected account', () => {
|
||||
assert.deepEqual(
|
||||
getSelectedAccount(mockState),
|
||||
{
|
||||
'code': '0x',
|
||||
'balance': '0x0',
|
||||
'nonce': '0x0',
|
||||
'address': '0xd85a4b6a394794842887b8284293d69163007bbb',
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getSelectedAddress()', () => {
|
||||
it('should', () => {
|
||||
assert.equal(
|
||||
getSelectedAddress(mockState),
|
||||
'0xd85a4b6a394794842887b8284293d69163007bbb'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getSelectedIdentity()', () => {
|
||||
it('should return the identity object of the currently selected address', () => {
|
||||
assert.deepEqual(
|
||||
getSelectedIdentity(mockState),
|
||||
{
|
||||
'address': '0xd85a4b6a394794842887b8284293d69163007bbb',
|
||||
'name': 'Send Account 4',
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getSelectedToken()', () => {
|
||||
it('should return the currently selected token if selected', () => {
|
||||
assert.deepEqual(
|
||||
getSelectedToken(mockState),
|
||||
{
|
||||
'address': '0x8d6b81208414189a58339873ab429b6c47ab92d3',
|
||||
'decimals': 4,
|
||||
'symbol': 'DEF',
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('should return the send token if none is currently selected, but a send token exists', () => {
|
||||
const mockSendToken = {
|
||||
'address': '0x123456708414189a58339873ab429b6c47ab92d3',
|
||||
'decimals': 4,
|
||||
'symbol': 'JKL',
|
||||
}
|
||||
const editedMockState = {
|
||||
metamask: Object.assign({}, mockState.metamask, {
|
||||
selectedTokenAddress: null,
|
||||
send: {
|
||||
token: mockSendToken,
|
||||
},
|
||||
}),
|
||||
}
|
||||
assert.deepEqual(
|
||||
getSelectedToken(editedMockState),
|
||||
Object.assign({}, mockSendToken)
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
// TODO
|
||||
// describe('getSelectedTokenContract()', () => {
|
||||
// it('should', () => {
|
||||
// assert.deepEqual(
|
||||
// getSelectedTokenContract(mockState),
|
||||
|
||||
// )
|
||||
// })
|
||||
// })
|
||||
|
||||
describe('getSelectedTokenExchangeRate()', () => {
|
||||
it('should return the exchange rate for the selected token', () => {
|
||||
assert.equal(
|
||||
getSelectedTokenExchangeRate(mockState),
|
||||
2.0
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getSelectedTokenToFiatRate()', () => {
|
||||
it('should return rate for converting the selected token to fiat', () => {
|
||||
assert.equal(
|
||||
getSelectedTokenToFiatRate(mockState),
|
||||
2401.76400654
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getSendAmount()', () => {
|
||||
it('should return the send.amount', () => {
|
||||
assert.equal(
|
||||
getSendAmount(mockState),
|
||||
'0x080'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getSendEditingTransactionId()', () => {
|
||||
it('should return the send.editingTransactionId', () => {
|
||||
assert.equal(
|
||||
getSendEditingTransactionId(mockState),
|
||||
97531
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getSendErrors()', () => {
|
||||
it('should return the send.errors', () => {
|
||||
assert.deepEqual(
|
||||
getSendErrors(mockState),
|
||||
{ 'someError': null }
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getSendFrom()', () => {
|
||||
it('should return the send.from', () => {
|
||||
assert.deepEqual(
|
||||
getSendFrom(mockState),
|
||||
{
|
||||
'address': '0xabcdefg',
|
||||
'balance': '0x5f4e3d2c1',
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getSendFromBalance()', () => {
|
||||
it('should get the send.from balance if it exists', () => {
|
||||
assert.equal(
|
||||
getSendFromBalance(mockState),
|
||||
'0x5f4e3d2c1'
|
||||
)
|
||||
})
|
||||
|
||||
it('should get the selected account balance if the send.from does not exist', () => {
|
||||
const editedMockState = {
|
||||
metamask: Object.assign({}, mockState.metamask, {
|
||||
send: {
|
||||
from: null,
|
||||
},
|
||||
}),
|
||||
}
|
||||
assert.equal(
|
||||
getSendFromBalance(editedMockState),
|
||||
'0x0'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getSendFromObject()', () => {
|
||||
it('should return send.from if it exists', () => {
|
||||
assert.deepEqual(
|
||||
getSendFromObject(mockState),
|
||||
{
|
||||
'address': '0xabcdefg',
|
||||
'balance': '0x5f4e3d2c1',
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('should return the current account with send ether info if send.from does not exist', () => {
|
||||
const editedMockState = {
|
||||
metamask: Object.assign({}, mockState.metamask, {
|
||||
send: {
|
||||
from: null,
|
||||
},
|
||||
}),
|
||||
}
|
||||
assert.deepEqual(
|
||||
getSendFromObject(editedMockState),
|
||||
{
|
||||
'code': '0x',
|
||||
'balance': '0x0',
|
||||
'nonce': '0x0',
|
||||
'address': '0xd85a4b6a394794842887b8284293d69163007bbb',
|
||||
'name': 'Send Account 4',
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getSendMaxModeState()', () => {
|
||||
it('should return send.maxModeOn', () => {
|
||||
assert.equal(
|
||||
getSendMaxModeState(mockState),
|
||||
false
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getSendTo()', () => {
|
||||
it('should return send.to', () => {
|
||||
assert.equal(
|
||||
getSendTo(mockState),
|
||||
'0x987fedabc'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getSendToAccounts()', () => {
|
||||
it('should return an array including all the users accounts and the address book', () => {
|
||||
assert.deepEqual(
|
||||
getSendToAccounts(mockState),
|
||||
[
|
||||
{
|
||||
'code': '0x',
|
||||
'balance': '0x47c9d71831c76efe',
|
||||
'nonce': '0x1b',
|
||||
'address': '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825',
|
||||
'name': 'Send Account 1',
|
||||
},
|
||||
{
|
||||
'code': '0x',
|
||||
'balance': '0x37452b1315889f80',
|
||||
'nonce': '0xa',
|
||||
'address': '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb',
|
||||
'name': 'Send Account 2',
|
||||
},
|
||||
{
|
||||
'code': '0x',
|
||||
'balance': '0x30c9d71831c76efe',
|
||||
'nonce': '0x1c',
|
||||
'address': '0x2f8d4a878cfa04a6e60d46362f5644deab66572d',
|
||||
'name': 'Send Account 3',
|
||||
},
|
||||
{
|
||||
'code': '0x',
|
||||
'balance': '0x0',
|
||||
'nonce': '0x0',
|
||||
'address': '0xd85a4b6a394794842887b8284293d69163007bbb',
|
||||
'name': 'Send Account 4',
|
||||
},
|
||||
{
|
||||
'address': '0x06195827297c7a80a443b6894d3bdb8824b43896',
|
||||
'name': 'Address Book Account 1',
|
||||
},
|
||||
]
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getTokenBalance()', () => {
|
||||
it('should', () => {
|
||||
assert.equal(
|
||||
getTokenBalance(mockState),
|
||||
3434
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getTokenExchangeRate()', () => {
|
||||
it('should return the passed tokens exchange rates', () => {
|
||||
assert.equal(
|
||||
getTokenExchangeRate(mockState, 'GHI'),
|
||||
31.01
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getUnapprovedTxs()', () => {
|
||||
it('should return the unapproved txs', () => {
|
||||
assert.deepEqual(
|
||||
getUnapprovedTxs(mockState),
|
||||
{
|
||||
'4768706228115573': {
|
||||
'id': 4768706228115573,
|
||||
'time': 1487363153561,
|
||||
'status': 'unapproved',
|
||||
'gasMultiplier': 1,
|
||||
'metamaskNetworkId': '3',
|
||||
'txParams': {
|
||||
'from': '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb',
|
||||
'to': '0x18a3462427bcc9133bb46e88bcbe39cd7ef0e761',
|
||||
'value': '0xde0b6b3a7640000',
|
||||
'metamaskId': 4768706228115573,
|
||||
'metamaskNetworkId': '3',
|
||||
'gas': '0x5209',
|
||||
},
|
||||
'gasLimitSpecified': false,
|
||||
'estimatedGas': '0x5209',
|
||||
'txFee': '17e0186e60800',
|
||||
'txValue': 'de0b6b3a7640000',
|
||||
'maxCost': 'de234b52e4a0800',
|
||||
'gasPrice': '4a817c800',
|
||||
},
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('isSendFormInError()', () => {
|
||||
it('should return true if amount or to errors are truthy', () => {
|
||||
const editedMockState1 = {
|
||||
send: Object.assign({}, mockState.send, {
|
||||
errors: { amount: true },
|
||||
}),
|
||||
}
|
||||
assert.deepEqual(
|
||||
isSendFormInError(editedMockState1),
|
||||
true
|
||||
)
|
||||
const editedMockState2 = {
|
||||
send: Object.assign({}, mockState.send, {
|
||||
errors: { to: true },
|
||||
}),
|
||||
}
|
||||
assert.deepEqual(
|
||||
isSendFormInError(editedMockState2),
|
||||
true
|
||||
)
|
||||
})
|
||||
|
||||
it('should return false if amount is falsy and to is null', () => {
|
||||
const editedMockState = {
|
||||
send: Object.assign({}, mockState.send, { errors: { amount: false, to: null } }),
|
||||
}
|
||||
assert.deepEqual(
|
||||
isSendFormInError(editedMockState),
|
||||
false
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
// TODO
|
||||
// describe('transactionsSelector()', () => {
|
||||
// it('should', () => {
|
||||
// assert.deepEqual(
|
||||
// transactionsSelector(mockState),
|
||||
|
||||
// )
|
||||
// })
|
||||
// })
|
||||
|
||||
})
|
@ -0,0 +1,264 @@
|
||||
import assert from 'assert'
|
||||
import sinon from 'sinon'
|
||||
import proxyquire from 'proxyquire'
|
||||
|
||||
const {
|
||||
INSUFFICIENT_FUNDS_ERROR,
|
||||
INSUFFICIENT_TOKENS_ERROR,
|
||||
} = require('../send.constants')
|
||||
|
||||
const stubs = {
|
||||
addCurrencies: sinon.stub().callsFake((a, b, obj) => a + b),
|
||||
conversionUtil: sinon.stub().callsFake((val, obj) => parseInt(val, 16)),
|
||||
conversionGTE: sinon.stub().callsFake((obj1, obj2) => obj1.value > obj2.value),
|
||||
multiplyCurrencies: sinon.stub().callsFake((a, b) => a * b),
|
||||
calcTokenAmount: sinon.stub().callsFake((a, d) => 'calc:' + a + d),
|
||||
rawEncode: sinon.stub().returns([16, 1100]),
|
||||
}
|
||||
|
||||
const sendUtils = proxyquire('../send.utils.js', {
|
||||
'../../conversion-util': {
|
||||
addCurrencies: stubs.addCurrencies,
|
||||
conversionUtil: stubs.conversionUtil,
|
||||
conversionGTE: stubs.conversionGTE,
|
||||
multiplyCurrencies: stubs.multiplyCurrencies,
|
||||
},
|
||||
'../../token-util': { calcTokenAmount: stubs.calcTokenAmount },
|
||||
'ethereumjs-abi': {
|
||||
rawEncode: stubs.rawEncode,
|
||||
},
|
||||
})
|
||||
|
||||
const {
|
||||
calcGasTotal,
|
||||
doesAmountErrorRequireUpdate,
|
||||
generateTokenTransferData,
|
||||
getAmountErrorObject,
|
||||
getParamsForGasEstimate,
|
||||
calcTokenBalance,
|
||||
isBalanceSufficient,
|
||||
isTokenBalanceSufficient,
|
||||
} = sendUtils
|
||||
|
||||
describe('send utils', () => {
|
||||
|
||||
describe('calcGasTotal()', () => {
|
||||
it('should call multiplyCurrencies with the correct params and return the multiplyCurrencies return', () => {
|
||||
const result = calcGasTotal(12, 15)
|
||||
assert.equal(result, 180)
|
||||
const call_ = stubs.multiplyCurrencies.getCall(0).args
|
||||
assert.deepEqual(
|
||||
call_,
|
||||
[12, 15, {
|
||||
toNumericBase: 'hex',
|
||||
multiplicandBase: 16,
|
||||
multiplierBase: 16,
|
||||
} ]
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('doesAmountErrorRequireUpdate()', () => {
|
||||
const config = {
|
||||
'should return true if balances are different': {
|
||||
balance: 0,
|
||||
prevBalance: 1,
|
||||
expectedResult: true,
|
||||
},
|
||||
'should return true if gasTotals are different': {
|
||||
gasTotal: 0,
|
||||
prevGasTotal: 1,
|
||||
expectedResult: true,
|
||||
},
|
||||
'should return true if token balances are different': {
|
||||
tokenBalance: 0,
|
||||
prevTokenBalance: 1,
|
||||
selectedToken: 'someToken',
|
||||
expectedResult: true,
|
||||
},
|
||||
'should return false if they are all the same': {
|
||||
balance: 1,
|
||||
prevBalance: 1,
|
||||
gasTotal: 1,
|
||||
prevGasTotal: 1,
|
||||
tokenBalance: 1,
|
||||
prevTokenBalance: 1,
|
||||
selectedToken: 'someToken',
|
||||
expectedResult: false,
|
||||
},
|
||||
}
|
||||
Object.entries(config).map(([description, obj]) => {
|
||||
it(description, () => {
|
||||
assert.equal(doesAmountErrorRequireUpdate(obj), obj.expectedResult)
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('generateTokenTransferData()', () => {
|
||||
it('should return undefined if not passed a selected token', () => {
|
||||
assert.equal(generateTokenTransferData('mockAddress', false), undefined)
|
||||
})
|
||||
|
||||
it('should return encoded token transfer data', () => {
|
||||
assert.equal(generateTokenTransferData('mockAddress', true), '104c')
|
||||
})
|
||||
})
|
||||
|
||||
describe('getAmountErrorObject()', () => {
|
||||
const config = {
|
||||
'should return insufficientFunds error if isBalanceSufficient returns false': {
|
||||
amount: 15,
|
||||
amountConversionRate: 2,
|
||||
balance: 1,
|
||||
conversionRate: 3,
|
||||
gasTotal: 17,
|
||||
primaryCurrency: 'ABC',
|
||||
expectedResult: { amount: INSUFFICIENT_FUNDS_ERROR },
|
||||
},
|
||||
'should return insufficientTokens error if token is selected and isTokenBalanceSufficient returns false': {
|
||||
amount: '0x10',
|
||||
amountConversionRate: 2,
|
||||
balance: 100,
|
||||
conversionRate: 3,
|
||||
decimals: 10,
|
||||
gasTotal: 17,
|
||||
primaryCurrency: 'ABC',
|
||||
selectedToken: 'someToken',
|
||||
tokenBalance: 123,
|
||||
expectedResult: { amount: INSUFFICIENT_TOKENS_ERROR },
|
||||
},
|
||||
}
|
||||
Object.entries(config).map(([description, obj]) => {
|
||||
it(description, () => {
|
||||
assert.deepEqual(getAmountErrorObject(obj), obj.expectedResult)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('getParamsForGasEstimate()', () => {
|
||||
it('should return from and gas properties if no symbol or data', () => {
|
||||
assert.deepEqual(
|
||||
getParamsForGasEstimate('mockAddress'),
|
||||
{
|
||||
from: 'mockAddress',
|
||||
gas: '746a528800',
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('should return value property if symbol provided', () => {
|
||||
assert.deepEqual(
|
||||
getParamsForGasEstimate('mockAddress', 'ABC'),
|
||||
{
|
||||
from: 'mockAddress',
|
||||
gas: '746a528800',
|
||||
value: '0x0',
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('should return data property if data provided', () => {
|
||||
assert.deepEqual(
|
||||
getParamsForGasEstimate('mockAddress', 'ABC', 'somedata'),
|
||||
{
|
||||
from: 'mockAddress',
|
||||
gas: '746a528800',
|
||||
value: '0x0',
|
||||
data: 'somedata',
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('calcTokenBalance()', () => {
|
||||
it('should return the calculated token blance', () => {
|
||||
assert.equal(calcTokenBalance({
|
||||
selectedToken: {
|
||||
decimals: 11,
|
||||
},
|
||||
usersToken: {
|
||||
balance: 20,
|
||||
},
|
||||
}), 'calc:2011')
|
||||
})
|
||||
})
|
||||
|
||||
describe('isBalanceSufficient()', () => {
|
||||
it('should correctly call addCurrencies and return the result of calling conversionGTE', () => {
|
||||
stubs.conversionGTE.resetHistory()
|
||||
const result = isBalanceSufficient({
|
||||
amount: 15,
|
||||
amountConversionRate: 2,
|
||||
balance: 100,
|
||||
conversionRate: 3,
|
||||
gasTotal: 17,
|
||||
primaryCurrency: 'ABC',
|
||||
})
|
||||
assert.deepEqual(
|
||||
stubs.addCurrencies.getCall(0).args,
|
||||
[
|
||||
15, 17, {
|
||||
aBase: 16,
|
||||
bBase: 16,
|
||||
toNumericBase: 'hex',
|
||||
},
|
||||
]
|
||||
)
|
||||
assert.deepEqual(
|
||||
stubs.conversionGTE.getCall(0).args,
|
||||
[
|
||||
{
|
||||
value: 100,
|
||||
fromNumericBase: 'hex',
|
||||
fromCurrency: 'ABC',
|
||||
conversionRate: 3,
|
||||
},
|
||||
{
|
||||
value: 32,
|
||||
fromNumericBase: 'hex',
|
||||
conversionRate: 2,
|
||||
fromCurrency: 'ABC',
|
||||
},
|
||||
]
|
||||
)
|
||||
|
||||
assert.equal(result, true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('isTokenBalanceSufficient()', () => {
|
||||
it('should correctly call conversionUtil and return the result of calling conversionGTE', () => {
|
||||
stubs.conversionGTE.resetHistory()
|
||||
const result = isTokenBalanceSufficient({
|
||||
amount: '0x10',
|
||||
tokenBalance: 123,
|
||||
decimals: 10,
|
||||
})
|
||||
assert.deepEqual(
|
||||
stubs.conversionUtil.getCall(0).args,
|
||||
[
|
||||
'0x10', {
|
||||
fromNumericBase: 'hex',
|
||||
},
|
||||
]
|
||||
)
|
||||
assert.deepEqual(
|
||||
stubs.conversionGTE.getCall(0).args,
|
||||
[
|
||||
{
|
||||
value: 123,
|
||||
fromNumericBase: 'dec',
|
||||
},
|
||||
{
|
||||
value: 'calc:1610',
|
||||
fromNumericBase: 'dec',
|
||||
},
|
||||
]
|
||||
)
|
||||
|
||||
assert.equal(result, false)
|
||||
})
|
||||
})
|
||||
|
||||
})
|
@ -203,8 +203,8 @@ TxListItem.prototype.showRetryButton = function () {
|
||||
const currentNonceTxs = selectedAddressTxList.filter(tx => tx.txParams.nonce === currentNonce)
|
||||
const currentNonceSubmittedTxs = currentNonceTxs.filter(tx => tx.status === 'submitted')
|
||||
const lastSubmittedTxWithCurrentNonce = currentNonceSubmittedTxs[currentNonceSubmittedTxs.length - 1]
|
||||
const currentTxIsLatestWithNonce = lastSubmittedTxWithCurrentNonce
|
||||
&& lastSubmittedTxWithCurrentNonce.id === transactionId
|
||||
const currentTxIsLatestWithNonce = lastSubmittedTxWithCurrentNonce &&
|
||||
lastSubmittedTxWithCurrentNonce.id === transactionId
|
||||
|
||||
return currentTxIsLatestWithNonce && Date.now() - transactionSubmittedTime > 30000
|
||||
}
|
||||
|
@ -6,14 +6,14 @@ const { compose } = require('recompose')
|
||||
const t = require('../i18n-helper').getMessage
|
||||
|
||||
class I18nProvider extends Component {
|
||||
getChildContext() {
|
||||
getChildContext () {
|
||||
const { localeMessages } = this.props
|
||||
return {
|
||||
t: t.bind(null, localeMessages),
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
render () {
|
||||
return this.props.children
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ MainContainer.prototype.render = function () {
|
||||
// - pass resulting h() to MainContainer
|
||||
// - error checking in separate func
|
||||
// - router in separate func
|
||||
let contents = {
|
||||
const contents = {
|
||||
component: AccountAndTransactionDetails,
|
||||
key: 'account-detail',
|
||||
style: {},
|
||||
|
Loading…
Reference in New Issue
Block a user