diff options
Diffstat (limited to 'ui/app/components/send_')
113 files changed, 0 insertions, 6794 deletions
diff --git a/ui/app/components/send_/README.md b/ui/app/components/send_/README.md deleted file mode 100644 index e69de29bb..000000000 --- a/ui/app/components/send_/README.md +++ /dev/null diff --git a/ui/app/components/send_/account-list-item/account-list-item-README.md b/ui/app/components/send_/account-list-item/account-list-item-README.md deleted file mode 100644 index e69de29bb..000000000 --- a/ui/app/components/send_/account-list-item/account-list-item-README.md +++ /dev/null diff --git a/ui/app/components/send_/account-list-item/account-list-item.component.js b/ui/app/components/send_/account-list-item/account-list-item.component.js deleted file mode 100644 index b8407d147..000000000 --- a/ui/app/components/send_/account-list-item/account-list-item.component.js +++ /dev/null @@ -1,74 +0,0 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' -import { checksumAddress } from '../../../util' -import Identicon from '../../identicon' -import CurrencyDisplay from '../../send/currency-display' - -export default class AccountListItem extends Component { - - static propTypes = { - account: PropTypes.object, - className: PropTypes.string, - conversionRate: PropTypes.number, - currentCurrency: PropTypes.string, - displayAddress: PropTypes.bool, - displayBalance: PropTypes.bool, - handleClick: PropTypes.func, - icon: PropTypes.node, - }; - - render () { - const { - account, - className, - conversionRate, - currentCurrency, - displayAddress = false, - displayBalance = true, - handleClick, - icon = null, - } = this.props - - const { name, address, balance } = account || {} - - return (<div - className={`account-list-item ${className}`} - onClick={() => 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>} - - </div> - - {displayAddress && name && <div className="account-list-item__account-address"> - { checksumAddress(address) } - </div>} - - {displayBalance && <CurrencyDisplay - className="account-list-item__account-balances" - conversionRate={conversionRate} - convertedBalanceClassName="account-list-item__account-secondary-balance" - convertedCurrency={currentCurrency} - primaryBalanceClassName="account-list-item__account-primary-balance" - primaryCurrency="ETH" - readOnly={true} - value={balance} - />} - - </div>) - } -} - -AccountListItem.contextTypes = { - t: PropTypes.func, -} - diff --git a/ui/app/components/send_/account-list-item/account-list-item.container.js b/ui/app/components/send_/account-list-item/account-list-item.container.js deleted file mode 100644 index 4b4519288..000000000 --- a/ui/app/components/send_/account-list-item/account-list-item.container.js +++ /dev/null @@ -1,15 +0,0 @@ -import { connect } from 'react-redux' -import { - getConversionRate, - getCurrentCurrency, -} from '../send.selectors.js' -import AccountListItem from './account-list-item.component' - -export default connect(mapStateToProps)(AccountListItem) - -function mapStateToProps (state) { - return { - conversionRate: getConversionRate(state), - currentCurrency: getCurrentCurrency(state), - } -} diff --git a/ui/app/components/send_/account-list-item/account-list-item.scss b/ui/app/components/send_/account-list-item/account-list-item.scss deleted file mode 100644 index e69de29bb..000000000 --- a/ui/app/components/send_/account-list-item/account-list-item.scss +++ /dev/null diff --git a/ui/app/components/send_/account-list-item/index.js b/ui/app/components/send_/account-list-item/index.js deleted file mode 100644 index 907485cf7..000000000 --- a/ui/app/components/send_/account-list-item/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './account-list-item.container' diff --git a/ui/app/components/send_/account-list-item/tests/account-list-item-component.test.js b/ui/app/components/send_/account-list-item/tests/account-list-item-component.test.js deleted file mode 100644 index bb7f3776c..000000000 --- a/ui/app/components/send_/account-list-item/tests/account-list-item-component.test.js +++ /dev/null @@ -1,138 +0,0 @@ -import React from 'react' -import assert from 'assert' -import { shallow } from 'enzyme' -import sinon from 'sinon' -import proxyquire from 'proxyquire' -import Identicon from '../../../identicon' -import CurrencyDisplay from '../../../send/currency-display' - -const utilsMethodStubs = { - checksumAddress: sinon.stub().returns('mockCheckSumAddress'), -} - -const AccountListItem = proxyquire('../account-list-item.component.js', { - '../../../util': utilsMethodStubs, -}).default - - -const propsMethodSpies = { - handleClick: sinon.spy(), -} - -describe('AccountListItem Component', function () { - let wrapper - - beforeEach(() => { - wrapper = shallow(<AccountListItem - account={ { address: 'mockAddress', name: 'mockName', balance: 'mockBalance' } } - className={'mockClassName'} - conversionRate={4} - currentCurrency={'mockCurrentyCurrency'} - displayAddress={false} - displayBalance={false} - handleClick={propsMethodSpies.handleClick} - icon={<i className="mockIcon" />} - />, { context: { t: str => str + '_t' } }) - }) - - afterEach(() => { - propsMethodSpies.handleClick.resetHistory() - }) - - describe('render', () => { - it('should render a div with the passed className', () => { - assert.equal(wrapper.find('.mockClassName').length, 1) - assert(wrapper.find('.mockClassName').is('div')) - assert(wrapper.find('.mockClassName').hasClass('account-list-item')) - }) - - it('should call handleClick with the expected props when the root div is clicked', () => { - const { onClick } = wrapper.find('.mockClassName').props() - assert.equal(propsMethodSpies.handleClick.callCount, 0) - onClick() - assert.equal(propsMethodSpies.handleClick.callCount, 1) - assert.deepEqual( - propsMethodSpies.handleClick.getCall(0).args, - [{ address: 'mockAddress', name: 'mockName', balance: 'mockBalance' }] - ) - }) - - it('should have a top row div', () => { - assert.equal(wrapper.find('.mockClassName > .account-list-item__top-row').length, 1) - assert(wrapper.find('.mockClassName > .account-list-item__top-row').is('div')) - }) - - it('should have an identicon, name and icon in the top row', () => { - const topRow = wrapper.find('.mockClassName > .account-list-item__top-row') - assert.equal(topRow.find(Identicon).length, 1) - assert.equal(topRow.find('.account-list-item__account-name').length, 1) - assert.equal(topRow.find('.account-list-item__icon').length, 1) - }) - - it('should show the account name if it exists', () => { - const topRow = wrapper.find('.mockClassName > .account-list-item__top-row') - assert.equal(topRow.find('.account-list-item__account-name').text(), 'mockName') - }) - - it('should show the account address if there is no name', () => { - wrapper.setProps({ account: { address: 'addressButNoName' } }) - const topRow = wrapper.find('.mockClassName > .account-list-item__top-row') - assert.equal(topRow.find('.account-list-item__account-name').text(), 'addressButNoName') - }) - - it('should render the passed icon', () => { - const topRow = wrapper.find('.mockClassName > .account-list-item__top-row') - assert(topRow.find('.account-list-item__icon').childAt(0).is('i')) - assert(topRow.find('.account-list-item__icon').childAt(0).hasClass('mockIcon')) - }) - - it('should not render an icon if none is passed', () => { - wrapper.setProps({ icon: null }) - const topRow = wrapper.find('.mockClassName > .account-list-item__top-row') - assert.equal(topRow.find('.account-list-item__icon').length, 0) - }) - - it('should render the account address as a checksumAddress if displayAddress is true and name is provided', () => { - wrapper.setProps({ displayAddress: true }) - assert.equal(wrapper.find('.account-list-item__account-address').length, 1) - assert.equal(wrapper.find('.account-list-item__account-address').text(), 'mockCheckSumAddress') - assert.deepEqual( - utilsMethodStubs.checksumAddress.getCall(0).args, - ['mockAddress'] - ) - }) - - it('should not render the account address as a checksumAddress if displayAddress is false', () => { - wrapper.setProps({ displayAddress: false }) - assert.equal(wrapper.find('.account-list-item__account-address').length, 0) - }) - - it('should not render the account address as a checksumAddress if name is not provided', () => { - wrapper.setProps({ account: { address: 'someAddressButNoName' } }) - assert.equal(wrapper.find('.account-list-item__account-address').length, 0) - }) - - it('should render a CurrencyDisplay with the correct props if displayBalance is true', () => { - wrapper.setProps({ displayBalance: true }) - assert.equal(wrapper.find(CurrencyDisplay).length, 1) - assert.deepEqual( - wrapper.find(CurrencyDisplay).props(), - { - className: 'account-list-item__account-balances', - conversionRate: 4, - convertedBalanceClassName: 'account-list-item__account-secondary-balance', - convertedCurrency: 'mockCurrentyCurrency', - primaryBalanceClassName: 'account-list-item__account-primary-balance', - primaryCurrency: 'ETH', - readOnly: true, - value: 'mockBalance', - } - ) - }) - - it('should not render a CurrencyDisplay if displayBalance is false', () => { - wrapper.setProps({ displayBalance: false }) - assert.equal(wrapper.find(CurrencyDisplay).length, 0) - }) - }) -}) diff --git a/ui/app/components/send_/account-list-item/tests/account-list-item-container.test.js b/ui/app/components/send_/account-list-item/tests/account-list-item-container.test.js deleted file mode 100644 index af0859117..000000000 --- a/ui/app/components/send_/account-list-item/tests/account-list-item-container.test.js +++ /dev/null @@ -1,32 +0,0 @@ -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}`, - getCurrentCurrency: (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', - }) - }) - - }) - -}) diff --git a/ui/app/components/send_/index.js b/ui/app/components/send_/index.js deleted file mode 100644 index b5114babc..000000000 --- a/ui/app/components/send_/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './send.container' diff --git a/ui/app/components/send_/send-content/index.js b/ui/app/components/send_/send-content/index.js deleted file mode 100644 index 891c17e6a..000000000 --- a/ui/app/components/send_/send-content/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './send-content.component' diff --git a/ui/app/components/send_/send-content/send-amount-row/README.md b/ui/app/components/send_/send-content/send-amount-row/README.md deleted file mode 100644 index e69de29bb..000000000 --- a/ui/app/components/send_/send-content/send-amount-row/README.md +++ /dev/null diff --git a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/amount-max-button.component.js b/ui/app/components/send_/send-content/send-amount-row/amount-max-button/amount-max-button.component.js deleted file mode 100644 index bdf12b738..000000000 --- a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/amount-max-button.component.js +++ /dev/null @@ -1,54 +0,0 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' - -export default class AmountMaxButton extends Component { - - static propTypes = { - balance: PropTypes.string, - gasTotal: PropTypes.string, - maxModeOn: PropTypes.bool, - selectedToken: PropTypes.object, - setAmountToMax: PropTypes.func, - setMaxModeTo: PropTypes.func, - tokenBalance: PropTypes.string, - }; - - setMaxAmount () { - const { - balance, - gasTotal, - selectedToken, - setAmountToMax, - tokenBalance, - } = this.props - - setAmountToMax({ - balance, - gasTotal, - selectedToken, - tokenBalance, - }) - } - - render () { - const { setMaxModeTo, maxModeOn } = this.props - - return ( - <div - className="send-v2__amount-max" - onClick={(event) => { - event.preventDefault() - setMaxModeTo(true) - this.setMaxAmount() - }} - > - {!maxModeOn ? this.context.t('max') : ''} - </div> - ) - } - -} - -AmountMaxButton.contextTypes = { - t: PropTypes.func, -} diff --git a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/amount-max-button.container.js b/ui/app/components/send_/send-content/send-amount-row/amount-max-button/amount-max-button.container.js deleted file mode 100644 index 2d2ec42f7..000000000 --- a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/amount-max-button.container.js +++ /dev/null @@ -1,40 +0,0 @@ -import { connect } from 'react-redux' -import { - getGasTotal, - getSelectedToken, - getSendFromBalance, - getTokenBalance, -} from '../../../send.selectors.js' -import { getMaxModeOn } from './amount-max-button.selectors.js' -import { calcMaxAmount } from './amount-max-button.utils.js' -import { - updateSendAmount, - setMaxModeTo, -} from '../../../../../actions' -import AmountMaxButton from './amount-max-button.component' -import { - updateSendErrors, -} from '../../../../../ducks/send.duck' - -export default connect(mapStateToProps, mapDispatchToProps)(AmountMaxButton) - -function mapStateToProps (state) { - - return { - balance: getSendFromBalance(state), - gasTotal: getGasTotal(state), - maxModeOn: getMaxModeOn(state), - selectedToken: getSelectedToken(state), - tokenBalance: getTokenBalance(state), - } -} - -function mapDispatchToProps (dispatch) { - return { - setAmountToMax: maxAmountDataObject => { - dispatch(updateSendErrors({ amount: null })) - dispatch(updateSendAmount(calcMaxAmount(maxAmountDataObject))) - }, - setMaxModeTo: bool => dispatch(setMaxModeTo(bool)), - } -} diff --git a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/amount-max-button.selectors.js b/ui/app/components/send_/send-content/send-amount-row/amount-max-button/amount-max-button.selectors.js deleted file mode 100644 index 69fec1994..000000000 --- a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/amount-max-button.selectors.js +++ /dev/null @@ -1,9 +0,0 @@ -const selectors = { - getMaxModeOn, -} - -module.exports = selectors - -function getMaxModeOn (state) { - return state.metamask.send.maxModeOn -} diff --git a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/amount-max-button.utils.js b/ui/app/components/send_/send-content/send-amount-row/amount-max-button/amount-max-button.utils.js deleted file mode 100644 index b490a7fd7..000000000 --- a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/amount-max-button.utils.js +++ /dev/null @@ -1,22 +0,0 @@ -const { - multiplyCurrencies, - subtractCurrencies, -} = require('../../../../../conversion-util') -const ethUtil = require('ethereumjs-util') - -function calcMaxAmount ({ balance, gasTotal, selectedToken, tokenBalance }) { - const { decimals } = selectedToken || {} - const multiplier = Math.pow(10, Number(decimals || 0)) - - return selectedToken - ? multiplyCurrencies(tokenBalance, multiplier, {toNumericBase: 'hex'}) - : subtractCurrencies( - ethUtil.addHexPrefix(balance), - ethUtil.addHexPrefix(gasTotal), - { toNumericBase: 'hex' } - ) -} - -module.exports = { - calcMaxAmount, -} diff --git a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/index.js b/ui/app/components/send_/send-content/send-amount-row/amount-max-button/index.js deleted file mode 100644 index ee8271494..000000000 --- a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './amount-max-button.container' diff --git a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/tests/amount-max-button-component.test.js b/ui/app/components/send_/send-content/send-amount-row/amount-max-button/tests/amount-max-button-component.test.js deleted file mode 100644 index 86a05ff21..000000000 --- a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/tests/amount-max-button-component.test.js +++ /dev/null @@ -1,90 +0,0 @@ -import React from 'react' -import assert from 'assert' -import { shallow } from 'enzyme' -import sinon from 'sinon' -import AmountMaxButton from '../amount-max-button.component.js' - -const propsMethodSpies = { - setAmountToMax: sinon.spy(), - setMaxModeTo: sinon.spy(), -} - -const MOCK_EVENT = { preventDefault: () => {} } - -sinon.spy(AmountMaxButton.prototype, 'setMaxAmount') - -describe('AmountMaxButton Component', function () { - let wrapper - let instance - - beforeEach(() => { - wrapper = shallow(<AmountMaxButton - balance={'mockBalance'} - gasTotal={'mockGasTotal'} - maxModeOn={false} - selectedToken={ { address: 'mockTokenAddress' } } - setAmountToMax={propsMethodSpies.setAmountToMax} - setMaxModeTo={propsMethodSpies.setMaxModeTo} - tokenBalance={'mockTokenBalance'} - />, { context: { t: str => str + '_t' } }) - instance = wrapper.instance() - }) - - afterEach(() => { - propsMethodSpies.setAmountToMax.resetHistory() - propsMethodSpies.setMaxModeTo.resetHistory() - AmountMaxButton.prototype.setMaxAmount.resetHistory() - }) - - describe('setMaxAmount', () => { - - it('should call setAmountToMax with the correct params', () => { - assert.equal(propsMethodSpies.setAmountToMax.callCount, 0) - instance.setMaxAmount() - assert.equal(propsMethodSpies.setAmountToMax.callCount, 1) - assert.deepEqual( - propsMethodSpies.setAmountToMax.getCall(0).args, - [{ - balance: 'mockBalance', - gasTotal: 'mockGasTotal', - selectedToken: { address: 'mockTokenAddress' }, - tokenBalance: 'mockTokenBalance', - }] - ) - }) - - }) - - describe('render', () => { - it('should render a div with a send-v2__amount-max class', () => { - assert.equal(wrapper.find('.send-v2__amount-max').length, 1) - assert(wrapper.find('.send-v2__amount-max').is('div')) - }) - - it('should call setMaxModeTo and setMaxAmount when the send-v2__amount-max div is clicked', () => { - const { - onClick, - } = wrapper.find('.send-v2__amount-max').props() - - assert.equal(AmountMaxButton.prototype.setMaxAmount.callCount, 0) - assert.equal(propsMethodSpies.setMaxModeTo.callCount, 0) - onClick(MOCK_EVENT) - assert.equal(AmountMaxButton.prototype.setMaxAmount.callCount, 1) - assert.equal(propsMethodSpies.setMaxModeTo.callCount, 1) - assert.deepEqual( - propsMethodSpies.setMaxModeTo.getCall(0).args, - [true] - ) - }) - - it('should not render text when maxModeOn is true', () => { - wrapper.setProps({ maxModeOn: true }) - assert.equal(wrapper.find('.send-v2__amount-max').text(), '') - }) - - it('should render the expected text when maxModeOn is false', () => { - wrapper.setProps({ maxModeOn: false }) - assert.equal(wrapper.find('.send-v2__amount-max').text(), 'max_t') - }) - }) -}) diff --git a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/tests/amount-max-button-container.test.js b/ui/app/components/send_/send-content/send-amount-row/amount-max-button/tests/amount-max-button-container.test.js deleted file mode 100644 index 2cc00d6d6..000000000 --- a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/tests/amount-max-button-container.test.js +++ /dev/null @@ -1,91 +0,0 @@ -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.duck': 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' - ) - }) - }) - - }) - -}) diff --git a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/tests/amount-max-button-selectors.test.js b/ui/app/components/send_/send-content/send-amount-row/amount-max-button/tests/amount-max-button-selectors.test.js deleted file mode 100644 index 655fe1969..000000000 --- a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/tests/amount-max-button-selectors.test.js +++ /dev/null @@ -1,22 +0,0 @@ -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) - }) - }) - -}) diff --git a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/tests/amount-max-button-utils.test.js b/ui/app/components/send_/send-content/send-amount-row/amount-max-button/tests/amount-max-button-utils.test.js deleted file mode 100644 index 816df6a12..000000000 --- a/ui/app/components/send_/send-content/send-amount-row/amount-max-button/tests/amount-max-button-utils.test.js +++ /dev/null @@ -1,27 +0,0 @@ -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') - }) - }) - -}) diff --git a/ui/app/components/send_/send-content/send-amount-row/index.js b/ui/app/components/send_/send-content/send-amount-row/index.js deleted file mode 100644 index abc6852fe..000000000 --- a/ui/app/components/send_/send-content/send-amount-row/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './send-amount-row.container' diff --git a/ui/app/components/send_/send-content/send-amount-row/send-amount-row.component.js b/ui/app/components/send_/send-content/send-amount-row/send-amount-row.component.js deleted file mode 100644 index 196538c11..000000000 --- a/ui/app/components/send_/send-content/send-amount-row/send-amount-row.component.js +++ /dev/null @@ -1,109 +0,0 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' -import SendRowWrapper from '../send-row-wrapper/' -import AmountMaxButton from './amount-max-button/' -import CurrencyDisplay from '../../../send/currency-display' - -export default class SendAmountRow extends Component { - - static propTypes = { - amount: PropTypes.string, - amountConversionRate: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.number, - ]), - balance: PropTypes.string, - conversionRate: PropTypes.number, - convertedCurrency: PropTypes.string, - gasTotal: PropTypes.string, - inError: PropTypes.bool, - primaryCurrency: PropTypes.string, - selectedToken: PropTypes.object, - setMaxModeTo: PropTypes.func, - tokenBalance: PropTypes.string, - updateSendAmount: PropTypes.func, - updateSendAmountError: PropTypes.func, - updateGas: PropTypes.func, - } - - validateAmount (amount) { - const { - amountConversionRate, - balance, - conversionRate, - gasTotal, - primaryCurrency, - selectedToken, - tokenBalance, - updateSendAmountError, - } = this.props - - updateSendAmountError({ - amount, - amountConversionRate, - balance, - conversionRate, - gasTotal, - primaryCurrency, - selectedToken, - tokenBalance, - }) - } - - updateAmount (amount) { - const { updateSendAmount, setMaxModeTo } = this.props - - setMaxModeTo(false) - updateSendAmount(amount) - } - - updateGas (amount) { - const { selectedToken, updateGas } = this.props - - if (selectedToken) { - updateGas({ amount }) - } - } - - render () { - const { - amount, - amountConversionRate, - convertedCurrency, - gasTotal, - inError, - primaryCurrency, - selectedToken, - } = this.props - - return ( - <SendRowWrapper - label={`${this.context.t('amount')}:`} - showError={inError} - errorType={'amount'} - > - {!inError && gasTotal && <AmountMaxButton />} - <CurrencyDisplay - conversionRate={amountConversionRate} - convertedCurrency={convertedCurrency} - onBlur={newAmount => { - this.updateGas(newAmount) - this.updateAmount(newAmount) - }} - onChange={newAmount => this.validateAmount(newAmount)} - inError={inError} - primaryCurrency={primaryCurrency || 'ETH'} - selectedToken={selectedToken} - value={amount} - step="any" - /> - </SendRowWrapper> - ) - } - -} - -SendAmountRow.contextTypes = { - t: PropTypes.func, -} - diff --git a/ui/app/components/send_/send-content/send-amount-row/send-amount-row.container.js b/ui/app/components/send_/send-content/send-amount-row/send-amount-row.container.js deleted file mode 100644 index b816d948f..000000000 --- a/ui/app/components/send_/send-content/send-amount-row/send-amount-row.container.js +++ /dev/null @@ -1,51 +0,0 @@ -import { connect } from 'react-redux' -import { - getAmountConversionRate, - getConversionRate, - getCurrentCurrency, - getGasTotal, - getPrimaryCurrency, - getSelectedToken, - getSendAmount, - getSendFromBalance, - getTokenBalance, -} from '../../send.selectors' -import { - sendAmountIsInError, -} from './send-amount-row.selectors' -import { getAmountErrorObject } from '../../send.utils' -import { - setMaxModeTo, - updateSendAmount, -} from '../../../../actions' -import { - updateSendErrors, -} from '../../../../ducks/send.duck' -import SendAmountRow from './send-amount-row.component' - -export default connect(mapStateToProps, mapDispatchToProps)(SendAmountRow) - -function mapStateToProps (state) { - return { - amount: getSendAmount(state), - amountConversionRate: getAmountConversionRate(state), - balance: getSendFromBalance(state), - conversionRate: getConversionRate(state), - convertedCurrency: getCurrentCurrency(state), - gasTotal: getGasTotal(state), - inError: sendAmountIsInError(state), - primaryCurrency: getPrimaryCurrency(state), - selectedToken: getSelectedToken(state), - tokenBalance: getTokenBalance(state), - } -} - -function mapDispatchToProps (dispatch) { - return { - setMaxModeTo: bool => dispatch(setMaxModeTo(bool)), - updateSendAmount: newAmount => dispatch(updateSendAmount(newAmount)), - updateSendAmountError: (amountDataObject) => { - dispatch(updateSendErrors(getAmountErrorObject(amountDataObject))) - }, - } -} diff --git a/ui/app/components/send_/send-content/send-amount-row/send-amount-row.scss b/ui/app/components/send_/send-content/send-amount-row/send-amount-row.scss deleted file mode 100644 index e69de29bb..000000000 --- a/ui/app/components/send_/send-content/send-amount-row/send-amount-row.scss +++ /dev/null diff --git a/ui/app/components/send_/send-content/send-amount-row/send-amount-row.selectors.js b/ui/app/components/send_/send-content/send-amount-row/send-amount-row.selectors.js deleted file mode 100644 index fb08c7ed7..000000000 --- a/ui/app/components/send_/send-content/send-amount-row/send-amount-row.selectors.js +++ /dev/null @@ -1,9 +0,0 @@ -const selectors = { - sendAmountIsInError, -} - -module.exports = selectors - -function sendAmountIsInError (state) { - return Boolean(state.send.errors.amount) -} diff --git a/ui/app/components/send_/send-content/send-amount-row/tests/send-amount-row-component.test.js b/ui/app/components/send_/send-content/send-amount-row/tests/send-amount-row-component.test.js deleted file mode 100644 index 579e18585..000000000 --- a/ui/app/components/send_/send-content/send-amount-row/tests/send-amount-row-component.test.js +++ /dev/null @@ -1,173 +0,0 @@ -import React from 'react' -import assert from 'assert' -import { shallow } from 'enzyme' -import sinon from 'sinon' -import SendAmountRow from '../send-amount-row.component.js' - -import SendRowWrapper from '../../send-row-wrapper/send-row-wrapper.component' -import AmountMaxButton from '../amount-max-button/amount-max-button.container' -import CurrencyDisplay from '../../../../send/currency-display' - -const propsMethodSpies = { - setMaxModeTo: sinon.spy(), - updateSendAmount: sinon.spy(), - updateSendAmountError: sinon.spy(), - updateGas: sinon.spy(), -} - -sinon.spy(SendAmountRow.prototype, 'updateAmount') -sinon.spy(SendAmountRow.prototype, 'validateAmount') -sinon.spy(SendAmountRow.prototype, 'updateGas') - -describe('SendAmountRow Component', function () { - let wrapper - let instance - - beforeEach(() => { - wrapper = shallow(<SendAmountRow - amount={'mockAmount'} - amountConversionRate={'mockAmountConversionRate'} - balance={'mockBalance'} - conversionRate={7} - convertedCurrency={'mockConvertedCurrency'} - gasTotal={'mockGasTotal'} - inError={false} - primaryCurrency={'mockPrimaryCurrency'} - selectedToken={ { address: 'mockTokenAddress' } } - setMaxModeTo={propsMethodSpies.setMaxModeTo} - tokenBalance={'mockTokenBalance'} - updateSendAmount={propsMethodSpies.updateSendAmount} - updateSendAmountError={propsMethodSpies.updateSendAmountError} - updateGas={propsMethodSpies.updateGas} - />, { context: { t: str => str + '_t' } }) - instance = wrapper.instance() - }) - - afterEach(() => { - propsMethodSpies.setMaxModeTo.resetHistory() - propsMethodSpies.updateSendAmount.resetHistory() - propsMethodSpies.updateSendAmountError.resetHistory() - SendAmountRow.prototype.validateAmount.resetHistory() - SendAmountRow.prototype.updateAmount.resetHistory() - }) - - describe('validateAmount', () => { - - it('should call updateSendAmountError with the correct params', () => { - assert.equal(propsMethodSpies.updateSendAmountError.callCount, 0) - instance.validateAmount('someAmount') - assert.equal(propsMethodSpies.updateSendAmountError.callCount, 1) - assert.deepEqual( - propsMethodSpies.updateSendAmountError.getCall(0).args, - [{ - amount: 'someAmount', - amountConversionRate: 'mockAmountConversionRate', - balance: 'mockBalance', - conversionRate: 7, - gasTotal: 'mockGasTotal', - primaryCurrency: 'mockPrimaryCurrency', - selectedToken: { address: 'mockTokenAddress' }, - tokenBalance: 'mockTokenBalance', - }] - ) - }) - - }) - - describe('updateAmount', () => { - - it('should call setMaxModeTo', () => { - assert.equal(propsMethodSpies.setMaxModeTo.callCount, 0) - instance.updateAmount('someAmount') - assert.equal(propsMethodSpies.setMaxModeTo.callCount, 1) - assert.deepEqual( - propsMethodSpies.setMaxModeTo.getCall(0).args, - [false] - ) - }) - - it('should call updateSendAmount', () => { - assert.equal(propsMethodSpies.updateSendAmount.callCount, 0) - instance.updateAmount('someAmount') - assert.equal(propsMethodSpies.updateSendAmount.callCount, 1) - assert.deepEqual( - propsMethodSpies.updateSendAmount.getCall(0).args, - ['someAmount'] - ) - }) - - }) - - describe('render', () => { - it('should render a SendRowWrapper component', () => { - assert.equal(wrapper.find(SendRowWrapper).length, 1) - }) - - it('should pass the correct props to SendRowWrapper', () => { - const { - errorType, - label, - showError, - } = wrapper.find(SendRowWrapper).props() - - assert.equal(errorType, 'amount') - - assert.equal(label, 'amount_t:') - - assert.equal(showError, false) - }) - - it('should render an AmountMaxButton as the first child of the SendRowWrapper', () => { - assert(wrapper.find(SendRowWrapper).childAt(0).is(AmountMaxButton)) - }) - - it('should render a CurrencyDisplay as the second child of the SendRowWrapper', () => { - assert(wrapper.find(SendRowWrapper).childAt(1).is(CurrencyDisplay)) - }) - - it('should render the CurrencyDisplay with the correct props', () => { - const { - conversionRate, - convertedCurrency, - onBlur, - onChange, - inError, - primaryCurrency, - selectedToken, - value, - } = wrapper.find(SendRowWrapper).childAt(1).props() - assert.equal(conversionRate, 'mockAmountConversionRate') - assert.equal(convertedCurrency, 'mockConvertedCurrency') - assert.equal(inError, false) - assert.equal(primaryCurrency, 'mockPrimaryCurrency') - assert.deepEqual(selectedToken, { address: 'mockTokenAddress' }) - assert.equal(value, 'mockAmount') - assert.equal(SendAmountRow.prototype.updateGas.callCount, 0) - assert.equal(SendAmountRow.prototype.updateAmount.callCount, 0) - onBlur('mockNewAmount') - assert.equal(SendAmountRow.prototype.updateGas.callCount, 1) - assert.deepEqual( - SendAmountRow.prototype.updateGas.getCall(0).args, - ['mockNewAmount'] - ) - assert.equal(SendAmountRow.prototype.updateAmount.callCount, 1) - assert.deepEqual( - SendAmountRow.prototype.updateAmount.getCall(0).args, - ['mockNewAmount'] - ) - assert.equal(SendAmountRow.prototype.validateAmount.callCount, 0) - onChange('mockNewAmount') - assert.equal(SendAmountRow.prototype.validateAmount.callCount, 1) - assert.deepEqual( - SendAmountRow.prototype.validateAmount.getCall(0).args, - ['mockNewAmount'] - ) - }) - - it('should pass the default primaryCurrency to the CurrencyDisplay if primaryCurrency is falsy', () => { - wrapper.setProps({ primaryCurrency: null }) - const { primaryCurrency } = wrapper.find(SendRowWrapper).childAt(1).props() - assert.equal(primaryCurrency, 'ETH') - }) - }) -}) diff --git a/ui/app/components/send_/send-content/send-amount-row/tests/send-amount-row-container.test.js b/ui/app/components/send_/send-content/send-amount-row/tests/send-amount-row-container.test.js deleted file mode 100644 index 94d9918a7..000000000 --- a/ui/app/components/send_/send-content/send-amount-row/tests/send-amount-row-container.test.js +++ /dev/null @@ -1,109 +0,0 @@ -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}`, - getCurrentCurrency: (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.duck': 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 } - ) - }) - }) - - }) - -}) diff --git a/ui/app/components/send_/send-content/send-amount-row/tests/send-amount-row-selectors.test.js b/ui/app/components/send_/send-content/send-amount-row/tests/send-amount-row-selectors.test.js deleted file mode 100644 index 4672cb8a7..000000000 --- a/ui/app/components/send_/send-content/send-amount-row/tests/send-amount-row-selectors.test.js +++ /dev/null @@ -1,34 +0,0 @@ -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) - }) - }) - -}) diff --git a/ui/app/components/send_/send-content/send-content-README.md b/ui/app/components/send_/send-content/send-content-README.md deleted file mode 100644 index e69de29bb..000000000 --- a/ui/app/components/send_/send-content/send-content-README.md +++ /dev/null diff --git a/ui/app/components/send_/send-content/send-content.component.js b/ui/app/components/send_/send-content/send-content.component.js deleted file mode 100644 index adc114c0e..000000000 --- a/ui/app/components/send_/send-content/send-content.component.js +++ /dev/null @@ -1,28 +0,0 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' -import PageContainerContent from '../../page-container/page-container-content.component' -import SendAmountRow from './send-amount-row/' -import SendFromRow from './send-from-row/' -import SendGasRow from './send-gas-row/' -import SendToRow from './send-to-row/' - -export default class SendContent extends Component { - - static propTypes = { - updateGas: PropTypes.func, - }; - - render () { - return ( - <PageContainerContent> - <div className="send-v2__form"> - <SendFromRow /> - <SendToRow updateGas={(updateData) => this.props.updateGas(updateData)} /> - <SendAmountRow updateGas={(updateData) => this.props.updateGas(updateData)} /> - <SendGasRow /> - </div> - </PageContainerContent> - ) - } - -} diff --git a/ui/app/components/send_/send-content/send-content.scss b/ui/app/components/send_/send-content/send-content.scss deleted file mode 100644 index e69de29bb..000000000 --- a/ui/app/components/send_/send-content/send-content.scss +++ /dev/null diff --git a/ui/app/components/send_/send-content/send-dropdown-list/index.js b/ui/app/components/send_/send-content/send-dropdown-list/index.js deleted file mode 100644 index 04af6536c..000000000 --- a/ui/app/components/send_/send-content/send-dropdown-list/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './send-dropdown-list.component' diff --git a/ui/app/components/send_/send-content/send-dropdown-list/send-dropdown-list.component.js b/ui/app/components/send_/send-content/send-dropdown-list/send-dropdown-list.component.js deleted file mode 100644 index 5c7174ecf..000000000 --- a/ui/app/components/send_/send-content/send-dropdown-list/send-dropdown-list.component.js +++ /dev/null @@ -1,52 +0,0 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' -import AccountListItem from '../../account-list-item/' - -export default class SendDropdownList extends Component { - - static propTypes = { - accounts: PropTypes.array, - closeDropdown: PropTypes.func, - onSelect: PropTypes.func, - activeAddress: PropTypes.string, - }; - - getListItemIcon (accountAddress, activeAddress) { - return accountAddress === activeAddress - ? <i className={`fa fa-check fa-lg`} style={ { color: '#02c9b1' } }/> - : null - } - - render () { - const { - accounts, - closeDropdown, - onSelect, - activeAddress, - } = this.props - - return (<div> - <div - className="send-v2__from-dropdown__close-area" - onClick={() => closeDropdown()} - /> - <div className="send-v2__from-dropdown__list"> - {accounts.map((account, index) => <AccountListItem - account={account} - className="account-list-item__dropdown" - handleClick={() => { - onSelect(account) - closeDropdown() - }} - icon={this.getListItemIcon(account.address, activeAddress)} - key={`send-dropdown-account-#${index}`} - />)} - </div> - </div>) - } - -} - -SendDropdownList.contextTypes = { - t: PropTypes.func, -} diff --git a/ui/app/components/send_/send-content/send-dropdown-list/tests/send-dropdown-list-component.test.js b/ui/app/components/send_/send-content/send-dropdown-list/tests/send-dropdown-list-component.test.js deleted file mode 100644 index b92dd4dfe..000000000 --- a/ui/app/components/send_/send-content/send-dropdown-list/tests/send-dropdown-list-component.test.js +++ /dev/null @@ -1,105 +0,0 @@ -import React from 'react' -import assert from 'assert' -import { shallow } from 'enzyme' -import sinon from 'sinon' -import SendDropdownList from '../send-dropdown-list.component.js' - -import AccountListItem from '../../../account-list-item/account-list-item.container' - -const propsMethodSpies = { - closeDropdown: sinon.spy(), - onSelect: sinon.spy(), -} - -sinon.spy(SendDropdownList.prototype, 'getListItemIcon') - -describe('SendDropdownList Component', function () { - let wrapper - - beforeEach(() => { - wrapper = shallow(<SendDropdownList - accounts={[ - { address: 'mockAccount0' }, - { address: 'mockAccount1' }, - { address: 'mockAccount2' }, - ]} - closeDropdown={propsMethodSpies.closeDropdown} - onSelect={propsMethodSpies.onSelect} - activeAddress={'mockAddress2'} - />, { context: { t: str => str + '_t' } }) - }) - - afterEach(() => { - propsMethodSpies.closeDropdown.resetHistory() - propsMethodSpies.onSelect.resetHistory() - SendDropdownList.prototype.getListItemIcon.resetHistory() - }) - - describe('getListItemIcon', () => { - it('should return check icon if the passed addresses are the same', () => { - assert.deepEqual( - wrapper.instance().getListItemIcon('mockAccount0', 'mockAccount0'), - <i className={`fa fa-check fa-lg`} style={ { color: '#02c9b1' } }/> - ) - }) - - it('should return null if the passed addresses are different', () => { - assert.equal( - wrapper.instance().getListItemIcon('mockAccount0', 'mockAccount1'), - null - ) - }) - }) - - describe('render', () => { - it('should render a single div with two children', () => { - assert(wrapper.is('div')) - assert.equal(wrapper.children().length, 2) - }) - - it('should render the children with the correct classes', () => { - assert(wrapper.childAt(0).hasClass('send-v2__from-dropdown__close-area')) - assert(wrapper.childAt(1).hasClass('send-v2__from-dropdown__list')) - }) - - it('should call closeDropdown onClick of the send-v2__from-dropdown__close-area', () => { - assert.equal(propsMethodSpies.closeDropdown.callCount, 0) - wrapper.childAt(0).props().onClick() - assert.equal(propsMethodSpies.closeDropdown.callCount, 1) - }) - - it('should render an AccountListItem for each item in accounts', () => { - assert.equal(wrapper.childAt(1).children().length, 3) - assert(wrapper.childAt(1).children().every(AccountListItem)) - }) - - it('should pass the correct props to the AccountListItem', () => { - wrapper.childAt(1).children().forEach((accountListItem, index) => { - const { - account, - className, - handleClick, - } = accountListItem.props() - assert.deepEqual(account, { address: 'mockAccount' + index }) - assert.equal(className, 'account-list-item__dropdown') - assert.equal(propsMethodSpies.onSelect.callCount, 0) - handleClick() - assert.equal(propsMethodSpies.onSelect.callCount, 1) - assert.deepEqual(propsMethodSpies.onSelect.getCall(0).args[0], { address: 'mockAccount' + index }) - propsMethodSpies.onSelect.resetHistory() - propsMethodSpies.closeDropdown.resetHistory() - assert.equal(propsMethodSpies.closeDropdown.callCount, 0) - handleClick() - assert.equal(propsMethodSpies.closeDropdown.callCount, 1) - propsMethodSpies.onSelect.resetHistory() - propsMethodSpies.closeDropdown.resetHistory() - }) - }) - - it('should call this.getListItemIcon for each AccountListItem', () => { - assert.equal(SendDropdownList.prototype.getListItemIcon.callCount, 3) - const getListItemIconCalls = SendDropdownList.prototype.getListItemIcon.getCalls() - assert(getListItemIconCalls.every(({ args }, index) => args[0] === 'mockAccount' + index)) - }) - }) -}) diff --git a/ui/app/components/send_/send-content/send-from-row/from-dropdown/from-dropdown-README.md b/ui/app/components/send_/send-content/send-from-row/from-dropdown/from-dropdown-README.md deleted file mode 100644 index e69de29bb..000000000 --- a/ui/app/components/send_/send-content/send-from-row/from-dropdown/from-dropdown-README.md +++ /dev/null diff --git a/ui/app/components/send_/send-content/send-from-row/from-dropdown/from-dropdown.component.js b/ui/app/components/send_/send-content/send-from-row/from-dropdown/from-dropdown.component.js deleted file mode 100644 index 418766cd9..000000000 --- a/ui/app/components/send_/send-content/send-from-row/from-dropdown/from-dropdown.component.js +++ /dev/null @@ -1,46 +0,0 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' -import AccountListItem from '../../../account-list-item/' -import SendDropdownList from '../../send-dropdown-list/' - -export default class FromDropdown extends Component { - - static propTypes = { - accounts: PropTypes.array, - closeDropdown: PropTypes.func, - dropdownOpen: PropTypes.bool, - onSelect: PropTypes.func, - openDropdown: PropTypes.func, - selectedAccount: PropTypes.object, - }; - - render () { - const { - accounts, - closeDropdown, - dropdownOpen, - openDropdown, - selectedAccount, - onSelect, - } = this.props - - return <div className="send-v2__from-dropdown"> - <AccountListItem - account={selectedAccount} - handleClick={openDropdown} - icon={<i className={`fa fa-caret-down fa-lg`} style={ { color: '#dedede' } }/>} - /> - {dropdownOpen && <SendDropdownList - accounts={accounts} - closeDropdown={closeDropdown} - onSelect={onSelect} - activeAddress={selectedAccount.address} - />} - </div> - } - -} - -FromDropdown.contextTypes = { - t: PropTypes.func, -} diff --git a/ui/app/components/send_/send-content/send-from-row/from-dropdown/from-dropdown.scss b/ui/app/components/send_/send-content/send-from-row/from-dropdown/from-dropdown.scss deleted file mode 100644 index e69de29bb..000000000 --- a/ui/app/components/send_/send-content/send-from-row/from-dropdown/from-dropdown.scss +++ /dev/null diff --git a/ui/app/components/send_/send-content/send-from-row/from-dropdown/index.js b/ui/app/components/send_/send-content/send-from-row/from-dropdown/index.js deleted file mode 100644 index 2314ef4e3..000000000 --- a/ui/app/components/send_/send-content/send-from-row/from-dropdown/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './from-dropdown.component' diff --git a/ui/app/components/send_/send-content/send-from-row/from-dropdown/tests/from-dropdown-component.test.js b/ui/app/components/send_/send-content/send-from-row/from-dropdown/tests/from-dropdown-component.test.js deleted file mode 100644 index 84fcb281e..000000000 --- a/ui/app/components/send_/send-content/send-from-row/from-dropdown/tests/from-dropdown-component.test.js +++ /dev/null @@ -1,88 +0,0 @@ -import React from 'react' -import assert from 'assert' -import { shallow } from 'enzyme' -import sinon from 'sinon' -import FromDropdown from '../from-dropdown.component.js' - -import AccountListItem from '../../../../account-list-item/account-list-item.container' -import SendDropdownList from '../../../send-dropdown-list/send-dropdown-list.component' - -const propsMethodSpies = { - closeDropdown: sinon.spy(), - openDropdown: sinon.spy(), - onSelect: sinon.spy(), -} - -describe('FromDropdown Component', function () { - let wrapper - - beforeEach(() => { - wrapper = shallow(<FromDropdown - accounts={['mockAccount']} - closeDropdown={propsMethodSpies.closeDropdown} - dropdownOpen={false} - onSelect={propsMethodSpies.onSelect} - openDropdown={propsMethodSpies.openDropdown} - selectedAccount={ { address: 'mockAddress' } } - />, { context: { t: str => str + '_t' } }) - }) - - afterEach(() => { - propsMethodSpies.closeDropdown.resetHistory() - propsMethodSpies.openDropdown.resetHistory() - propsMethodSpies.onSelect.resetHistory() - }) - - describe('render', () => { - it('should render a div with a .send-v2__from-dropdown class', () => { - assert.equal(wrapper.find('.send-v2__from-dropdown').length, 1) - }) - - it('should render an AccountListItem as the first child of the .send-v2__from-dropdown div', () => { - assert(wrapper.find('.send-v2__from-dropdown').childAt(0).is(AccountListItem)) - }) - - it('should pass the correct props to AccountListItem', () => { - const { - account, - handleClick, - icon, - } = wrapper.find('.send-v2__from-dropdown').childAt(0).props() - assert.deepEqual(account, { address: 'mockAddress' }) - assert.deepEqual( - icon, - <i className={`fa fa-caret-down fa-lg`} style={ { color: '#dedede' } }/> - ) - assert.equal(propsMethodSpies.openDropdown.callCount, 0) - handleClick() - assert.equal(propsMethodSpies.openDropdown.callCount, 1) - }) - - it('should not render a SendDropdownList when dropdownOpen is false', () => { - assert.equal(wrapper.find(SendDropdownList).length, 0) - }) - - it('should render a SendDropdownList when dropdownOpen is true', () => { - wrapper.setProps({ dropdownOpen: true }) - assert(wrapper.find(SendDropdownList).length, 1) - }) - - it('should pass the correct props to the SendDropdownList]', () => { - wrapper.setProps({ dropdownOpen: true }) - const { - accounts, - closeDropdown, - onSelect, - activeAddress, - } = wrapper.find(SendDropdownList).props() - assert.deepEqual(accounts, ['mockAccount']) - assert.equal(activeAddress, 'mockAddress') - assert.equal(propsMethodSpies.closeDropdown.callCount, 0) - closeDropdown() - assert.equal(propsMethodSpies.closeDropdown.callCount, 1) - assert.equal(propsMethodSpies.onSelect.callCount, 0) - onSelect() - assert.equal(propsMethodSpies.onSelect.callCount, 1) - }) - }) -}) diff --git a/ui/app/components/send_/send-content/send-from-row/index.js b/ui/app/components/send_/send-content/send-from-row/index.js deleted file mode 100644 index 0a79726b2..000000000 --- a/ui/app/components/send_/send-content/send-from-row/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './send-from-row.container' diff --git a/ui/app/components/send_/send-content/send-from-row/send-from-row-README.md b/ui/app/components/send_/send-content/send-from-row/send-from-row-README.md deleted file mode 100644 index e69de29bb..000000000 --- a/ui/app/components/send_/send-content/send-from-row/send-from-row-README.md +++ /dev/null diff --git a/ui/app/components/send_/send-content/send-from-row/send-from-row.component.js b/ui/app/components/send_/send-content/send-from-row/send-from-row.component.js deleted file mode 100644 index a580aef96..000000000 --- a/ui/app/components/send_/send-content/send-from-row/send-from-row.component.js +++ /dev/null @@ -1,63 +0,0 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' -import SendRowWrapper from '../send-row-wrapper/' -import FromDropdown from './from-dropdown/' - -export default class SendFromRow extends Component { - - static propTypes = { - closeFromDropdown: PropTypes.func, - conversionRate: PropTypes.number, - from: PropTypes.object, - fromAccounts: PropTypes.array, - fromDropdownOpen: PropTypes.bool, - openFromDropdown: PropTypes.func, - tokenContract: PropTypes.object, - updateSendFrom: PropTypes.func, - setSendTokenBalance: PropTypes.func, - }; - - async handleFromChange (newFrom) { - const { - updateSendFrom, - tokenContract, - setSendTokenBalance, - } = this.props - - if (tokenContract) { - const usersToken = await tokenContract.balanceOf(newFrom.address) - setSendTokenBalance(usersToken) - } - updateSendFrom(newFrom) - } - - render () { - const { - closeFromDropdown, - conversionRate, - from, - fromAccounts, - fromDropdownOpen, - openFromDropdown, - } = this.props - - return ( - <SendRowWrapper label={`${this.context.t('from')}:`}> - <FromDropdown - accounts={fromAccounts} - closeDropdown={() => closeFromDropdown()} - conversionRate={conversionRate} - dropdownOpen={fromDropdownOpen} - onSelect={newFrom => this.handleFromChange(newFrom)} - openDropdown={() => openFromDropdown()} - selectedAccount={from} - /> - </SendRowWrapper> - ) - } - -} - -SendFromRow.contextTypes = { - t: PropTypes.func, -} diff --git a/ui/app/components/send_/send-content/send-from-row/send-from-row.container.js b/ui/app/components/send_/send-content/send-from-row/send-from-row.container.js deleted file mode 100644 index 33cb63b43..000000000 --- a/ui/app/components/send_/send-content/send-from-row/send-from-row.container.js +++ /dev/null @@ -1,46 +0,0 @@ -import { connect } from 'react-redux' -import { - accountsWithSendEtherInfoSelector, - getConversionRate, - getSelectedTokenContract, - getSendFromObject, -} from '../../send.selectors.js' -import { - getFromDropdownOpen, -} from './send-from-row.selectors.js' -import { calcTokenBalance } from '../../send.utils.js' -import { - updateSendFrom, - setSendTokenBalance, -} from '../../../../actions' -import { - closeFromDropdown, - openFromDropdown, -} from '../../../../ducks/send.duck' -import SendFromRow from './send-from-row.component' - -export default connect(mapStateToProps, mapDispatchToProps)(SendFromRow) - -function mapStateToProps (state) { - return { - conversionRate: getConversionRate(state), - from: getSendFromObject(state), - fromAccounts: accountsWithSendEtherInfoSelector(state), - fromDropdownOpen: getFromDropdownOpen(state), - tokenContract: getSelectedTokenContract(state), - } -} - -function mapDispatchToProps (dispatch) { - return { - closeFromDropdown: () => dispatch(closeFromDropdown()), - openFromDropdown: () => dispatch(openFromDropdown()), - updateSendFrom: newFrom => dispatch(updateSendFrom(newFrom)), - setSendTokenBalance: (usersToken, selectedToken) => { - if (!usersToken) return - - const tokenBalance = calcTokenBalance({ usersToken, selectedToken }) - dispatch(setSendTokenBalance(tokenBalance)) - }, - } -} diff --git a/ui/app/components/send_/send-content/send-from-row/send-from-row.selectors.js b/ui/app/components/send_/send-content/send-from-row/send-from-row.selectors.js deleted file mode 100644 index 03ef4806b..000000000 --- a/ui/app/components/send_/send-content/send-from-row/send-from-row.selectors.js +++ /dev/null @@ -1,9 +0,0 @@ -const selectors = { - getFromDropdownOpen, -} - -module.exports = selectors - -function getFromDropdownOpen (state) { - return state.send.fromDropdownOpen -} diff --git a/ui/app/components/send_/send-content/send-from-row/tests/send-from-row-component.test.js b/ui/app/components/send_/send-content/send-from-row/tests/send-from-row-component.test.js deleted file mode 100644 index 9ba8d1739..000000000 --- a/ui/app/components/send_/send-content/send-from-row/tests/send-from-row-component.test.js +++ /dev/null @@ -1,121 +0,0 @@ -import React from 'react' -import assert from 'assert' -import { shallow } from 'enzyme' -import sinon from 'sinon' -import SendFromRow from '../send-from-row.component.js' - -import SendRowWrapper from '../../send-row-wrapper/send-row-wrapper.component' -import FromDropdown from '../from-dropdown/from-dropdown.component' - -const propsMethodSpies = { - closeFromDropdown: sinon.spy(), - openFromDropdown: sinon.spy(), - updateSendFrom: sinon.spy(), - setSendTokenBalance: sinon.spy(), -} - -sinon.spy(SendFromRow.prototype, 'handleFromChange') - -describe('SendFromRow Component', function () { - let wrapper - let instance - - beforeEach(() => { - wrapper = shallow(<SendFromRow - closeFromDropdown={propsMethodSpies.closeFromDropdown} - conversionRate={15} - from={ { address: 'mockAddress' } } - fromAccounts={['mockAccount']} - fromDropdownOpen={false} - openFromDropdown={propsMethodSpies.openFromDropdown} - setSendTokenBalance={propsMethodSpies.setSendTokenBalance} - tokenContract={null} - updateSendFrom={propsMethodSpies.updateSendFrom} - />, { context: { t: str => str + '_t' } }) - instance = wrapper.instance() - }) - - afterEach(() => { - propsMethodSpies.closeFromDropdown.resetHistory() - propsMethodSpies.openFromDropdown.resetHistory() - propsMethodSpies.updateSendFrom.resetHistory() - propsMethodSpies.setSendTokenBalance.resetHistory() - SendFromRow.prototype.handleFromChange.resetHistory() - }) - - describe('handleFromChange', () => { - - it('should call updateSendFrom', () => { - assert.equal(propsMethodSpies.updateSendFrom.callCount, 0) - instance.handleFromChange('mockFrom') - assert.equal(propsMethodSpies.updateSendFrom.callCount, 1) - assert.deepEqual( - propsMethodSpies.updateSendFrom.getCall(0).args, - ['mockFrom'] - ) - }) - - it('should call tokenContract.balanceOf and setSendTokenBalance if tokenContract is defined', async () => { - wrapper.setProps({ - tokenContract: { - balanceOf: () => new Promise((resolve) => resolve('mockUsersToken')), - }, - }) - assert.equal(propsMethodSpies.setSendTokenBalance.callCount, 0) - await instance.handleFromChange('mockFrom') - assert.equal(propsMethodSpies.setSendTokenBalance.callCount, 1) - assert.deepEqual( - propsMethodSpies.setSendTokenBalance.getCall(0).args, - ['mockUsersToken'] - ) - }) - - }) - - describe('render', () => { - it('should render a SendRowWrapper component', () => { - assert.equal(wrapper.find(SendRowWrapper).length, 1) - }) - - it('should pass the correct props to SendRowWrapper', () => { - const { - label, - } = wrapper.find(SendRowWrapper).props() - - assert.equal(label, 'from_t:') - }) - - it('should render an FromDropdown as a child of the SendRowWrapper', () => { - assert(wrapper.find(SendRowWrapper).childAt(0).is(FromDropdown)) - }) - - it('should render the FromDropdown with the correct props', () => { - const { - accounts, - closeDropdown, - conversionRate, - dropdownOpen, - onSelect, - openDropdown, - selectedAccount, - } = wrapper.find(SendRowWrapper).childAt(0).props() - assert.deepEqual(accounts, ['mockAccount']) - assert.equal(dropdownOpen, false) - assert.equal(conversionRate, 15) - assert.deepEqual(selectedAccount, { address: 'mockAddress' }) - assert.equal(propsMethodSpies.closeFromDropdown.callCount, 0) - closeDropdown() - assert.equal(propsMethodSpies.closeFromDropdown.callCount, 1) - assert.equal(propsMethodSpies.openFromDropdown.callCount, 0) - openDropdown() - assert.equal(propsMethodSpies.openFromDropdown.callCount, 1) - assert.equal(SendFromRow.prototype.handleFromChange.callCount, 0) - onSelect('mockNewFrom') - assert.equal(SendFromRow.prototype.handleFromChange.callCount, 1) - assert.deepEqual( - SendFromRow.prototype.handleFromChange.getCall(0).args, - ['mockNewFrom'] - ) - }) - }) -}) diff --git a/ui/app/components/send_/send-content/send-from-row/tests/send-from-row-container.test.js b/ui/app/components/send_/send-content/send-from-row/tests/send-from-row-container.test.js deleted file mode 100644 index e080b2fe3..000000000 --- a/ui/app/components/send_/send-content/send-from-row/tests/send-from-row-container.test.js +++ /dev/null @@ -1,110 +0,0 @@ -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: ({ usersToken, selectedToken }) => usersToken + selectedToken }, - '../../../../actions': actionSpies, - '../../../../ducks/send.duck': 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' - ) - }) - }) - - }) - -}) diff --git a/ui/app/components/send_/send-content/send-from-row/tests/send-from-row-selectors.test.js b/ui/app/components/send_/send-content/send-from-row/tests/send-from-row-selectors.test.js deleted file mode 100644 index ecb57bbc3..000000000 --- a/ui/app/components/send_/send-content/send-from-row/tests/send-from-row-selectors.test.js +++ /dev/null @@ -1,20 +0,0 @@ -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) - }) - }) - -}) diff --git a/ui/app/components/send_/send-content/send-gas-row/README.md b/ui/app/components/send_/send-content/send-gas-row/README.md deleted file mode 100644 index e69de29bb..000000000 --- a/ui/app/components/send_/send-content/send-gas-row/README.md +++ /dev/null diff --git a/ui/app/components/send_/send-content/send-gas-row/gas-fee-display/gas-fee-display.component.js b/ui/app/components/send_/send-content/send-gas-row/gas-fee-display/gas-fee-display.component.js deleted file mode 100644 index c8d619be5..000000000 --- a/ui/app/components/send_/send-content/send-gas-row/gas-fee-display/gas-fee-display.component.js +++ /dev/null @@ -1,61 +0,0 @@ -import React, {Component} from 'react' -import PropTypes from 'prop-types' -import CurrencyDisplay from '../../../../send/currency-display' - - -export default class GasFeeDisplay extends Component { - - static propTypes = { - conversionRate: PropTypes.number, - primaryCurrency: PropTypes.string, - convertedCurrency: PropTypes.string, - gasLoadingError: PropTypes.bool, - gasTotal: PropTypes.string, - onClick: PropTypes.func, - }; - - render () { - const { - conversionRate, - gasTotal, - onClick, - primaryCurrency = 'ETH', - convertedCurrency, - gasLoadingError, - } = this.props - - return ( - <div className="send-v2__gas-fee-display"> - {gasTotal - ? <CurrencyDisplay - primaryCurrency={primaryCurrency} - convertedCurrency={convertedCurrency} - value={gasTotal} - conversionRate={conversionRate} - gasLoadingError={gasLoadingError} - convertedPrefix={'$'} - readOnly - /> - : gasLoadingError - ? <div className="currency-display.currency-display--message"> - {this.context.t('setGasPrice')} - </div> - : <div className="currency-display"> - {this.context.t('loading')} - </div> - } - <button - className="sliders-icon-container" - onClick={onClick} - disabled={!gasTotal && !gasLoadingError} - > - <i className="fa fa-sliders sliders-icon" /> - </button> - </div> - ) - } -} - -GasFeeDisplay.contextTypes = { - t: PropTypes.func, -} diff --git a/ui/app/components/send_/send-content/send-gas-row/gas-fee-display/index.js b/ui/app/components/send_/send-content/send-gas-row/gas-fee-display/index.js deleted file mode 100644 index dba0edb7b..000000000 --- a/ui/app/components/send_/send-content/send-gas-row/gas-fee-display/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './gas-fee-display.component' diff --git a/ui/app/components/send_/send-content/send-gas-row/gas-fee-display/test/gas-fee-display.component.test.js b/ui/app/components/send_/send-content/send-gas-row/gas-fee-display/test/gas-fee-display.component.test.js deleted file mode 100644 index 7cbe8d0df..000000000 --- a/ui/app/components/send_/send-content/send-gas-row/gas-fee-display/test/gas-fee-display.component.test.js +++ /dev/null @@ -1,55 +0,0 @@ -import React from 'react' -import assert from 'assert' -import {shallow} from 'enzyme' -import GasFeeDisplay from '../gas-fee-display.component' -import CurrencyDisplay from '../../../../../send/currency-display' -import sinon from 'sinon' - - -const propsMethodSpies = { - showCustomizeGasModal: sinon.spy(), -} - -describe('SendGasRow Component', function () { - let wrapper - - beforeEach(() => { - wrapper = shallow(<GasFeeDisplay - conversionRate={20} - gasTotal={'mockGasTotal'} - onClick={propsMethodSpies.showCustomizeGasModal} - primaryCurrency={'mockPrimaryCurrency'} - convertedCurrency={'mockConvertedCurrency'} - />, {context: {t: str => str + '_t'}}) - }) - - afterEach(() => { - propsMethodSpies.showCustomizeGasModal.resetHistory() - }) - - describe('render', () => { - it('should render a CurrencyDisplay component', () => { - assert.equal(wrapper.find(CurrencyDisplay).length, 1) - }) - - it('should render the CurrencyDisplay with the correct props', () => { - const { - conversionRate, - convertedCurrency, - value, - } = wrapper.find(CurrencyDisplay).props() - assert.equal(conversionRate, 20) - assert.equal(convertedCurrency, 'mockConvertedCurrency') - assert.equal(value, 'mockGasTotal') - }) - - it('should render the Button with the correct props', () => { - const { - onClick, - } = wrapper.find('button').props() - assert.equal(propsMethodSpies.showCustomizeGasModal.callCount, 0) - onClick() - assert.equal(propsMethodSpies.showCustomizeGasModal.callCount, 1) - }) - }) -}) diff --git a/ui/app/components/send_/send-content/send-gas-row/index.js b/ui/app/components/send_/send-content/send-gas-row/index.js deleted file mode 100644 index 3c7ff1d5f..000000000 --- a/ui/app/components/send_/send-content/send-gas-row/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './send-gas-row.container' diff --git a/ui/app/components/send_/send-content/send-gas-row/send-gas-row.component.js b/ui/app/components/send_/send-content/send-gas-row/send-gas-row.component.js deleted file mode 100644 index 17cea3d4e..000000000 --- a/ui/app/components/send_/send-content/send-gas-row/send-gas-row.component.js +++ /dev/null @@ -1,42 +0,0 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' -import SendRowWrapper from '../send-row-wrapper/' -import GasFeeDisplay from './gas-fee-display/gas-fee-display.component' - -export default class SendGasRow extends Component { - - static propTypes = { - conversionRate: PropTypes.number, - convertedCurrency: PropTypes.string, - gasLoadingError: PropTypes.bool, - gasTotal: PropTypes.string, - showCustomizeGasModal: PropTypes.func, - }; - - render () { - const { - conversionRate, - convertedCurrency, - gasLoadingError, - gasTotal, - showCustomizeGasModal, - } = this.props - - return ( - <SendRowWrapper label={`${this.context.t('gasFee')}:`}> - <GasFeeDisplay - conversionRate={conversionRate} - convertedCurrency={convertedCurrency} - gasLoadingError={gasLoadingError} - gasTotal={gasTotal} - onClick={() => showCustomizeGasModal()} - /> - </SendRowWrapper> - ) - } - -} - -SendGasRow.contextTypes = { - t: PropTypes.func, -} diff --git a/ui/app/components/send_/send-content/send-gas-row/send-gas-row.container.js b/ui/app/components/send_/send-content/send-gas-row/send-gas-row.container.js deleted file mode 100644 index 6e6fbc8a8..000000000 --- a/ui/app/components/send_/send-content/send-gas-row/send-gas-row.container.js +++ /dev/null @@ -1,26 +0,0 @@ -import { connect } from 'react-redux' -import { - getConversionRate, - getCurrentCurrency, - getGasTotal, -} from '../../send.selectors.js' -import { sendGasIsInError } from './send-gas-row.selectors.js' -import { showModal } from '../../../../actions' -import SendGasRow from './send-gas-row.component' - -export default connect(mapStateToProps, mapDispatchToProps)(SendGasRow) - -function mapStateToProps (state) { - return { - conversionRate: getConversionRate(state), - convertedCurrency: getCurrentCurrency(state), - gasTotal: getGasTotal(state), - gasLoadingError: sendGasIsInError(state), - } -} - -function mapDispatchToProps (dispatch) { - return { - showCustomizeGasModal: () => dispatch(showModal({ name: 'CUSTOMIZE_GAS' })), - } -} diff --git a/ui/app/components/send_/send-content/send-gas-row/send-gas-row.scss b/ui/app/components/send_/send-content/send-gas-row/send-gas-row.scss deleted file mode 100644 index e69de29bb..000000000 --- a/ui/app/components/send_/send-content/send-gas-row/send-gas-row.scss +++ /dev/null diff --git a/ui/app/components/send_/send-content/send-gas-row/send-gas-row.selectors.js b/ui/app/components/send_/send-content/send-gas-row/send-gas-row.selectors.js deleted file mode 100644 index d069ae8c6..000000000 --- a/ui/app/components/send_/send-content/send-gas-row/send-gas-row.selectors.js +++ /dev/null @@ -1,9 +0,0 @@ -const selectors = { - sendGasIsInError, -} - -module.exports = selectors - -function sendGasIsInError (state) { - return state.send.errors.gasLoading -} diff --git a/ui/app/components/send_/send-content/send-gas-row/tests/send-gas-row-component.test.js b/ui/app/components/send_/send-content/send-gas-row/tests/send-gas-row-component.test.js deleted file mode 100644 index db37f18be..000000000 --- a/ui/app/components/send_/send-content/send-gas-row/tests/send-gas-row-component.test.js +++ /dev/null @@ -1,65 +0,0 @@ -import React from 'react' -import assert from 'assert' -import { shallow } from 'enzyme' -import sinon from 'sinon' -import SendGasRow from '../send-gas-row.component.js' - -import SendRowWrapper from '../../send-row-wrapper/send-row-wrapper.component' -import GasFeeDisplay from '../gas-fee-display/gas-fee-display.component' - -const propsMethodSpies = { - showCustomizeGasModal: sinon.spy(), -} - -describe('SendGasRow Component', function () { - let wrapper - - beforeEach(() => { - wrapper = shallow(<SendGasRow - conversionRate={20} - convertedCurrency={'mockConvertedCurrency'} - gasLoadingError={false} - gasTotal={'mockGasTotal'} - showCustomizeGasModal={propsMethodSpies.showCustomizeGasModal} - />, { context: { t: str => str + '_t' } }) - }) - - afterEach(() => { - propsMethodSpies.showCustomizeGasModal.resetHistory() - }) - - describe('render', () => { - it('should render a SendRowWrapper component', () => { - assert.equal(wrapper.find(SendRowWrapper).length, 1) - }) - - it('should pass the correct props to SendRowWrapper', () => { - const { - label, - } = wrapper.find(SendRowWrapper).props() - - assert.equal(label, 'gasFee_t:') - }) - - it('should render a GasFeeDisplay as a child of the SendRowWrapper', () => { - assert(wrapper.find(SendRowWrapper).childAt(0).is(GasFeeDisplay)) - }) - - it('should render the GasFeeDisplay with the correct props', () => { - const { - conversionRate, - convertedCurrency, - gasLoadingError, - gasTotal, - onClick, - } = wrapper.find(SendRowWrapper).childAt(0).props() - assert.equal(conversionRate, 20) - assert.equal(convertedCurrency, 'mockConvertedCurrency') - assert.equal(gasLoadingError, false) - assert.equal(gasTotal, 'mockGasTotal') - assert.equal(propsMethodSpies.showCustomizeGasModal.callCount, 0) - onClick() - assert.equal(propsMethodSpies.showCustomizeGasModal.callCount, 1) - }) - }) -}) diff --git a/ui/app/components/send_/send-content/send-gas-row/tests/send-gas-row-container.test.js b/ui/app/components/send_/send-content/send-gas-row/tests/send-gas-row-container.test.js deleted file mode 100644 index e928c8aba..000000000 --- a/ui/app/components/send_/send-content/send-gas-row/tests/send-gas-row-container.test.js +++ /dev/null @@ -1,66 +0,0 @@ -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}`, - getCurrentCurrency: (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' } - ) - }) - }) - - }) - -}) diff --git a/ui/app/components/send_/send-content/send-gas-row/tests/send-gas-row-selectors.test.js b/ui/app/components/send_/send-content/send-gas-row/tests/send-gas-row-selectors.test.js deleted file mode 100644 index a5196334e..000000000 --- a/ui/app/components/send_/send-content/send-gas-row/tests/send-gas-row-selectors.test.js +++ /dev/null @@ -1,22 +0,0 @@ -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') - }) - }) - -}) diff --git a/ui/app/components/send_/send-content/send-row-wrapper/index.js b/ui/app/components/send_/send-content/send-row-wrapper/index.js deleted file mode 100644 index d17545dcc..000000000 --- a/ui/app/components/send_/send-content/send-row-wrapper/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './send-row-wrapper.component' diff --git a/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/index.js b/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/index.js deleted file mode 100644 index c00617f83..000000000 --- a/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './send-row-error-message.container' diff --git a/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/send-row-error-message-README.md b/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/send-row-error-message-README.md deleted file mode 100644 index e69de29bb..000000000 --- a/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/send-row-error-message-README.md +++ /dev/null diff --git a/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.component.js b/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.component.js deleted file mode 100644 index 0d314208b..000000000 --- a/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.component.js +++ /dev/null @@ -1,27 +0,0 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' - -export default class SendRowErrorMessage extends Component { - - static propTypes = { - errors: PropTypes.object, - errorType: PropTypes.string, - }; - - render () { - const { errors, errorType } = this.props - - const errorMessage = errors[errorType] - - return ( - errorMessage - ? <div className="send-v2__error">{this.context.t(errorMessage)}</div> - : null - ) - } - -} - -SendRowErrorMessage.contextTypes = { - t: PropTypes.func, -} diff --git a/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.container.js b/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.container.js deleted file mode 100644 index 59622047f..000000000 --- a/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.container.js +++ /dev/null @@ -1,12 +0,0 @@ -import { connect } from 'react-redux' -import { getSendErrors } from '../../../send.selectors' -import SendRowErrorMessage from './send-row-error-message.component' - -export default connect(mapStateToProps)(SendRowErrorMessage) - -function mapStateToProps (state, ownProps) { - return { - errors: getSendErrors(state), - errorType: ownProps.errorType, - } -} diff --git a/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.scss b/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.scss deleted file mode 100644 index e69de29bb..000000000 --- a/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.scss +++ /dev/null diff --git a/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/tests/send-row-error-message-component.test.js b/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/tests/send-row-error-message-component.test.js deleted file mode 100644 index 2304a43d2..000000000 --- a/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/tests/send-row-error-message-component.test.js +++ /dev/null @@ -1,28 +0,0 @@ -import React from 'react' -import assert from 'assert' -import { shallow } from 'enzyme' -import SendRowErrorMessage from '../send-row-error-message.component.js' - -describe('SendRowErrorMessage Component', function () { - let wrapper - - beforeEach(() => { - wrapper = shallow(<SendRowErrorMessage - errors={{ error1: 'abc', error2: 'def' }} - errorType={'error3'} - />, { context: { t: str => str + '_t' } }) - }) - - describe('render', () => { - it('should render null if the passed errors do not contain an error of errorType', () => { - assert.equal(wrapper.find('.send-v2__error').length, 0) - assert.equal(wrapper.html(), null) - }) - - it('should render an error message if the passed errors contain an error of errorType', () => { - wrapper.setProps({ errors: { error1: 'abc', error2: 'def', error3: 'xyz' } }) - assert.equal(wrapper.find('.send-v2__error').length, 1) - assert.equal(wrapper.find('.send-v2__error').text(), 'xyz_t') - }) - }) -}) diff --git a/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/tests/send-row-error-message-container.test.js b/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/tests/send-row-error-message-container.test.js deleted file mode 100644 index eecff165d..000000000 --- a/ui/app/components/send_/send-content/send-row-wrapper/send-row-error-message/tests/send-row-error-message-container.test.js +++ /dev/null @@ -1,28 +0,0 @@ -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' }) - }) - - }) - -}) diff --git a/ui/app/components/send_/send-content/send-row-wrapper/send-row-wrapper-README.md b/ui/app/components/send_/send-content/send-row-wrapper/send-row-wrapper-README.md deleted file mode 100644 index e69de29bb..000000000 --- a/ui/app/components/send_/send-content/send-row-wrapper/send-row-wrapper-README.md +++ /dev/null diff --git a/ui/app/components/send_/send-content/send-row-wrapper/send-row-wrapper.component.js b/ui/app/components/send_/send-content/send-row-wrapper/send-row-wrapper.component.js deleted file mode 100644 index f484bd8d9..000000000 --- a/ui/app/components/send_/send-content/send-row-wrapper/send-row-wrapper.component.js +++ /dev/null @@ -1,43 +0,0 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' -import SendRowErrorMessage from './send-row-error-message/' - -export default class SendRowWrapper extends Component { - - static propTypes = { - children: PropTypes.node, - errorType: PropTypes.string, - label: PropTypes.string, - showError: PropTypes.bool, - }; - - render () { - const { - children, - errorType = '', - label, - showError = false, - } = this.props - - const formField = Array.isArray(children) ? children[1] || children[0] : children - const customLabelContent = children.length > 1 ? children[0] : null - - return ( - <div className="send-v2__form-row"> - <div className="send-v2__form-label"> - {label} - {showError && <SendRowErrorMessage errorType={errorType}/>} - {customLabelContent} - </div> - <div className="send-v2__form-field"> - {formField} - </div> - </div> - ) - } - -} - -SendRowWrapper.contextTypes = { - t: PropTypes.func, -} diff --git a/ui/app/components/send_/send-content/send-row-wrapper/send-row-wrapper.scss b/ui/app/components/send_/send-content/send-row-wrapper/send-row-wrapper.scss deleted file mode 100644 index e69de29bb..000000000 --- a/ui/app/components/send_/send-content/send-row-wrapper/send-row-wrapper.scss +++ /dev/null diff --git a/ui/app/components/send_/send-content/send-row-wrapper/tests/send-row-wrapper-component.test.js b/ui/app/components/send_/send-content/send-row-wrapper/tests/send-row-wrapper-component.test.js deleted file mode 100644 index 30280e1d0..000000000 --- a/ui/app/components/send_/send-content/send-row-wrapper/tests/send-row-wrapper-component.test.js +++ /dev/null @@ -1,79 +0,0 @@ -import React from 'react' -import assert from 'assert' -import { shallow } from 'enzyme' -import SendRowWrapper from '../send-row-wrapper.component.js' - -import SendRowErrorMessage from '../send-row-error-message/send-row-error-message.container' - -describe('SendContent Component', function () { - let wrapper - - beforeEach(() => { - wrapper = shallow(<SendRowWrapper - errorType={'mockErrorType'} - label={'mockLabel'} - showError={false} - > - <span>Mock Form Field</span> - </SendRowWrapper>) - }) - - describe('render', () => { - it('should render a div with a send-v2__form-row class', () => { - assert.equal(wrapper.find('div.send-v2__form-row').length, 1) - }) - - it('should render two children of the root div, with send-v2_form label and field classes', () => { - assert.equal(wrapper.find('.send-v2__form-row > .send-v2__form-label').length, 1) - assert.equal(wrapper.find('.send-v2__form-row > .send-v2__form-field').length, 1) - }) - - it('should render the label as a child of the send-v2__form-label', () => { - assert.equal(wrapper.find('.send-v2__form-row > .send-v2__form-label').childAt(0).text(), 'mockLabel') - }) - - it('should render its first child as a child of the send-v2__form-field', () => { - assert.equal(wrapper.find('.send-v2__form-row > .send-v2__form-field').childAt(0).text(), 'Mock Form Field') - }) - - it('should not render a SendRowErrorMessage if showError is false', () => { - assert.equal(wrapper.find(SendRowErrorMessage).length, 0) - }) - - it('should render a SendRowErrorMessage with and errorType props if showError is true', () => { - wrapper.setProps({showError: true}) - assert.equal(wrapper.find(SendRowErrorMessage).length, 1) - - const expectedSendRowErrorMessage = wrapper.find('.send-v2__form-row > .send-v2__form-label').childAt(1) - assert(expectedSendRowErrorMessage.is(SendRowErrorMessage)) - assert.deepEqual( - expectedSendRowErrorMessage.props(), - { errorType: 'mockErrorType' } - ) - }) - - it('should render its second child as a child of the send-v2__form-field, if it has two children', () => { - wrapper = shallow(<SendRowWrapper - errorType={'mockErrorType'} - label={'mockLabel'} - showError={false} - > - <span>Mock Custom Label Content</span> - <span>Mock Form Field</span> - </SendRowWrapper>) - assert.equal(wrapper.find('.send-v2__form-row > .send-v2__form-field').childAt(0).text(), 'Mock Form Field') - }) - - it('should render its first child as the last child of the send-v2__form-label, if it has two children', () => { - wrapper = shallow(<SendRowWrapper - errorType={'mockErrorType'} - label={'mockLabel'} - showError={false} - > - <span>Mock Custom Label Content</span> - <span>Mock Form Field</span> - </SendRowWrapper>) - assert.equal(wrapper.find('.send-v2__form-row > .send-v2__form-label').childAt(1).text(), 'Mock Custom Label Content') - }) - }) -}) diff --git a/ui/app/components/send_/send-content/send-to-row/index.js b/ui/app/components/send_/send-content/send-to-row/index.js deleted file mode 100644 index 121f15148..000000000 --- a/ui/app/components/send_/send-content/send-to-row/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './send-to-row.container' diff --git a/ui/app/components/send_/send-content/send-to-row/send-to-row-README.md b/ui/app/components/send_/send-content/send-to-row/send-to-row-README.md deleted file mode 100644 index e69de29bb..000000000 --- a/ui/app/components/send_/send-content/send-to-row/send-to-row-README.md +++ /dev/null diff --git a/ui/app/components/send_/send-content/send-to-row/send-to-row.component.js b/ui/app/components/send_/send-content/send-to-row/send-to-row.component.js deleted file mode 100644 index 1c2ecdf9c..000000000 --- a/ui/app/components/send_/send-content/send-to-row/send-to-row.component.js +++ /dev/null @@ -1,70 +0,0 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' -import SendRowWrapper from '../send-row-wrapper/' -import EnsInput from '../../../ens-input' -import { getToErrorObject } from './send-to-row.utils.js' - -export default class SendToRow extends Component { - - static propTypes = { - closeToDropdown: PropTypes.func, - inError: PropTypes.bool, - network: PropTypes.string, - openToDropdown: PropTypes.func, - to: PropTypes.string, - toAccounts: PropTypes.array, - toDropdownOpen: PropTypes.bool, - updateGas: PropTypes.func, - updateSendTo: PropTypes.func, - updateSendToError: PropTypes.func, - }; - - handleToChange (to, nickname = '', toError) { - const { updateSendTo, updateSendToError, updateGas } = this.props - const toErrorObject = getToErrorObject(to, toError) - updateSendTo(to, nickname) - updateSendToError(toErrorObject) - if (toErrorObject.to === null) { - updateGas({ to }) - } - } - - render () { - const { - closeToDropdown, - inError, - network, - openToDropdown, - to, - toAccounts, - toDropdownOpen, - } = this.props - - return ( - <SendRowWrapper - errorType={'to'} - label={`${this.context.t('to')}`} - showError={inError} - > - <EnsInput - accounts={toAccounts} - closeDropdown={() => closeToDropdown()} - dropdownOpen={toDropdownOpen} - inError={inError} - name={'address'} - network={network} - onChange={({ toAddress, nickname, toError }) => this.handleToChange(toAddress, nickname, toError)} - openDropdown={() => openToDropdown()} - placeholder={this.context.t('recipientAddress')} - to={to} - /> - </SendRowWrapper> - ) - } - -} - -SendToRow.contextTypes = { - t: PropTypes.func, -} - diff --git a/ui/app/components/send_/send-content/send-to-row/send-to-row.container.js b/ui/app/components/send_/send-content/send-to-row/send-to-row.container.js deleted file mode 100644 index 1c9c9d518..000000000 --- a/ui/app/components/send_/send-content/send-to-row/send-to-row.container.js +++ /dev/null @@ -1,42 +0,0 @@ -import { connect } from 'react-redux' -import { - getCurrentNetwork, - getSendTo, - getSendToAccounts, -} from '../../send.selectors.js' -import { - getToDropdownOpen, - sendToIsInError, -} from './send-to-row.selectors.js' -import { - updateSendTo, -} from '../../../../actions' -import { - updateSendErrors, - openToDropdown, - closeToDropdown, -} from '../../../../ducks/send.duck' -import SendToRow from './send-to-row.component' - -export default connect(mapStateToProps, mapDispatchToProps)(SendToRow) - -function mapStateToProps (state) { - return { - inError: sendToIsInError(state), - network: getCurrentNetwork(state), - to: getSendTo(state), - toAccounts: getSendToAccounts(state), - toDropdownOpen: getToDropdownOpen(state), - } -} - -function mapDispatchToProps (dispatch) { - return { - closeToDropdown: () => dispatch(closeToDropdown()), - openToDropdown: () => dispatch(openToDropdown()), - updateSendTo: (to, nickname) => dispatch(updateSendTo(to, nickname)), - updateSendToError: (toErrorObject) => { - dispatch(updateSendErrors(toErrorObject)) - }, - } -} diff --git a/ui/app/components/send_/send-content/send-to-row/send-to-row.selectors.js b/ui/app/components/send_/send-content/send-to-row/send-to-row.selectors.js deleted file mode 100644 index 8919014be..000000000 --- a/ui/app/components/send_/send-content/send-to-row/send-to-row.selectors.js +++ /dev/null @@ -1,14 +0,0 @@ -const selectors = { - getToDropdownOpen, - sendToIsInError, -} - -module.exports = selectors - -function getToDropdownOpen (state) { - return state.send.toDropdownOpen -} - -function sendToIsInError (state) { - return Boolean(state.send.errors.to) -} diff --git a/ui/app/components/send_/send-content/send-to-row/send-to-row.utils.js b/ui/app/components/send_/send-content/send-to-row/send-to-row.utils.js deleted file mode 100644 index 6b90a9f09..000000000 --- a/ui/app/components/send_/send-content/send-to-row/send-to-row.utils.js +++ /dev/null @@ -1,19 +0,0 @@ -const { - REQUIRED_ERROR, - INVALID_RECIPIENT_ADDRESS_ERROR, -} = require('../../send.constants') -const { isValidAddress } = require('../../../../util') - -function getToErrorObject (to, toError = null) { - if (!to) { - toError = REQUIRED_ERROR - } else if (!isValidAddress(to) && !toError) { - toError = INVALID_RECIPIENT_ADDRESS_ERROR - } - - return { to: toError } -} - -module.exports = { - getToErrorObject, -} diff --git a/ui/app/components/send_/send-content/send-to-row/tests/send-to-row-component.test.js b/ui/app/components/send_/send-content/send-to-row/tests/send-to-row-component.test.js deleted file mode 100644 index 781371004..000000000 --- a/ui/app/components/send_/send-content/send-to-row/tests/send-to-row-component.test.js +++ /dev/null @@ -1,149 +0,0 @@ -import React from 'react' -import assert from 'assert' -import { shallow } from 'enzyme' -import sinon from 'sinon' -import proxyquire from 'proxyquire' - -const SendToRow = proxyquire('../send-to-row.component.js', { - './send-to-row.utils.js': { - getToErrorObject: (to, toError) => ({ - to: to === false ? null : `mockToErrorObject:${to}${toError}`, - }), - }, -}).default - -import SendRowWrapper from '../../send-row-wrapper/send-row-wrapper.component' -import EnsInput from '../../../../ens-input' - -const propsMethodSpies = { - closeToDropdown: sinon.spy(), - openToDropdown: sinon.spy(), - updateGas: sinon.spy(), - updateSendTo: sinon.spy(), - updateSendToError: sinon.spy(), -} - -sinon.spy(SendToRow.prototype, 'handleToChange') - -describe('SendToRow Component', function () { - let wrapper - let instance - - beforeEach(() => { - wrapper = shallow(<SendToRow - closeToDropdown={propsMethodSpies.closeToDropdown} - inError={false} - network={'mockNetwork'} - openToDropdown={propsMethodSpies.openToDropdown} - to={'mockTo'} - toAccounts={['mockAccount']} - toDropdownOpen={false} - updateGas={propsMethodSpies.updateGas} - updateSendTo={propsMethodSpies.updateSendTo} - updateSendToError={propsMethodSpies.updateSendToError} - />, { context: { t: str => str + '_t' } }) - instance = wrapper.instance() - }) - - afterEach(() => { - propsMethodSpies.closeToDropdown.resetHistory() - propsMethodSpies.openToDropdown.resetHistory() - propsMethodSpies.updateSendTo.resetHistory() - propsMethodSpies.updateSendToError.resetHistory() - SendToRow.prototype.handleToChange.resetHistory() - }) - - describe('handleToChange', () => { - - it('should call updateSendTo', () => { - assert.equal(propsMethodSpies.updateSendTo.callCount, 0) - instance.handleToChange('mockTo2', 'mockNickname') - assert.equal(propsMethodSpies.updateSendTo.callCount, 1) - assert.deepEqual( - propsMethodSpies.updateSendTo.getCall(0).args, - ['mockTo2', 'mockNickname'] - ) - }) - - it('should call updateSendToError', () => { - assert.equal(propsMethodSpies.updateSendToError.callCount, 0) - instance.handleToChange('mockTo2', '', 'mockToError') - assert.equal(propsMethodSpies.updateSendToError.callCount, 1) - assert.deepEqual( - propsMethodSpies.updateSendToError.getCall(0).args, - [{ to: 'mockToErrorObject:mockTo2mockToError' }] - ) - }) - - it('should not call updateGas if there is a to error', () => { - assert.equal(propsMethodSpies.updateGas.callCount, 0) - instance.handleToChange('mockTo2') - assert.equal(propsMethodSpies.updateGas.callCount, 0) - }) - - it('should call updateGas if there is no to error', () => { - assert.equal(propsMethodSpies.updateGas.callCount, 0) - instance.handleToChange(false) - assert.equal(propsMethodSpies.updateGas.callCount, 1) - }) - }) - - describe('render', () => { - it('should render a SendRowWrapper component', () => { - assert.equal(wrapper.find(SendRowWrapper).length, 1) - }) - - it('should pass the correct props to SendRowWrapper', () => { - const { - errorType, - label, - showError, - } = wrapper.find(SendRowWrapper).props() - - assert.equal(errorType, 'to') - - assert.equal(label, 'to_t') - - assert.equal(showError, false) - }) - - it('should render an EnsInput as a child of the SendRowWrapper', () => { - assert(wrapper.find(SendRowWrapper).childAt(0).is(EnsInput)) - }) - - it('should render the EnsInput with the correct props', () => { - const { - accounts, - closeDropdown, - dropdownOpen, - inError, - name, - network, - onChange, - openDropdown, - placeholder, - to, - } = wrapper.find(SendRowWrapper).childAt(0).props() - assert.deepEqual(accounts, ['mockAccount']) - assert.equal(dropdownOpen, false) - assert.equal(inError, false) - assert.equal(name, 'address') - assert.equal(network, 'mockNetwork') - assert.equal(placeholder, 'recipientAddress_t') - assert.equal(to, 'mockTo') - assert.equal(propsMethodSpies.closeToDropdown.callCount, 0) - closeDropdown() - assert.equal(propsMethodSpies.closeToDropdown.callCount, 1) - assert.equal(propsMethodSpies.openToDropdown.callCount, 0) - openDropdown() - assert.equal(propsMethodSpies.openToDropdown.callCount, 1) - assert.equal(SendToRow.prototype.handleToChange.callCount, 0) - onChange({ toAddress: 'mockNewTo', nickname: 'mockNewNickname', toError: 'mockToError' }) - assert.equal(SendToRow.prototype.handleToChange.callCount, 1) - assert.deepEqual( - SendToRow.prototype.handleToChange.getCall(0).args, - ['mockNewTo', 'mockNewNickname', 'mockToError'] - ) - }) - }) -}) diff --git a/ui/app/components/send_/send-content/send-to-row/tests/send-to-row-container.test.js b/ui/app/components/send_/send-content/send-to-row/tests/send-to-row-container.test.js deleted file mode 100644 index 92355c00a..000000000 --- a/ui/app/components/send_/send-content/send-to-row/tests/send-to-row-container.test.js +++ /dev/null @@ -1,113 +0,0 @@ -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}`, - }, - '../../../../actions': actionSpies, - '../../../../ducks/send.duck': 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('mockToErrorObject') - assert(dispatchSpy.calledOnce) - assert(duckActionSpies.updateSendErrors.calledOnce) - assert.equal( - duckActionSpies.updateSendErrors.getCall(0).args[0], - 'mockToErrorObject' - ) - }) - }) - - }) - -}) diff --git a/ui/app/components/send_/send-content/send-to-row/tests/send-to-row-selectors.test.js b/ui/app/components/send_/send-content/send-to-row/tests/send-to-row-selectors.test.js deleted file mode 100644 index 122ad3265..000000000 --- a/ui/app/components/send_/send-content/send-to-row/tests/send-to-row-selectors.test.js +++ /dev/null @@ -1,47 +0,0 @@ -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) - }) - }) - -}) diff --git a/ui/app/components/send_/send-content/send-to-row/tests/send-to-row-utils.test.js b/ui/app/components/send_/send-content/send-to-row/tests/send-to-row-utils.test.js deleted file mode 100644 index 4d2447c32..000000000 --- a/ui/app/components/send_/send-content/send-to-row/tests/send-to-row-utils.test.js +++ /dev/null @@ -1,51 +0,0 @@ -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, - }) - }) - - it('should return the passed error if to is truthy but invalid if to is truthy and valid', () => { - assert.deepEqual(getToErrorObject('invalid #$ 345878', 'someExplicitError'), { - to: 'someExplicitError', - }) - }) - }) - -}) diff --git a/ui/app/components/send_/send-content/tests/send-content-component.test.js b/ui/app/components/send_/send-content/tests/send-content-component.test.js deleted file mode 100644 index d5bb6693c..000000000 --- a/ui/app/components/send_/send-content/tests/send-content-component.test.js +++ /dev/null @@ -1,38 +0,0 @@ -import React from 'react' -import assert from 'assert' -import { shallow } from 'enzyme' -import SendContent from '../send-content.component.js' - -import PageContainerContent from '../../../page-container/page-container-content.component' -import SendAmountRow from '../send-amount-row/send-amount-row.container' -import SendFromRow from '../send-from-row/send-from-row.container' -import SendGasRow from '../send-gas-row/send-gas-row.container' -import SendToRow from '../send-to-row/send-to-row.container' - -describe('SendContent Component', function () { - let wrapper - - beforeEach(() => { - wrapper = shallow(<SendContent />) - }) - - describe('render', () => { - it('should render a PageContainerContent component', () => { - assert.equal(wrapper.find(PageContainerContent).length, 1) - }) - - it('should render a div with a .send-v2__form class as a child of PageContainerContent', () => { - const PageContainerContentChild = wrapper.find(PageContainerContent).children() - PageContainerContentChild.is('div') - PageContainerContentChild.is('.send-v2__form') - }) - - it('should render the correct row components as grandchildren of the PageContainerContent component', () => { - const PageContainerContentChild = wrapper.find(PageContainerContent).children() - assert(PageContainerContentChild.childAt(0).is(SendFromRow)) - assert(PageContainerContentChild.childAt(1).is(SendToRow)) - assert(PageContainerContentChild.childAt(2).is(SendAmountRow)) - assert(PageContainerContentChild.childAt(3).is(SendGasRow)) - }) - }) -}) diff --git a/ui/app/components/send_/send-footer/README.md b/ui/app/components/send_/send-footer/README.md deleted file mode 100644 index e69de29bb..000000000 --- a/ui/app/components/send_/send-footer/README.md +++ /dev/null diff --git a/ui/app/components/send_/send-footer/index.js b/ui/app/components/send_/send-footer/index.js deleted file mode 100644 index 58e91d622..000000000 --- a/ui/app/components/send_/send-footer/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './send-footer.container' diff --git a/ui/app/components/send_/send-footer/send-footer.component.js b/ui/app/components/send_/send-footer/send-footer.component.js deleted file mode 100644 index 6471ae1a3..000000000 --- a/ui/app/components/send_/send-footer/send-footer.component.js +++ /dev/null @@ -1,99 +0,0 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' -import PageContainerFooter from '../../page-container/page-container-footer' -import { CONFIRM_TRANSACTION_ROUTE, DEFAULT_ROUTE } from '../../../routes' - -export default class SendFooter extends Component { - - static propTypes = { - addToAddressBookIfNew: PropTypes.func, - amount: PropTypes.string, - clearSend: PropTypes.func, - disabled: PropTypes.bool, - editingTransactionId: PropTypes.string, - errors: PropTypes.object, - from: PropTypes.object, - gasLimit: PropTypes.string, - gasPrice: PropTypes.string, - gasTotal: PropTypes.string, - history: PropTypes.object, - inError: PropTypes.bool, - selectedToken: PropTypes.object, - sign: PropTypes.func, - to: PropTypes.string, - toAccounts: PropTypes.array, - tokenBalance: PropTypes.string, - unapprovedTxs: PropTypes.object, - update: PropTypes.func, - }; - - onCancel () { - this.props.clearSend() - this.props.history.push(DEFAULT_ROUTE) - } - - onSubmit (event) { - event.preventDefault() - const { - addToAddressBookIfNew, - amount, - editingTransactionId, - from: {address: from}, - gasLimit: gas, - gasPrice, - selectedToken, - sign, - to, - unapprovedTxs, - // updateTx, - update, - toAccounts, - } = this.props - - // Should not be needed because submit should be disabled if there are errors. - // const noErrors = !amountError && toError === null - - // if (!noErrors) { - // return - // } - - // TODO: add nickname functionality - addToAddressBookIfNew(to, toAccounts) - - editingTransactionId - ? update({ - amount, - editingTransactionId, - from, - gas, - gasPrice, - selectedToken, - to, - unapprovedTxs, - }) - : sign({ selectedToken, to, amount, from, gas, gasPrice }) - - this.props.history.push(CONFIRM_TRANSACTION_ROUTE) - } - - formShouldBeDisabled () { - const { inError, selectedToken, tokenBalance, gasTotal, to } = this.props - const missingTokenBalance = selectedToken && !tokenBalance - return inError || !gasTotal || missingTokenBalance || !to - } - - render () { - return ( - <PageContainerFooter - onCancel={() => this.onCancel()} - onSubmit={e => this.onSubmit(e)} - disabled={this.formShouldBeDisabled()} - /> - ) - } - -} - -SendFooter.contextTypes = { - t: PropTypes.func, -} diff --git a/ui/app/components/send_/send-footer/send-footer.container.js b/ui/app/components/send_/send-footer/send-footer.container.js deleted file mode 100644 index 260ff40bc..000000000 --- a/ui/app/components/send_/send-footer/send-footer.container.js +++ /dev/null @@ -1,100 +0,0 @@ -import { connect } from 'react-redux' -import ethUtil from 'ethereumjs-util' -import { - addToAddressBook, - clearSend, - signTokenTx, - signTx, - updateTransaction, -} from '../../../actions' -import SendFooter from './send-footer.component' -import { - getGasLimit, - getGasPrice, - getGasTotal, - getSelectedToken, - getSendAmount, - getSendEditingTransactionId, - getSendFromObject, - getSendTo, - getSendToAccounts, - getTokenBalance, - getUnapprovedTxs, -} from '../send.selectors' -import { - isSendFormInError, -} from './send-footer.selectors' -import { - addressIsNew, - constructTxParams, - constructUpdatedTx, -} from './send-footer.utils' - -export default connect(mapStateToProps, mapDispatchToProps)(SendFooter) - -function mapStateToProps (state) { - return { - amount: getSendAmount(state), - editingTransactionId: getSendEditingTransactionId(state), - from: getSendFromObject(state), - gasLimit: getGasLimit(state), - gasPrice: getGasPrice(state), - gasTotal: getGasTotal(state), - inError: isSendFormInError(state), - selectedToken: getSelectedToken(state), - to: getSendTo(state), - toAccounts: getSendToAccounts(state), - tokenBalance: getTokenBalance(state), - unapprovedTxs: getUnapprovedTxs(state), - } -} - -function mapDispatchToProps (dispatch) { - return { - clearSend: () => dispatch(clearSend()), - sign: ({ selectedToken, to, amount, from, gas, gasPrice }) => { - const txParams = constructTxParams({ - amount, - from, - gas, - gasPrice, - selectedToken, - to, - }) - - selectedToken - ? dispatch(signTokenTx(selectedToken.address, to, amount, txParams)) - : dispatch(signTx(txParams)) - }, - update: ({ - amount, - editingTransactionId, - from, - gas, - gasPrice, - selectedToken, - to, - unapprovedTxs, - }) => { - const editingTx = constructUpdatedTx({ - amount, - editingTransactionId, - from, - gas, - gasPrice, - selectedToken, - to, - unapprovedTxs, - }) - - dispatch(updateTransaction(editingTx)) - }, - addToAddressBookIfNew: (newAddress, toAccounts, nickname = '') => { - const hexPrefixedAddress = ethUtil.addHexPrefix(newAddress) - if (addressIsNew(toAccounts)) { - // TODO: nickname, i.e. addToAddressBook(recipient, nickname) - dispatch(addToAddressBook(hexPrefixedAddress, nickname)) - } - }, - } -} diff --git a/ui/app/components/send_/send-footer/send-footer.scss b/ui/app/components/send_/send-footer/send-footer.scss deleted file mode 100644 index e69de29bb..000000000 --- a/ui/app/components/send_/send-footer/send-footer.scss +++ /dev/null diff --git a/ui/app/components/send_/send-footer/send-footer.selectors.js b/ui/app/components/send_/send-footer/send-footer.selectors.js deleted file mode 100644 index e20addfdc..000000000 --- a/ui/app/components/send_/send-footer/send-footer.selectors.js +++ /dev/null @@ -1,11 +0,0 @@ -const { getSendErrors } = require('../send.selectors') - -const selectors = { - isSendFormInError, -} - -module.exports = selectors - -function isSendFormInError (state) { - return Object.values(getSendErrors(state)).some(n => n) -} diff --git a/ui/app/components/send_/send-footer/send-footer.utils.js b/ui/app/components/send_/send-footer/send-footer.utils.js deleted file mode 100644 index 875e7d948..000000000 --- a/ui/app/components/send_/send-footer/send-footer.utils.js +++ /dev/null @@ -1,81 +0,0 @@ -const ethAbi = require('ethereumjs-abi') -const ethUtil = require('ethereumjs-util') -const { TOKEN_TRANSFER_FUNCTION_SIGNATURE } = require('../send.constants') - -function addHexPrefixToObjectValues (obj) { - return Object.keys(obj).reduce((newObj, key) => { - return { ...newObj, [key]: ethUtil.addHexPrefix(obj[key]) } - }, {}) -} - -function constructTxParams ({ selectedToken, to, amount, from, gas, gasPrice }) { - const txParams = { - from, - value: '0', - gas, - gasPrice, - } - - if (!selectedToken) { - txParams.value = amount - txParams.to = to - } - - const hexPrefixedTxParams = addHexPrefixToObjectValues(txParams) - - return hexPrefixedTxParams -} - -function constructUpdatedTx ({ - amount, - editingTransactionId, - from, - gas, - gasPrice, - selectedToken, - to, - unapprovedTxs, -}) { - const editingTx = { - ...unapprovedTxs[editingTransactionId], - txParams: addHexPrefixToObjectValues({ from, gas, gasPrice }), - } - - if (selectedToken) { - 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) - ).join('') - - Object.assign(editingTx.txParams, addHexPrefixToObjectValues({ - value: '0', - to: selectedToken.address, - data, - })) - } else { - const { data } = unapprovedTxs[editingTransactionId].txParams - - Object.assign(editingTx.txParams, addHexPrefixToObjectValues({ - value: amount, - to, - data, - })) - - if (typeof editingTx.txParams.data === 'undefined') { - delete editingTx.txParams.data - } - } - - return editingTx -} - -function addressIsNew (toAccounts, newAddress) { - return !toAccounts.find(({ address }) => newAddress === address) -} - -module.exports = { - addressIsNew, - constructTxParams, - constructUpdatedTx, - addHexPrefixToObjectValues, -} diff --git a/ui/app/components/send_/send-footer/tests/send-footer-component.test.js b/ui/app/components/send_/send-footer/tests/send-footer-component.test.js deleted file mode 100644 index e071fe54f..000000000 --- a/ui/app/components/send_/send-footer/tests/send-footer-component.test.js +++ /dev/null @@ -1,227 +0,0 @@ -import React from 'react' -import assert from 'assert' -import { shallow } from 'enzyme' -import sinon from 'sinon' -import { CONFIRM_TRANSACTION_ROUTE, DEFAULT_ROUTE } from '../../../../routes' -import SendFooter from '../send-footer.component.js' - -import PageContainerFooter from '../../../page-container/page-container-footer' - -const propsMethodSpies = { - addToAddressBookIfNew: sinon.spy(), - clearSend: sinon.spy(), - sign: sinon.spy(), - update: sinon.spy(), -} -const historySpies = { - push: sinon.spy(), -} -const MOCK_EVENT = { preventDefault: () => {} } - -sinon.spy(SendFooter.prototype, 'onCancel') -sinon.spy(SendFooter.prototype, 'onSubmit') - -describe('SendFooter Component', function () { - let wrapper - - beforeEach(() => { - wrapper = shallow(<SendFooter - addToAddressBookIfNew={propsMethodSpies.addToAddressBookIfNew} - amount={'mockAmount'} - clearSend={propsMethodSpies.clearSend} - disabled={true} - editingTransactionId={'mockEditingTransactionId'} - errors={{}} - from={ { address: 'mockAddress', balance: 'mockBalance' } } - gasLimit={'mockGasLimit'} - gasPrice={'mockGasPrice'} - gasTotal={'mockGasTotal'} - history={historySpies} - inError={false} - selectedToken={{ mockProp: 'mockSelectedTokenProp' }} - sign={propsMethodSpies.sign} - to={'mockTo'} - toAccounts={['mockAccount']} - tokenBalance={'mockTokenBalance'} - unapprovedTxs={['mockTx']} - update={propsMethodSpies.update} - />, { context: { t: str => str } }) - }) - - afterEach(() => { - propsMethodSpies.clearSend.resetHistory() - propsMethodSpies.addToAddressBookIfNew.resetHistory() - propsMethodSpies.clearSend.resetHistory() - propsMethodSpies.sign.resetHistory() - propsMethodSpies.update.resetHistory() - historySpies.push.resetHistory() - SendFooter.prototype.onCancel.resetHistory() - SendFooter.prototype.onSubmit.resetHistory() - }) - - describe('onCancel', () => { - it('should call clearSend', () => { - assert.equal(propsMethodSpies.clearSend.callCount, 0) - wrapper.instance().onCancel() - assert.equal(propsMethodSpies.clearSend.callCount, 1) - }) - - it('should call history.push', () => { - assert.equal(historySpies.push.callCount, 0) - wrapper.instance().onCancel() - assert.equal(historySpies.push.callCount, 1) - assert.equal(historySpies.push.getCall(0).args[0], DEFAULT_ROUTE) - }) - }) - - - 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 to is truthy': { - to: '0xsomevalidAddress', - 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, () => { - wrapper.setProps(obj) - assert.equal(wrapper.instance().formShouldBeDisabled(), obj.expectedResult) - }) - }) - }) - - describe('onSubmit', () => { - it('should call addToAddressBookIfNew with the correct params', () => { - wrapper.instance().onSubmit(MOCK_EVENT) - assert(propsMethodSpies.addToAddressBookIfNew.calledOnce) - assert.deepEqual( - propsMethodSpies.addToAddressBookIfNew.getCall(0).args, - ['mockTo', ['mockAccount']] - ) - }) - - it('should call props.update if editingTransactionId is truthy', () => { - wrapper.instance().onSubmit(MOCK_EVENT) - assert(propsMethodSpies.update.calledOnce) - assert.deepEqual( - propsMethodSpies.update.getCall(0).args[0], - { - amount: 'mockAmount', - editingTransactionId: 'mockEditingTransactionId', - from: 'mockAddress', - gas: 'mockGasLimit', - gasPrice: 'mockGasPrice', - selectedToken: { mockProp: 'mockSelectedTokenProp' }, - to: 'mockTo', - unapprovedTxs: ['mockTx'], - } - ) - }) - - it('should not call props.sign if editingTransactionId is truthy', () => { - assert.equal(propsMethodSpies.sign.callCount, 0) - }) - - it('should call props.sign if editingTransactionId is falsy', () => { - wrapper.setProps({ editingTransactionId: null }) - wrapper.instance().onSubmit(MOCK_EVENT) - assert(propsMethodSpies.sign.calledOnce) - assert.deepEqual( - propsMethodSpies.sign.getCall(0).args[0], - { - amount: 'mockAmount', - from: 'mockAddress', - gas: 'mockGasLimit', - gasPrice: 'mockGasPrice', - selectedToken: { mockProp: 'mockSelectedTokenProp' }, - to: 'mockTo', - } - ) - }) - - it('should not call props.update if editingTransactionId is falsy', () => { - assert.equal(propsMethodSpies.update.callCount, 0) - }) - - it('should call history.push', () => { - wrapper.instance().onSubmit(MOCK_EVENT) - assert.equal(historySpies.push.callCount, 1) - assert.equal(historySpies.push.getCall(0).args[0], CONFIRM_TRANSACTION_ROUTE) - }) - }) - - describe('render', () => { - beforeEach(() => { - sinon.stub(SendFooter.prototype, 'formShouldBeDisabled').returns('formShouldBeDisabledReturn') - wrapper = shallow(<SendFooter - addToAddressBookIfNew={propsMethodSpies.addToAddressBookIfNew} - amount={'mockAmount'} - clearSend={propsMethodSpies.clearSend} - disabled={true} - editingTransactionId={'mockEditingTransactionId'} - errors={{}} - from={ { address: 'mockAddress', balance: 'mockBalance' } } - gasLimit={'mockGasLimit'} - gasPrice={'mockGasPrice'} - gasTotal={'mockGasTotal'} - history={historySpies} - inError={false} - selectedToken={{ mockProp: 'mockSelectedTokenProp' }} - sign={propsMethodSpies.sign} - to={'mockTo'} - toAccounts={['mockAccount']} - tokenBalance={'mockTokenBalance'} - unapprovedTxs={['mockTx']} - update={propsMethodSpies.update} - />, { context: { t: str => str } }) - }) - - afterEach(() => { - SendFooter.prototype.formShouldBeDisabled.restore() - }) - - it('should render a PageContainerFooter component', () => { - assert.equal(wrapper.find(PageContainerFooter).length, 1) - }) - - it('should pass the correct props to PageContainerFooter', () => { - const { - onCancel, - onSubmit, - disabled, - } = wrapper.find(PageContainerFooter).props() - assert.equal(disabled, 'formShouldBeDisabledReturn') - - assert.equal(SendFooter.prototype.onSubmit.callCount, 0) - onSubmit(MOCK_EVENT) - assert.equal(SendFooter.prototype.onSubmit.callCount, 1) - - assert.equal(SendFooter.prototype.onCancel.callCount, 0) - onCancel() - assert.equal(SendFooter.prototype.onCancel.callCount, 1) - }) - }) -}) diff --git a/ui/app/components/send_/send-footer/tests/send-footer-container.test.js b/ui/app/components/send_/send-footer/tests/send-footer-container.test.js deleted file mode 100644 index 39d6a7686..000000000 --- a/ui/app/components/send_/send-footer/tests/send-footer-container.test.js +++ /dev/null @@ -1,191 +0,0 @@ -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'), -} - -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}`, - }, - './send-footer.selectors': { isSendFormInError: (s) => `mockInError:${s}` }, - './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', - selectedToken: 'mockSelectedToken:mockState', - editingTransactionId: 'mockEditingTransactionId:mockState', - from: 'mockFromObject:mockState', - gasLimit: 'mockGasLimit:mockState', - gasPrice: 'mockGasPrice:mockState', - gasTotal: 'mockGasTotal:mockState', - inError: 'mockInError:mockState', - to: 'mockTo:mockState', - toAccounts: 'mockToAccounts:mockState', - tokenBalance: 'mockTokenBalance:mockState', - unapprovedTxs: 'mockUnapprovedTxs: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' ] - ) - }) - }) - - }) - -}) diff --git a/ui/app/components/send_/send-footer/tests/send-footer-selectors.test.js b/ui/app/components/send_/send-footer/tests/send-footer-selectors.test.js deleted file mode 100644 index 8de032f57..000000000 --- a/ui/app/components/send_/send-footer/tests/send-footer-selectors.test.js +++ /dev/null @@ -1,24 +0,0 @@ -import assert from 'assert' -import proxyquire from 'proxyquire' - -const { - isSendFormInError, -} = proxyquire('../send-footer.selectors', { - '../send.selectors': { - getSendErrors: (mockState) => mockState.errors, - }, -}) - -describe('send-footer selectors', () => { - - describe('getTitleKey()', () => { - it('should return true if any of the values of the object returned by getSendErrors are truthy', () => { - assert.equal(isSendFormInError({ errors: { a: 'abc', b: false} }), true) - }) - - it('should return false if all of the values of the object returned by getSendErrors are falsy', () => { - assert.equal(isSendFormInError({ errors: { a: false, b: null} }), false) - }) - }) - -}) diff --git a/ui/app/components/send_/send-footer/tests/send-footer-utils.test.js b/ui/app/components/send_/send-footer/tests/send-footer-utils.test.js deleted file mode 100644 index 2d3135995..000000000 --- a/ui/app/components/send_/send-footer/tests/send-footer-utils.test.js +++ /dev/null @@ -1,210 +0,0 @@ -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, - 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('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`, - }, - }) - }) - }) - -}) diff --git a/ui/app/components/send_/send-header/README.md b/ui/app/components/send_/send-header/README.md deleted file mode 100644 index e69de29bb..000000000 --- a/ui/app/components/send_/send-header/README.md +++ /dev/null diff --git a/ui/app/components/send_/send-header/index.js b/ui/app/components/send_/send-header/index.js deleted file mode 100644 index 0b17f0b7d..000000000 --- a/ui/app/components/send_/send-header/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './send-header.container' diff --git a/ui/app/components/send_/send-header/send-header.component.js b/ui/app/components/send_/send-header/send-header.component.js deleted file mode 100644 index 5f6617fce..000000000 --- a/ui/app/components/send_/send-header/send-header.component.js +++ /dev/null @@ -1,34 +0,0 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' -import PageContainerHeader from '../../page-container/page-container-header' -import { DEFAULT_ROUTE } from '../../../routes' - -export default class SendHeader extends Component { - - static propTypes = { - clearSend: PropTypes.func, - history: PropTypes.object, - titleKey: PropTypes.string, - subtitleParams: PropTypes.array, - }; - - onClose () { - this.props.clearSend() - this.props.history.push(DEFAULT_ROUTE) - } - - render () { - return ( - <PageContainerHeader - onClose={() => this.onClose()} - subtitle={this.context.t(...this.props.subtitleParams)} - title={this.context.t(this.props.titleKey)} - /> - ) - } - -} - -SendHeader.contextTypes = { - t: PropTypes.func, -} diff --git a/ui/app/components/send_/send-header/send-header.container.js b/ui/app/components/send_/send-header/send-header.container.js deleted file mode 100644 index 4bcd0d1b6..000000000 --- a/ui/app/components/send_/send-header/send-header.container.js +++ /dev/null @@ -1,19 +0,0 @@ -import { connect } from 'react-redux' -import { clearSend } from '../../../actions' -import SendHeader from './send-header.component' -import { getSubtitleParams, getTitleKey } from './send-header.selectors' - -export default connect(mapStateToProps, mapDispatchToProps)(SendHeader) - -function mapStateToProps (state) { - return { - titleKey: getTitleKey(state), - subtitleParams: getSubtitleParams(state), - } -} - -function mapDispatchToProps (dispatch) { - return { - clearSend: () => dispatch(clearSend()), - } -} diff --git a/ui/app/components/send_/send-header/send-header.selectors.js b/ui/app/components/send_/send-header/send-header.selectors.js deleted file mode 100644 index d7c9d3766..000000000 --- a/ui/app/components/send_/send-header/send-header.selectors.js +++ /dev/null @@ -1,37 +0,0 @@ -const { - getSelectedToken, - getSendEditingTransactionId, -} = require('../send.selectors.js') - -const selectors = { - getTitleKey, - getSubtitleParams, -} - -module.exports = selectors - -function getTitleKey (state) { - const isEditing = Boolean(getSendEditingTransactionId(state)) - const isToken = Boolean(getSelectedToken(state)) - - if (isEditing) { - return 'edit' - } else if (isToken) { - return 'sendTokens' - } else { - return 'sendETH' - } -} - -function getSubtitleParams (state) { - const isEditing = Boolean(getSendEditingTransactionId(state)) - const token = getSelectedToken(state) - - if (isEditing) { - return [ 'editingTransaction' ] - } else if (token) { - return [ 'onlySendTokensToAccountAddress', [ token.symbol ] ] - } else { - return [ 'onlySendToEtherAddress' ] - } -} diff --git a/ui/app/components/send_/send-header/tests/send-header-component.test.js b/ui/app/components/send_/send-header/tests/send-header-component.test.js deleted file mode 100644 index 930bfa387..000000000 --- a/ui/app/components/send_/send-header/tests/send-header-component.test.js +++ /dev/null @@ -1,70 +0,0 @@ -import React from 'react' -import assert from 'assert' -import { shallow } from 'enzyme' -import sinon from 'sinon' -import { DEFAULT_ROUTE } from '../../../../routes' -import SendHeader from '../send-header.component.js' - -import PageContainerHeader from '../../../page-container/page-container-header' - -const propsMethodSpies = { - clearSend: sinon.spy(), -} -const historySpies = { - push: sinon.spy(), -} - -sinon.spy(SendHeader.prototype, 'onClose') - -describe('SendHeader Component', function () { - let wrapper - - beforeEach(() => { - wrapper = shallow(<SendHeader - clearSend={propsMethodSpies.clearSend} - history={historySpies} - titleKey={'mockTitleKey'} - subtitleParams={[ 'mockSubtitleKey', 'mockVal']} - />, { context: { t: (str1, str2) => str2 ? str1 + str2 : str1 } }) - }) - - afterEach(() => { - propsMethodSpies.clearSend.resetHistory() - historySpies.push.resetHistory() - SendHeader.prototype.onClose.resetHistory() - }) - - describe('onClose', () => { - it('should call clearSend', () => { - assert.equal(propsMethodSpies.clearSend.callCount, 0) - wrapper.instance().onClose() - assert.equal(propsMethodSpies.clearSend.callCount, 1) - }) - - it('should call history.push', () => { - assert.equal(historySpies.push.callCount, 0) - wrapper.instance().onClose() - assert.equal(historySpies.push.callCount, 1) - assert.equal(historySpies.push.getCall(0).args[0], DEFAULT_ROUTE) - }) - }) - - describe('render', () => { - it('should render a PageContainerHeader compenent', () => { - assert.equal(wrapper.find(PageContainerHeader).length, 1) - }) - - it('should pass the correct props to PageContainerHeader', () => { - const { - onClose, - subtitle, - title, - } = wrapper.find(PageContainerHeader).props() - assert.equal(subtitle, 'mockSubtitleKeymockVal') - assert.equal(title, 'mockTitleKey') - assert.equal(SendHeader.prototype.onClose.callCount, 0) - onClose() - assert.equal(SendHeader.prototype.onClose.callCount, 1) - }) - }) -}) diff --git a/ui/app/components/send_/send-header/tests/send-header-container.test.js b/ui/app/components/send_/send-header/tests/send-header-container.test.js deleted file mode 100644 index 41a7e8a89..000000000 --- a/ui/app/components/send_/send-header/tests/send-header-container.test.js +++ /dev/null @@ -1,59 +0,0 @@ -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, - './send-header.selectors': { - getTitleKey: (s) => `mockTitleKey:${s}`, - getSubtitleParams: (s) => `mockSubtitleParams:${s}`, - }, -}) - -describe('send-header container', () => { - - describe('mapStateToProps()', () => { - - it('should map the correct properties to props', () => { - assert.deepEqual(mapStateToProps('mockState'), { - titleKey: 'mockTitleKey:mockState', - subtitleParams: 'mockSubtitleParams: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) - }) - }) - - }) - -}) diff --git a/ui/app/components/send_/send-header/tests/send-header-selectors.test.js b/ui/app/components/send_/send-header/tests/send-header-selectors.test.js deleted file mode 100644 index e0c6a3ab3..000000000 --- a/ui/app/components/send_/send-header/tests/send-header-selectors.test.js +++ /dev/null @@ -1,47 +0,0 @@ -import assert from 'assert' -import proxyquire from 'proxyquire' - -const { - getTitleKey, - getSubtitleParams, -} = proxyquire('../send-header.selectors', { - '../send.selectors': { - getSelectedToken: (mockState) => mockState.t, - getSendEditingTransactionId: (mockState) => mockState.e, - }, -}) - -describe('send-header selectors', () => { - - describe('getTitleKey()', () => { - it('should return the correct key when getSendEditingTransactionId is truthy', () => { - assert.equal(getTitleKey({ e: 1, t: true }), 'edit') - }) - - it('should return the correct key when getSendEditingTransactionId is falsy and getSelectedToken is truthy', () => { - assert.equal(getTitleKey({ e: null, t: 'abc' }), 'sendTokens') - }) - - it('should return the correct key when getSendEditingTransactionId is falsy and getSelectedToken is falsy', () => { - assert.equal(getTitleKey({ e: null }), 'sendETH') - }) - }) - - describe('getSubtitleParams()', () => { - it('should return the correct params when getSendEditingTransactionId is truthy', () => { - assert.deepEqual(getSubtitleParams({ e: 1, t: true }), [ 'editingTransaction' ]) - }) - - it('should return the correct params when getSendEditingTransactionId is falsy and getSelectedToken is truthy', () => { - assert.deepEqual( - getSubtitleParams({ e: null, t: { symbol: 'ABC' } }), - [ 'onlySendTokensToAccountAddress', [ 'ABC' ] ] - ) - }) - - it('should return the correct params when getSendEditingTransactionId is falsy and getSelectedToken is falsy', () => { - assert.deepEqual(getSubtitleParams({ e: null }), [ 'onlySendToEtherAddress' ]) - }) - }) - -}) diff --git a/ui/app/components/send_/send.component.js b/ui/app/components/send_/send.component.js deleted file mode 100644 index 219b362f2..000000000 --- a/ui/app/components/send_/send.component.js +++ /dev/null @@ -1,162 +0,0 @@ -import React from 'react' -import PropTypes from 'prop-types' -import PersistentForm from '../../../lib/persistent-form' -import { - getAmountErrorObject, - getToAddressForGasUpdate, - doesAmountErrorRequireUpdate, -} from './send.utils' - -import SendHeader from './send-header/' -import SendContent from './send-content/' -import SendFooter from './send-footer/' - -export default class SendTransactionScreen extends PersistentForm { - - static propTypes = { - amount: PropTypes.string, - amountConversionRate: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.number, - ]), - blockGasLimit: PropTypes.string, - conversionRate: PropTypes.number, - editingTransactionId: PropTypes.string, - from: PropTypes.object, - gasLimit: PropTypes.string, - gasPrice: PropTypes.string, - gasTotal: PropTypes.string, - history: PropTypes.object, - network: PropTypes.string, - primaryCurrency: PropTypes.string, - recentBlocks: PropTypes.array, - selectedAddress: PropTypes.string, - selectedToken: PropTypes.object, - tokenBalance: PropTypes.string, - tokenContract: PropTypes.object, - updateAndSetGasTotal: PropTypes.func, - updateSendErrors: PropTypes.func, - updateSendTokenBalance: PropTypes.func, - }; - - updateGas ({ to: updatedToAddress, amount: value } = {}) { - const { - amount, - blockGasLimit, - editingTransactionId, - gasLimit, - gasPrice, - recentBlocks, - selectedAddress, - selectedToken = {}, - to: currentToAddress, - updateAndSetGasTotal, - } = this.props - - updateAndSetGasTotal({ - blockGasLimit, - editingTransactionId, - gasLimit, - gasPrice, - recentBlocks, - selectedAddress, - selectedToken, - to: getToAddressForGasUpdate(updatedToAddress, currentToAddress), - value: value || amount, - }) - } - - componentDidUpdate (prevProps) { - const { - amount, - amountConversionRate, - conversionRate, - from: { address, balance }, - gasTotal, - network, - primaryCurrency, - selectedToken, - tokenBalance, - updateSendErrors, - updateSendTokenBalance, - tokenContract, - } = this.props - - const { - from: { balance: prevBalance }, - gasTotal: prevGasTotal, - tokenBalance: prevTokenBalance, - network: prevNetwork, - } = prevProps - - const uninitialized = [prevBalance, prevGasTotal].every(n => n === null) - - const amountErrorRequiresUpdate = doesAmountErrorRequireUpdate({ - balance, - gasTotal, - prevBalance, - prevGasTotal, - prevTokenBalance, - selectedToken, - tokenBalance, - }) - - if (amountErrorRequiresUpdate) { - const amountErrorObject = getAmountErrorObject({ - amount, - amountConversionRate, - balance, - conversionRate, - gasTotal, - primaryCurrency, - selectedToken, - tokenBalance, - }) - updateSendErrors(amountErrorObject) - } - - if (!uninitialized) { - - if (network !== prevNetwork && network !== 'loading') { - updateSendTokenBalance({ - selectedToken, - tokenContract, - address, - }) - this.updateGas() - } - } - } - - componentWillMount () { - const { - from: { address }, - selectedToken, - tokenContract, - updateSendTokenBalance, - } = this.props - updateSendTokenBalance({ - selectedToken, - tokenContract, - address, - }) - this.updateGas() - } - - render () { - const { history } = this.props - - return ( - <div className="page-container"> - <SendHeader history={history}/> - <SendContent updateGas={(updateData) => this.updateGas(updateData)}/> - <SendFooter history={history}/> - </div> - ) - } - -} - -SendTransactionScreen.contextTypes = { - t: PropTypes.func, -} diff --git a/ui/app/components/send_/send.constants.js b/ui/app/components/send_/send.constants.js deleted file mode 100644 index 8acdf0641..000000000 --- a/ui/app/components/send_/send.constants.js +++ /dev/null @@ -1,57 +0,0 @@ -const ethUtil = require('ethereumjs-util') -const { conversionUtil, multiplyCurrencies } = require('../../conversion-util') - -const MIN_GAS_PRICE_DEC = '0' -const MIN_GAS_PRICE_HEX = (parseInt(MIN_GAS_PRICE_DEC)).toString(16) -const MIN_GAS_LIMIT_DEC = '21000' -const MIN_GAS_LIMIT_HEX = (parseInt(MIN_GAS_LIMIT_DEC)).toString(16) - -const MIN_GAS_PRICE_GWEI = ethUtil.addHexPrefix(conversionUtil(MIN_GAS_PRICE_HEX, { - fromDenomination: 'WEI', - toDenomination: 'GWEI', - fromNumericBase: 'hex', - toNumericBase: 'hex', - numberOfDecimals: 1, -})) - -const MIN_GAS_TOTAL = multiplyCurrencies(MIN_GAS_LIMIT_HEX, MIN_GAS_PRICE_HEX, { - toNumericBase: 'hex', - multiplicandBase: 16, - multiplierBase: 16, -}) - -const TOKEN_TRANSFER_FUNCTION_SIGNATURE = '0xa9059cbb' - -const INSUFFICIENT_FUNDS_ERROR = 'insufficientFunds' -const INSUFFICIENT_TOKENS_ERROR = 'insufficientTokens' -const NEGATIVE_ETH_ERROR = 'negativeETH' -const INVALID_RECIPIENT_ADDRESS_ERROR = 'invalidAddressRecipient' -const REQUIRED_ERROR = 'required' - -const ONE_GWEI_IN_WEI_HEX = ethUtil.addHexPrefix(conversionUtil('0x1', { - fromDenomination: 'GWEI', - toDenomination: 'WEI', - fromNumericBase: 'hex', - toNumericBase: 'hex', -})) - -const SIMPLE_GAS_COST = '0x5208' // Hex for 21000, cost of a simple send. -const BASE_TOKEN_GAS_COST = '0x186a0' // Hex for 100000, a base estimate for token transfers. - -module.exports = { - INSUFFICIENT_FUNDS_ERROR, - INSUFFICIENT_TOKENS_ERROR, - INVALID_RECIPIENT_ADDRESS_ERROR, - MIN_GAS_LIMIT_DEC, - MIN_GAS_LIMIT_HEX, - MIN_GAS_PRICE_DEC, - MIN_GAS_PRICE_GWEI, - MIN_GAS_PRICE_HEX, - MIN_GAS_TOTAL, - NEGATIVE_ETH_ERROR, - ONE_GWEI_IN_WEI_HEX, - REQUIRED_ERROR, - SIMPLE_GAS_COST, - TOKEN_TRANSFER_FUNCTION_SIGNATURE, - BASE_TOKEN_GAS_COST, -} diff --git a/ui/app/components/send_/send.container.js b/ui/app/components/send_/send.container.js deleted file mode 100644 index 185653c5f..000000000 --- a/ui/app/components/send_/send.container.js +++ /dev/null @@ -1,91 +0,0 @@ -import { connect } from 'react-redux' -import SendEther from './send.component' -import { withRouter } from 'react-router-dom' -import { compose } from 'recompose' -import { - getAmountConversionRate, - getBlockGasLimit, - getConversionRate, - getCurrentNetwork, - getGasLimit, - getGasPrice, - getGasTotal, - getPrimaryCurrency, - getRecentBlocks, - getSelectedAddress, - getSelectedToken, - getSelectedTokenContract, - getSelectedTokenToFiatRate, - getSendAmount, - getSendEditingTransactionId, - getSendFromObject, - getSendTo, - getTokenBalance, -} from './send.selectors' -import { - updateSendTokenBalance, - updateGasData, - setGasTotal, -} from '../../actions' -import { - updateSendErrors, -} from '../../ducks/send.duck' -import { - calcGasTotal, -} from './send.utils.js' - -module.exports = compose( - withRouter, - connect(mapStateToProps, mapDispatchToProps) -)(SendEther) - -function mapStateToProps (state) { - return { - amount: getSendAmount(state), - amountConversionRate: getAmountConversionRate(state), - blockGasLimit: getBlockGasLimit(state), - conversionRate: getConversionRate(state), - editingTransactionId: getSendEditingTransactionId(state), - from: getSendFromObject(state), - gasLimit: getGasLimit(state), - gasPrice: getGasPrice(state), - gasTotal: getGasTotal(state), - network: getCurrentNetwork(state), - primaryCurrency: getPrimaryCurrency(state), - recentBlocks: getRecentBlocks(state), - selectedAddress: getSelectedAddress(state), - selectedToken: getSelectedToken(state), - to: getSendTo(state), - tokenBalance: getTokenBalance(state), - tokenContract: getSelectedTokenContract(state), - tokenToFiatRate: getSelectedTokenToFiatRate(state), - } -} - -function mapDispatchToProps (dispatch) { - return { - updateAndSetGasTotal: ({ - blockGasLimit, - editingTransactionId, - gasLimit, - gasPrice, - recentBlocks, - selectedAddress, - selectedToken, - to, - value, - }) => { - !editingTransactionId - ? dispatch(updateGasData({ recentBlocks, selectedAddress, selectedToken, blockGasLimit, to, value })) - : dispatch(setGasTotal(calcGasTotal(gasLimit, gasPrice))) - }, - updateSendTokenBalance: ({ selectedToken, tokenContract, address }) => { - dispatch(updateSendTokenBalance({ - selectedToken, - tokenContract, - address, - })) - }, - updateSendErrors: newError => dispatch(updateSendErrors(newError)), - } -} diff --git a/ui/app/components/send_/send.scss b/ui/app/components/send_/send.scss deleted file mode 100644 index e69de29bb..000000000 --- a/ui/app/components/send_/send.scss +++ /dev/null diff --git a/ui/app/components/send_/send.selectors.js b/ui/app/components/send_/send.selectors.js deleted file mode 100644 index f910f7caf..000000000 --- a/ui/app/components/send_/send.selectors.js +++ /dev/null @@ -1,279 +0,0 @@ -const { valuesFor } = require('../../util') -const abi = require('human-standard-token-abi') -const { - multiplyCurrencies, -} = require('../../conversion-util') -const { - estimateGasPriceFromRecentBlocks, -} = require('./send.utils') - -const selectors = { - accountsWithSendEtherInfoSelector, - // autoAddToBetaUI, - getAddressBook, - getAmountConversionRate, - getBlockGasLimit, - getConversionRate, - getCurrentAccountWithSendEtherInfo, - getCurrentCurrency, - getCurrentNetwork, - getCurrentViewContext, - getForceGasMin, - getGasLimit, - getGasPrice, - getGasPriceFromRecentBlocks, - getGasTotal, - getPrimaryCurrency, - getRecentBlocks, - getSelectedAccount, - getSelectedAddress, - getSelectedIdentity, - getSelectedToken, - getSelectedTokenContract, - getSelectedTokenExchangeRate, - getSelectedTokenToFiatRate, - getSendAmount, - getSendEditingTransactionId, - getSendErrors, - getSendFrom, - getSendFromBalance, - getSendFromObject, - getSendMaxModeState, - getSendTo, - getSendToAccounts, - getTokenBalance, - getTokenExchangeRate, - getUnapprovedTxs, - transactionsSelector, -} - -module.exports = selectors - -function accountsWithSendEtherInfoSelector (state) { - const { - accounts, - identities, - } = state.metamask - - const accountsWithSendEtherInfo = Object.entries(accounts).map(([key, account]) => { - return Object.assign({}, account, identities[key]) - }) - - return accountsWithSendEtherInfo -} - -// 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 userPassesThreshold = (numberOfTransactions > autoAddTransactionThreshold) && -// (numberOfAccounts > autoAddAccountsThreshold) && -// (numberOfTokensAdded > autoAddTokensThreshold) -// const userIsNotInBeta = !state.metamask.featureFlags.betaUI - -// return userIsNotInBeta && userPassesThreshold -// } - -function getAddressBook (state) { - return state.metamask.addressBook -} - -function getAmountConversionRate (state) { - return getSelectedToken(state) - ? getSelectedTokenToFiatRate(state) - : getConversionRate(state) -} - -function getBlockGasLimit (state) { - return state.metamask.currentBlockGasLimit -} - -function getConversionRate (state) { - return state.metamask.conversionRate -} - -function getCurrentAccountWithSendEtherInfo (state) { - const currentAddress = getSelectedAddress(state) - const accounts = accountsWithSendEtherInfoSelector(state) - - return accounts.find(({ address }) => address === currentAddress) -} - -function getCurrentCurrency (state) { - return state.metamask.currentCurrency -} - -function getCurrentNetwork (state) { - return state.metamask.network -} - -function getCurrentViewContext (state) { - const { currentView = {} } = state.appState - return currentView.context -} - -function getForceGasMin (state) { - return state.metamask.send.forceGasMin -} - -function getGasLimit (state) { - return state.metamask.send.gasLimit -} - -function getGasPrice (state) { - return state.metamask.send.gasPrice -} - -function getGasPriceFromRecentBlocks (state) { - return estimateGasPriceFromRecentBlocks(state.metamask.recentBlocks) -} - -function getGasTotal (state) { - return state.metamask.send.gasTotal -} - -function getPrimaryCurrency (state) { - const selectedToken = getSelectedToken(state) - return selectedToken && selectedToken.symbol -} - -function getRecentBlocks (state) { - return state.metamask.recentBlocks -} - -function getSelectedAccount (state) { - const accounts = state.metamask.accounts - const selectedAddress = getSelectedAddress(state) - - return accounts[selectedAddress] -} - -function getSelectedAddress (state) { - const selectedAddress = state.metamask.selectedAddress || Object.keys(state.metamask.accounts)[0] - - return selectedAddress -} - -function getSelectedIdentity (state) { - const selectedAddress = getSelectedAddress(state) - const identities = state.metamask.identities - - return identities[selectedAddress] -} - -function getSelectedToken (state) { - const tokens = state.metamask.tokens || [] - const selectedTokenAddress = state.metamask.selectedTokenAddress - const selectedToken = tokens.filter(({ address }) => address === selectedTokenAddress)[0] - const sendToken = state.metamask.send.token - - return selectedToken || sendToken || null -} - -function getSelectedTokenContract (state) { - const selectedToken = getSelectedToken(state) - - return selectedToken - ? global.eth.contract(abi).at(selectedToken.address) - : null -} - -function getSelectedTokenExchangeRate (state) { - const tokenExchangeRates = state.metamask.tokenExchangeRates - const selectedToken = getSelectedToken(state) || {} - const { symbol = '' } = selectedToken - const pair = `${symbol.toLowerCase()}_eth` - const { rate: tokenExchangeRate = 0 } = tokenExchangeRates && tokenExchangeRates[pair] || {} - - return tokenExchangeRate -} - -function getSelectedTokenToFiatRate (state) { - const selectedTokenExchangeRate = getSelectedTokenExchangeRate(state) - const conversionRate = getConversionRate(state) - - const tokenToFiatRate = multiplyCurrencies( - conversionRate, - selectedTokenExchangeRate, - { toNumericBase: 'dec' } - ) - - return tokenToFiatRate -} - -function getSendAmount (state) { - return state.metamask.send.amount -} - -function getSendEditingTransactionId (state) { - return state.metamask.send.editingTransactionId -} - -function getSendErrors (state) { - return state.send.errors -} - -function getSendFrom (state) { - return state.metamask.send.from -} - -function getSendFromBalance (state) { - const from = getSendFrom(state) || getSelectedAccount(state) - return from.balance -} - -function getSendFromObject (state) { - return getSendFrom(state) || getCurrentAccountWithSendEtherInfo(state) -} - -function getSendMaxModeState (state) { - return state.metamask.send.maxModeOn -} - -function getSendTo (state) { - return state.metamask.send.to -} - -function getSendToAccounts (state) { - const fromAccounts = accountsWithSendEtherInfoSelector(state) - const addressBookAccounts = getAddressBook(state) - const allAccounts = [...fromAccounts, ...addressBookAccounts] - // TODO: figure out exactly what the below returns and put a descriptive variable name on it - return Object.entries(allAccounts).map(([key, account]) => account) -} - -function getTokenBalance (state) { - return state.metamask.send.tokenBalance -} - -function getTokenExchangeRate (state, tokenSymbol) { - const pair = `${tokenSymbol.toLowerCase()}_eth` - const tokenExchangeRates = state.metamask.tokenExchangeRates - const { rate: tokenExchangeRate = 0 } = tokenExchangeRates[pair] || {} - - return tokenExchangeRate -} - -function getUnapprovedTxs (state) { - return state.metamask.unapprovedTxs -} - -function transactionsSelector (state) { - const { network, selectedTokenAddress } = state.metamask - const unapprovedMsgs = valuesFor(state.metamask.unapprovedMsgs) - const shapeShiftTxList = (network === '1') ? state.metamask.shapeShiftTxList : undefined - const transactions = state.metamask.selectedAddressTxList || [] - const txsToRender = !shapeShiftTxList ? transactions.concat(unapprovedMsgs) : transactions.concat(unapprovedMsgs, shapeShiftTxList) - - return selectedTokenAddress - ? txsToRender - .filter(({ txParams }) => txParams && txParams.to === selectedTokenAddress) - .sort((a, b) => b.time - a.time) - : txsToRender - .sort((a, b) => b.time - a.time) -} diff --git a/ui/app/components/send_/send.utils.js b/ui/app/components/send_/send.utils.js deleted file mode 100644 index 34275248f..000000000 --- a/ui/app/components/send_/send.utils.js +++ /dev/null @@ -1,283 +0,0 @@ -const { - addCurrencies, - conversionUtil, - conversionGTE, - multiplyCurrencies, - conversionGreaterThan, - conversionLessThan, -} = require('../../conversion-util') -const { - calcTokenAmount, -} = require('../../token-util') -const { - BASE_TOKEN_GAS_COST, - INSUFFICIENT_FUNDS_ERROR, - INSUFFICIENT_TOKENS_ERROR, - NEGATIVE_ETH_ERROR, - ONE_GWEI_IN_WEI_HEX, - SIMPLE_GAS_COST, - TOKEN_TRANSFER_FUNCTION_SIGNATURE, -} = require('./send.constants') -const abi = require('ethereumjs-abi') -const ethUtil = require('ethereumjs-util') - -module.exports = { - addGasBuffer, - calcGasTotal, - calcTokenBalance, - doesAmountErrorRequireUpdate, - estimateGas, - estimateGasPriceFromRecentBlocks, - generateTokenTransferData, - getAmountErrorObject, - getToAddressForGasUpdate, - isBalanceSufficient, - isTokenBalanceSufficient, - removeLeadingZeroes, -} - -function calcGasTotal (gasLimit, gasPrice) { - return multiplyCurrencies(gasLimit, gasPrice, { - toNumericBase: 'hex', - multiplicandBase: 16, - multiplierBase: 16, - }) -} - -function isBalanceSufficient ({ - amount = '0x0', - amountConversionRate = 0, - balance, - conversionRate, - gasTotal = '0x0', - primaryCurrency, -}) { - const totalAmount = addCurrencies(amount, gasTotal, { - aBase: 16, - bBase: 16, - toNumericBase: 'hex', - }) - - const balanceIsSufficient = conversionGTE( - { - value: balance, - fromNumericBase: 'hex', - fromCurrency: primaryCurrency, - conversionRate, - }, - { - value: totalAmount, - fromNumericBase: 'hex', - conversionRate: Number(amountConversionRate) || conversionRate, - fromCurrency: primaryCurrency, - }, - ) - - return balanceIsSufficient -} - -function isTokenBalanceSufficient ({ - amount = '0x0', - tokenBalance, - decimals, -}) { - const amountInDec = conversionUtil(amount, { - fromNumericBase: 'hex', - }) - - const tokenBalanceIsSufficient = conversionGTE( - { - value: tokenBalance, - fromNumericBase: 'dec', - }, - { - value: calcTokenAmount(amountInDec, decimals), - fromNumericBase: 'dec', - }, - ) - - return tokenBalanceIsSufficient -} - -function getAmountErrorObject ({ - amount, - amountConversionRate, - balance, - conversionRate, - gasTotal, - primaryCurrency, - selectedToken, - tokenBalance, -}) { - let insufficientFunds = false - if (gasTotal && conversionRate) { - insufficientFunds = !isBalanceSufficient({ - amount: selectedToken ? '0x0' : amount, - amountConversionRate, - balance, - conversionRate, - gasTotal, - primaryCurrency, - }) - } - - let inSufficientTokens = false - if (selectedToken && tokenBalance !== null) { - const { decimals } = selectedToken - inSufficientTokens = !isTokenBalanceSufficient({ - tokenBalance, - amount, - decimals, - }) - } - - const amountLessThanZero = conversionGreaterThan( - { value: 0, fromNumericBase: 'dec' }, - { value: amount, fromNumericBase: 'hex' }, - ) - - let amountError = null - - if (insufficientFunds) { - amountError = INSUFFICIENT_FUNDS_ERROR - } else if (inSufficientTokens) { - amountError = INSUFFICIENT_TOKENS_ERROR - } else if (amountLessThanZero) { - amountError = NEGATIVE_ETH_ERROR - } - - return { amount: amountError } -} - -function calcTokenBalance ({ selectedToken, usersToken }) { - const { decimals } = selectedToken || {} - return calcTokenAmount(usersToken.balance.toString(), decimals) + '' -} - -function doesAmountErrorRequireUpdate ({ - balance, - gasTotal, - prevBalance, - prevGasTotal, - prevTokenBalance, - selectedToken, - tokenBalance, -}) { - const balanceHasChanged = balance !== prevBalance - const gasTotalHasChange = gasTotal !== prevGasTotal - const tokenBalanceHasChanged = selectedToken && tokenBalance !== prevTokenBalance - const amountErrorRequiresUpdate = balanceHasChanged || gasTotalHasChange || tokenBalanceHasChanged - - return amountErrorRequiresUpdate -} - -async function estimateGas ({ selectedAddress, selectedToken, blockGasLimit, to, value, gasPrice, estimateGasMethod }) { - const paramsForGasEstimate = { from: selectedAddress, value, gasPrice } - - if (selectedToken) { - paramsForGasEstimate.value = '0x0' - paramsForGasEstimate.data = generateTokenTransferData({ toAddress: to, amount: value, selectedToken }) - } - - // if recipient has no code, gas is 21k max: - if (!selectedToken) { - const code = Boolean(to) && await global.eth.getCode(to) - if (!code || code === '0x') { - return SIMPLE_GAS_COST - } - } else if (selectedToken && !to) { - return BASE_TOKEN_GAS_COST - } - - paramsForGasEstimate.to = selectedToken ? selectedToken.address : to - - // if not, fall back to block gasLimit - paramsForGasEstimate.gas = ethUtil.addHexPrefix(multiplyCurrencies(blockGasLimit, 0.95, { - multiplicandBase: 16, - multiplierBase: 10, - roundDown: '0', - toNumericBase: 'hex', - })) - // run tx - return new Promise((resolve, reject) => { - return estimateGasMethod(paramsForGasEstimate, (err, estimatedGas) => { - if (err) { - const simulationFailed = ( - err.message.includes('Transaction execution error.') || - err.message.includes('gas required exceeds allowance or always failing transaction') - ) - if (simulationFailed) { - const estimateWithBuffer = addGasBuffer(paramsForGasEstimate.gas, blockGasLimit, 1.5) - return resolve(ethUtil.addHexPrefix(estimateWithBuffer)) - } else { - return reject(err) - } - } - const estimateWithBuffer = addGasBuffer(estimatedGas.toString(16), blockGasLimit, 1.5) - return resolve(ethUtil.addHexPrefix(estimateWithBuffer)) - }) - }) -} - -function addGasBuffer (initialGasLimitHex, blockGasLimitHex, bufferMultiplier = 1.5) { - const upperGasLimit = multiplyCurrencies(blockGasLimitHex, 0.9, { - toNumericBase: 'hex', - multiplicandBase: 16, - multiplierBase: 10, - numberOfDecimals: '0', - }) - const bufferedGasLimit = multiplyCurrencies(initialGasLimitHex, bufferMultiplier, { - toNumericBase: 'hex', - multiplicandBase: 16, - multiplierBase: 10, - numberOfDecimals: '0', - }) - - // if initialGasLimit is above blockGasLimit, dont modify it - if (conversionGreaterThan( - { value: initialGasLimitHex, fromNumericBase: 'hex' }, - { value: upperGasLimit, fromNumericBase: 'hex' }, - )) return initialGasLimitHex - // if bufferedGasLimit is below blockGasLimit, use bufferedGasLimit - if (conversionLessThan( - { value: bufferedGasLimit, fromNumericBase: 'hex' }, - { value: upperGasLimit, fromNumericBase: 'hex' }, - )) return bufferedGasLimit - // otherwise use blockGasLimit - return upperGasLimit -} - -function generateTokenTransferData ({ toAddress = '0x0', amount = '0x0', selectedToken }) { - if (!selectedToken) return - return TOKEN_TRANSFER_FUNCTION_SIGNATURE + Array.prototype.map.call( - abi.rawEncode(['address', 'uint256'], [toAddress, ethUtil.addHexPrefix(amount)]), - x => ('00' + x.toString(16)).slice(-2) - ).join('') -} - -function estimateGasPriceFromRecentBlocks (recentBlocks) { - // Return 1 gwei if no blocks have been observed: - if (!recentBlocks || recentBlocks.length === 0) { - return ONE_GWEI_IN_WEI_HEX - } - - const lowestPrices = recentBlocks.map((block) => { - if (!block.gasPrices || block.gasPrices.length < 1) { - return ONE_GWEI_IN_WEI_HEX - } - return block.gasPrices.reduce((currentLowest, next) => { - return parseInt(next, 16) < parseInt(currentLowest, 16) ? next : currentLowest - }) - }) - .sort((a, b) => parseInt(a, 16) > parseInt(b, 16) ? 1 : -1) - - return lowestPrices[Math.floor(lowestPrices.length / 2)] -} - -function getToAddressForGasUpdate (...addresses) { - return [...addresses, ''].find(str => str !== undefined && str !== null).toLowerCase() -} - -function removeLeadingZeroes (str) { - return str.replace(/^0*(?=\d)/, '') -} diff --git a/ui/app/components/send_/send.utils.test.js b/ui/app/components/send_/send.utils.test.js deleted file mode 100644 index 36f3a5c10..000000000 --- a/ui/app/components/send_/send.utils.test.js +++ /dev/null @@ -1,30 +0,0 @@ -import assert from 'assert' -import { removeLeadingZeroes } from './send.utils' - - -describe('send utils', () => { - describe('removeLeadingZeroes()', () => { - it('should remove leading zeroes from int when user types', () => { - assert.equal(removeLeadingZeroes('0'), '0') - assert.equal(removeLeadingZeroes('1'), '1') - assert.equal(removeLeadingZeroes('00'), '0') - assert.equal(removeLeadingZeroes('01'), '1') - }) - - it('should remove leading zeroes from int when user copy/paste', () => { - assert.equal(removeLeadingZeroes('001'), '1') - }) - - it('should remove leading zeroes from float when user types', () => { - assert.equal(removeLeadingZeroes('0.'), '0.') - assert.equal(removeLeadingZeroes('0.0'), '0.0') - assert.equal(removeLeadingZeroes('0.00'), '0.00') - assert.equal(removeLeadingZeroes('0.001'), '0.001') - assert.equal(removeLeadingZeroes('0.10'), '0.10') - }) - - it('should remove leading zeroes from float when user copy/paste', () => { - assert.equal(removeLeadingZeroes('00.1'), '0.1') - }) - }) -}) diff --git a/ui/app/components/send_/tests/send-component.test.js b/ui/app/components/send_/tests/send-component.test.js deleted file mode 100644 index 4ba9b226d..000000000 --- a/ui/app/components/send_/tests/send-component.test.js +++ /dev/null @@ -1,261 +0,0 @@ -import React from 'react' -import assert from 'assert' -import proxyquire from 'proxyquire' -import { shallow } from 'enzyme' -import sinon from 'sinon' - -import SendHeader from '../send-header/send-header.container' -import SendContent from '../send-content/send-content.component' -import SendFooter from '../send-footer/send-footer.container' - -const propsMethodSpies = { - updateAndSetGasTotal: sinon.spy(), - updateSendErrors: sinon.spy(), - updateSendTokenBalance: sinon.spy(), -} -const utilsMethodStubs = { - getAmountErrorObject: sinon.stub().returns({ amount: 'mockAmountError' }), - doesAmountErrorRequireUpdate: sinon.stub().callsFake(obj => obj.balance !== obj.prevBalance), -} - -const SendTransactionScreen = proxyquire('../send.component.js', { - './send.utils': utilsMethodStubs, -}).default - -sinon.spy(SendTransactionScreen.prototype, 'componentDidMount') -sinon.spy(SendTransactionScreen.prototype, 'updateGas') - -describe('Send Component', function () { - let wrapper - - beforeEach(() => { - wrapper = shallow(<SendTransactionScreen - amount={'mockAmount'} - amountConversionRate={'mockAmountConversionRate'} - blockGasLimit={'mockBlockGasLimit'} - conversionRate={10} - editingTransactionId={'mockEditingTransactionId'} - from={ { address: 'mockAddress', balance: 'mockBalance' } } - gasLimit={'mockGasLimit'} - gasPrice={'mockGasPrice'} - gasTotal={'mockGasTotal'} - history={{ mockProp: 'history-abc'}} - network={'3'} - primaryCurrency={'mockPrimaryCurrency'} - recentBlocks={['mockBlock']} - selectedAddress={'mockSelectedAddress'} - selectedToken={'mockSelectedToken'} - tokenBalance={'mockTokenBalance'} - tokenContract={'mockTokenContract'} - updateAndSetGasTotal={propsMethodSpies.updateAndSetGasTotal} - updateSendErrors={propsMethodSpies.updateSendErrors} - updateSendTokenBalance={propsMethodSpies.updateSendTokenBalance} - />) - }) - - afterEach(() => { - SendTransactionScreen.prototype.componentDidMount.resetHistory() - SendTransactionScreen.prototype.updateGas.resetHistory() - utilsMethodStubs.doesAmountErrorRequireUpdate.resetHistory() - utilsMethodStubs.getAmountErrorObject.resetHistory() - propsMethodSpies.updateAndSetGasTotal.resetHistory() - propsMethodSpies.updateSendErrors.resetHistory() - propsMethodSpies.updateSendTokenBalance.resetHistory() - }) - - it('should call componentDidMount', () => { - assert(SendTransactionScreen.prototype.componentDidMount.calledOnce) - }) - - describe('componentWillMount', () => { - it('should call this.updateGas', () => { - SendTransactionScreen.prototype.updateGas.resetHistory() - propsMethodSpies.updateSendErrors.resetHistory() - assert.equal(SendTransactionScreen.prototype.updateGas.callCount, 0) - wrapper.instance().componentWillMount() - assert.equal(SendTransactionScreen.prototype.updateGas.callCount, 1) - }) - }) - - describe('componentDidUpdate', () => { - it('should call doesAmountErrorRequireUpdate with the expected params', () => { - utilsMethodStubs.getAmountErrorObject.resetHistory() - wrapper.instance().componentDidUpdate({ - from: { - balance: '', - }, - }) - assert(utilsMethodStubs.doesAmountErrorRequireUpdate.calledOnce) - assert.deepEqual( - utilsMethodStubs.doesAmountErrorRequireUpdate.getCall(0).args[0], - { - balance: 'mockBalance', - gasTotal: 'mockGasTotal', - prevBalance: '', - prevGasTotal: undefined, - prevTokenBalance: undefined, - selectedToken: 'mockSelectedToken', - tokenBalance: 'mockTokenBalance', - } - ) - }) - - it('should not call getAmountErrorObject if doesAmountErrorRequireUpdate returns false', () => { - utilsMethodStubs.getAmountErrorObject.resetHistory() - wrapper.instance().componentDidUpdate({ - from: { - balance: 'mockBalance', - }, - }) - assert.equal(utilsMethodStubs.getAmountErrorObject.callCount, 0) - }) - - it('should call getAmountErrorObject if doesAmountErrorRequireUpdate returns true', () => { - utilsMethodStubs.getAmountErrorObject.resetHistory() - wrapper.instance().componentDidUpdate({ - from: { - balance: 'balanceChanged', - }, - }) - assert.equal(utilsMethodStubs.getAmountErrorObject.callCount, 1) - assert.deepEqual( - utilsMethodStubs.getAmountErrorObject.getCall(0).args[0], - { - amount: 'mockAmount', - amountConversionRate: 'mockAmountConversionRate', - balance: 'mockBalance', - conversionRate: 10, - gasTotal: 'mockGasTotal', - primaryCurrency: 'mockPrimaryCurrency', - selectedToken: 'mockSelectedToken', - tokenBalance: 'mockTokenBalance', - } - ) - }) - - it('should call updateSendErrors with the expected params', () => { - propsMethodSpies.updateSendErrors.resetHistory() - wrapper.instance().componentDidUpdate({ - from: { - balance: 'balanceChanged', - }, - }) - assert.equal(propsMethodSpies.updateSendErrors.callCount, 1) - assert.deepEqual( - propsMethodSpies.updateSendErrors.getCall(0).args[0], - { amount: 'mockAmountError'} - ) - }) - - it('should not call updateSendTokenBalance or this.updateGas if network === prevNetwork', () => { - SendTransactionScreen.prototype.updateGas.resetHistory() - propsMethodSpies.updateSendTokenBalance.resetHistory() - wrapper.instance().componentDidUpdate({ - from: { - balance: 'balanceChanged', - }, - network: '3', - }) - assert.equal(propsMethodSpies.updateSendTokenBalance.callCount, 0) - assert.equal(SendTransactionScreen.prototype.updateGas.callCount, 0) - }) - - it('should not call updateSendTokenBalance or this.updateGas if network === loading', () => { - wrapper.setProps({ network: 'loading' }) - SendTransactionScreen.prototype.updateGas.resetHistory() - propsMethodSpies.updateSendTokenBalance.resetHistory() - wrapper.instance().componentDidUpdate({ - from: { - balance: 'balanceChanged', - }, - network: '3', - }) - assert.equal(propsMethodSpies.updateSendTokenBalance.callCount, 0) - assert.equal(SendTransactionScreen.prototype.updateGas.callCount, 0) - }) - - it('should call updateSendTokenBalance and this.updateGas with the correct params', () => { - SendTransactionScreen.prototype.updateGas.resetHistory() - propsMethodSpies.updateSendTokenBalance.resetHistory() - wrapper.instance().componentDidUpdate({ - from: { - balance: 'balanceChanged', - }, - network: '2', - }) - assert.equal(propsMethodSpies.updateSendTokenBalance.callCount, 1) - assert.deepEqual( - propsMethodSpies.updateSendTokenBalance.getCall(0).args[0], - { - selectedToken: 'mockSelectedToken', - tokenContract: 'mockTokenContract', - address: 'mockAddress', - } - ) - assert.equal(SendTransactionScreen.prototype.updateGas.callCount, 1) - assert.deepEqual( - SendTransactionScreen.prototype.updateGas.getCall(0).args, - [] - ) - }) - }) - - describe('updateGas', () => { - it('should call updateAndSetGasTotal with the correct params if no to prop is passed', () => { - propsMethodSpies.updateAndSetGasTotal.resetHistory() - wrapper.instance().updateGas() - assert.equal(propsMethodSpies.updateAndSetGasTotal.callCount, 1) - assert.deepEqual( - propsMethodSpies.updateAndSetGasTotal.getCall(0).args[0], - { - blockGasLimit: 'mockBlockGasLimit', - editingTransactionId: 'mockEditingTransactionId', - gasLimit: 'mockGasLimit', - gasPrice: 'mockGasPrice', - recentBlocks: ['mockBlock'], - selectedAddress: 'mockSelectedAddress', - selectedToken: 'mockSelectedToken', - to: '', - value: 'mockAmount', - } - ) - }) - - it('should call updateAndSetGasTotal with the correct params if a to prop is passed', () => { - propsMethodSpies.updateAndSetGasTotal.resetHistory() - wrapper.setProps({ to: 'someAddress' }) - wrapper.instance().updateGas() - assert.equal( - propsMethodSpies.updateAndSetGasTotal.getCall(0).args[0].to, - 'someaddress', - ) - }) - - it('should call updateAndSetGasTotal with to set to lowercase if passed', () => { - propsMethodSpies.updateAndSetGasTotal.resetHistory() - wrapper.instance().updateGas({ to: '0xABC' }) - assert.equal(propsMethodSpies.updateAndSetGasTotal.getCall(0).args[0].to, '0xabc') - }) - }) - - describe('render', () => { - it('should render a page-container class', () => { - assert.equal(wrapper.find('.page-container').length, 1) - }) - - it('should render SendHeader, SendContent and SendFooter', () => { - assert.equal(wrapper.find(SendHeader).length, 1) - assert.equal(wrapper.find(SendContent).length, 1) - assert.equal(wrapper.find(SendFooter).length, 1) - }) - - it('should pass the history prop to SendHeader and SendFooter', () => { - assert.deepEqual( - wrapper.find(SendFooter).props(), - { - history: { mockProp: 'history-abc' }, - } - ) - }) - }) -}) diff --git a/ui/app/components/send_/tests/send-container.test.js b/ui/app/components/send_/tests/send-container.test.js deleted file mode 100644 index 91484f4d8..000000000 --- a/ui/app/components/send_/tests/send-container.test.js +++ /dev/null @@ -1,157 +0,0 @@ -import assert from 'assert' -import proxyquire from 'proxyquire' -import sinon from 'sinon' - -let mapStateToProps -let mapDispatchToProps - -const actionSpies = { - updateSendTokenBalance: sinon.spy(), - updateGasData: 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}`, - getBlockGasLimit: (s) => `mockBlockGasLimit:${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}`, - getRecentBlocks: (s) => `mockRecentBlocks:${s}`, - getSelectedAddress: (s) => `mockSelectedAddress:${s}`, - getSelectedToken: (s) => `mockSelectedToken:${s}`, - getSelectedTokenContract: (s) => `mockTokenContract:${s}`, - getSelectedTokenToFiatRate: (s) => `mockTokenToFiatRate:${s}`, - getSendAmount: (s) => `mockAmount:${s}`, - getSendTo: (s) => `mockTo:${s}`, - getSendEditingTransactionId: (s) => `mockEditingTransactionId:${s}`, - getSendFromObject: (s) => `mockFrom:${s}`, - getTokenBalance: (s) => `mockTokenBalance:${s}`, - }, - '../../actions': actionSpies, - '../../ducks/send.duck': duckActionSpies, - './send.utils.js': { - calcGasTotal: (gasLimit, gasPrice) => gasLimit + gasPrice, - }, -}) - -describe('send container', () => { - - describe('mapStateToProps()', () => { - - it('should map the correct properties to props', () => { - assert.deepEqual(mapStateToProps('mockState'), { - amount: 'mockAmount:mockState', - amountConversionRate: 'mockAmountConversionRate:mockState', - blockGasLimit: 'mockBlockGasLimit:mockState', - conversionRate: 'mockConversionRate:mockState', - editingTransactionId: 'mockEditingTransactionId:mockState', - from: 'mockFrom:mockState', - gasLimit: 'mockGasLimit:mockState', - gasPrice: 'mockGasPrice:mockState', - gasTotal: 'mockGasTotal:mockState', - network: 'mockNetwork:mockState', - primaryCurrency: 'mockPrimaryCurrency:mockState', - recentBlocks: 'mockRecentBlocks:mockState', - selectedAddress: 'mockSelectedAddress:mockState', - selectedToken: 'mockSelectedToken:mockState', - to: 'mockTo: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 = { - blockGasLimit: 'mockBlockGasLimit', - editingTransactionId: '0x2', - gasLimit: '0x3', - gasPrice: '0x4', - recentBlocks: ['mockBlock'], - selectedAddress: '0x4', - selectedToken: { address: '0x1' }, - to: 'mockTo', - value: 'mockValue', - } - - 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 updateGasData action when editingTransactionId is falsy', () => { - const { selectedAddress, selectedToken, recentBlocks, blockGasLimit, to, value } = mockProps - mapDispatchToPropsObject.updateAndSetGasTotal( - Object.assign({}, mockProps, {editingTransactionId: false}) - ) - assert(dispatchSpy.calledOnce) - assert.deepEqual( - actionSpies.updateGasData.getCall(0).args[0], - { selectedAddress, selectedToken, recentBlocks, blockGasLimit, to, value } - ) - }) - }) - - 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' - ) - }) - }) - - }) - -}) diff --git a/ui/app/components/send_/tests/send-selectors-test-data.js b/ui/app/components/send_/tests/send-selectors-test-data.js deleted file mode 100644 index 8f9c19314..000000000 --- a/ui/app/components/send_/tests/send-selectors-test-data.js +++ /dev/null @@ -1,230 +0,0 @@ -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', - }, - }, - 'currentBlockGasLimit': '0x4c1878', - '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': [ - { - 'id': 'mockTokenTx1', - 'txParams': { - 'to': '0x8d6b81208414189a58339873ab429b6c47ab92d3', - }, - 'time': 1700000000000, - }, - { - 'id': 'mockTokenTx2', - 'txParams': { - 'to': '0xafaketokenaddress', - }, - 'time': 1600000000000, - }, - { - 'id': 'mockTokenTx3', - 'txParams': { - 'to': '0x8d6b81208414189a58339873ab429b6c47ab92d3', - }, - 'time': 1500000000000, - }, - { - 'id': 'mockEthTx1', - 'txParams': { - 'to': '0xd85a4b6a394794842887b8284293d69163007bbb', - }, - 'time': 1400000000000, - }, - ], - 'selectedTokenAddress': '0x8d6b81208414189a58339873ab429b6c47ab92d3', - 'unapprovedMsgs': { - '0xabc': { id: 'unapprovedMessage1', 'time': 1650000000000 }, - '0xdef': { id: 'unapprovedMessage2', 'time': 1550000000000 }, - '0xghi': { id: 'unapprovedMessage3', 'time': 1450000000000 }, - }, - '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': [ - { id: 'shapeShiftTx1', 'time': 1675000000000 }, - { id: 'shapeShiftTx2', 'time': 1575000000000 }, - { id: 'shapeShiftTx3', 'time': 1475000000000 }, - ], - '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', - recentBlocks: ['mockBlock1', 'mockBlock2', 'mockBlock3'], - }, - '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 }, - }, -} diff --git a/ui/app/components/send_/tests/send-selectors.test.js b/ui/app/components/send_/tests/send-selectors.test.js deleted file mode 100644 index 218da656b..000000000 --- a/ui/app/components/send_/tests/send-selectors.test.js +++ /dev/null @@ -1,685 +0,0 @@ -import assert from 'assert' -import sinon from 'sinon' -import selectors from '../send.selectors.js' -const { - accountsWithSendEtherInfoSelector, - // autoAddToBetaUI, - getAddressBook, - getBlockGasLimit, - getAmountConversionRate, - getConversionRate, - getCurrentAccountWithSendEtherInfo, - getCurrentCurrency, - getCurrentNetwork, - getCurrentViewContext, - getForceGasMin, - getGasLimit, - getGasPrice, - getGasTotal, - getPrimaryCurrency, - getRecentBlocks, - getSelectedAccount, - getSelectedAddress, - getSelectedIdentity, - getSelectedToken, - getSelectedTokenContract, - getSelectedTokenExchangeRate, - getSelectedTokenToFiatRate, - getSendAmount, - getSendEditingTransactionId, - getSendErrors, - getSendFrom, - getSendFromBalance, - getSendFromObject, - getSendMaxModeState, - getSendTo, - getSendToAccounts, - getTokenBalance, - getTokenExchangeRate, - getUnapprovedTxs, - transactionsSelector, -} = selectors -import mockState from './send-selectors-test-data' - -describe('send selectors', () => { - const tempGlobalEth = Object.assign({}, global.eth) - beforeEach(() => { - global.eth = { - contract: sinon.stub().returns({ - at: address => 'mockAt:' + address, - }), - } - }) - - afterEach(() => { - global.eth = tempGlobalEth - }) - - 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('getBlockGasLimit', () => { - it('should return the current block gas limit', () => { - assert.deepEqual( - getBlockGasLimit(mockState), - '0x4c1878' - ) - }) - }) - - describe('getConversionRate()', () => { - it('should return the eth conversion rate', () => { - assert.deepEqual( - getConversionRate(mockState), - 1200.88200327 - ) - }) - }) - - 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('getRecentBlocks()', () => { - it('should return the recent blocks', () => { - assert.deepEqual( - getRecentBlocks(mockState), - ['mockBlock1', 'mockBlock2', 'mockBlock3'] - ) - }) - }) - - 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) - ) - }) - }) - - describe('getSelectedTokenContract()', () => { - it('should return the contract at the selected token address', () => { - assert.equal( - getSelectedTokenContract(mockState), - 'mockAt:0x8d6b81208414189a58339873ab429b6c47ab92d3' - ) - }) - - it('should return null if no token is selected', () => { - const modifiedMetamaskState = Object.assign({}, mockState.metamask, { selectedTokenAddress: false }) - assert.equal( - getSelectedTokenContract(Object.assign({}, mockState, { metamask: modifiedMetamaskState })), - null - ) - }) - }) - - 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('transactionsSelector()', () => { - it('should return the selected addresses selected token transactions', () => { - assert.deepEqual( - transactionsSelector(mockState), - [ - { - id: 'mockTokenTx1', - txParams: { - to: '0x8d6b81208414189a58339873ab429b6c47ab92d3', - }, - time: 1700000000000, - }, - { - id: 'mockTokenTx3', - txParams: { - to: '0x8d6b81208414189a58339873ab429b6c47ab92d3', - }, - time: 1500000000000, - }, - ] - ) - }) - - it('should return all transactions if no token is selected', () => { - const modifiedMetamaskState = Object.assign({}, mockState.metamask, { selectedTokenAddress: false }) - const modifiedState = Object.assign({}, mockState, { metamask: modifiedMetamaskState }) - assert.deepEqual( - transactionsSelector(modifiedState), - [ - { - id: 'mockTokenTx1', - time: 1700000000000, - txParams: { - to: '0x8d6b81208414189a58339873ab429b6c47ab92d3', - }, - }, - { - id: 'unapprovedMessage1', - time: 1650000000000, - }, - { - id: 'mockTokenTx2', - time: 1600000000000, - txParams: { - to: '0xafaketokenaddress', - }, - }, - { - id: 'unapprovedMessage2', - time: 1550000000000, - }, - { - id: 'mockTokenTx3', - time: 1500000000000, - txParams: { - to: '0x8d6b81208414189a58339873ab429b6c47ab92d3', - }, - }, - { - id: 'unapprovedMessage3', - time: 1450000000000, - }, - { - id: 'mockEthTx1', - time: 1400000000000, - txParams: { - to: '0xd85a4b6a394794842887b8284293d69163007bbb', - }, - }, - ] - ) - }) - - it('should return shapeshift transactions if current network is 1', () => { - const modifiedMetamaskState = Object.assign({}, mockState.metamask, { selectedTokenAddress: false, network: '1' }) - const modifiedState = Object.assign({}, mockState, { metamask: modifiedMetamaskState }) - assert.deepEqual( - transactionsSelector(modifiedState), - [ - { - id: 'mockTokenTx1', - time: 1700000000000, - txParams: { - to: '0x8d6b81208414189a58339873ab429b6c47ab92d3', - }, - }, - { id: 'shapeShiftTx1', 'time': 1675000000000 }, - { - id: 'unapprovedMessage1', - time: 1650000000000, - }, - { - id: 'mockTokenTx2', - time: 1600000000000, - txParams: { - to: '0xafaketokenaddress', - }, - }, - { id: 'shapeShiftTx2', 'time': 1575000000000 }, - { - id: 'unapprovedMessage2', - time: 1550000000000, - }, - { - id: 'mockTokenTx3', - time: 1500000000000, - txParams: { - to: '0x8d6b81208414189a58339873ab429b6c47ab92d3', - }, - }, - { id: 'shapeShiftTx3', 'time': 1475000000000 }, - { - id: 'unapprovedMessage3', - time: 1450000000000, - }, - { - id: 'mockEthTx1', - time: 1400000000000, - txParams: { - to: '0xd85a4b6a394794842887b8284293d69163007bbb', - }, - }, - ] - ) - }) - }) - -}) diff --git a/ui/app/components/send_/tests/send-utils.test.js b/ui/app/components/send_/tests/send-utils.test.js deleted file mode 100644 index a518a64e9..000000000 --- a/ui/app/components/send_/tests/send-utils.test.js +++ /dev/null @@ -1,442 +0,0 @@ -import assert from 'assert' -import sinon from 'sinon' -import proxyquire from 'proxyquire' -import { - BASE_TOKEN_GAS_COST, - ONE_GWEI_IN_WEI_HEX, - SIMPLE_GAS_COST, -} from '../send.constants' -const { - addCurrencies, - subtractCurrencies, -} = require('../../../conversion-util') - -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}x${b}`), - calcTokenAmount: sinon.stub().callsFake((a, d) => 'calc:' + a + d), - rawEncode: sinon.stub().returns([16, 1100]), - conversionGreaterThan: sinon.stub().callsFake((obj1, obj2) => obj1.value > obj2.value), - conversionLessThan: sinon.stub().callsFake((obj1, obj2) => obj1.value < obj2.value), -} - -const sendUtils = proxyquire('../send.utils.js', { - '../../conversion-util': { - addCurrencies: stubs.addCurrencies, - conversionUtil: stubs.conversionUtil, - conversionGTE: stubs.conversionGTE, - multiplyCurrencies: stubs.multiplyCurrencies, - conversionGreaterThan: stubs.conversionGreaterThan, - conversionLessThan: stubs.conversionLessThan, - }, - '../../token-util': { calcTokenAmount: stubs.calcTokenAmount }, - 'ethereumjs-abi': { - rawEncode: stubs.rawEncode, - }, -}) - -const { - calcGasTotal, - estimateGas, - doesAmountErrorRequireUpdate, - estimateGasPriceFromRecentBlocks, - generateTokenTransferData, - getAmountErrorObject, - getToAddressForGasUpdate, - 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, '12x15') - 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({ toAddress: 'mockAddress', amount: '0xa', selectedToken: false}), undefined) - }) - - it('should call abi.rawEncode with the correct params', () => { - stubs.rawEncode.resetHistory() - generateTokenTransferData({ toAddress: 'mockAddress', amount: 'ab', selectedToken: true}) - assert.deepEqual( - stubs.rawEncode.getCall(0).args, - [['address', 'uint256'], ['mockAddress', '0xab']] - ) - }) - - it('should return encoded token transfer data', () => { - assert.equal( - generateTokenTransferData({ toAddress: 'mockAddress', amount: '0xa', selectedToken: true}), - '0xa9059cbb104c' - ) - }) - }) - - 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('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) - }) - }) - - describe('estimateGas', () => { - const baseMockParams = { - blockGasLimit: '0x64', - selectedAddress: 'mockAddress', - to: '0xisContract', - estimateGasMethod: sinon.stub().callsFake( - (data, cb) => cb( - data.to.match(/willFailBecauseOf:/) ? { message: data.to.match(/:(.+)$/)[1] } : null, - { toString: (n) => `0xabc${n}` } - ) - ), - } - const baseExpectedCall = { - from: 'mockAddress', - gas: '0x64x0.95', - to: '0xisContract', - } - - beforeEach(() => { - global.eth = { - getCode: sinon.stub().callsFake( - (address) => Promise.resolve(address.match(/isContract/) ? 'not-0x' : '0x') - ), - } - }) - - afterEach(() => { - baseMockParams.estimateGasMethod.resetHistory() - global.eth.getCode.resetHistory() - }) - - it('should call ethQuery.estimateGas with the expected params', async () => { - const result = await sendUtils.estimateGas(baseMockParams) - assert.equal(baseMockParams.estimateGasMethod.callCount, 1) - assert.deepEqual( - baseMockParams.estimateGasMethod.getCall(0).args[0], - Object.assign({ gasPrice: undefined, value: undefined }, baseExpectedCall) - ) - assert.equal(result, '0xabc16') - }) - - it('should call ethQuery.estimateGas with the expected params when initialGasLimitHex is lower than the upperGasLimit', async () => { - const result = await estimateGas(Object.assign({}, baseMockParams, { blockGasLimit: '0xbcd' })) - assert.equal(baseMockParams.estimateGasMethod.callCount, 1) - assert.deepEqual( - baseMockParams.estimateGasMethod.getCall(0).args[0], - Object.assign({ gasPrice: undefined, value: undefined }, baseExpectedCall, { gas: '0xbcdx0.95' }) - ) - assert.equal(result, '0xabc16x1.5') - }) - - it('should call ethQuery.estimateGas with a value of 0x0 and the expected data and to if passed a selectedToken', async () => { - const result = await estimateGas(Object.assign({ data: 'mockData', selectedToken: { address: 'mockAddress' } }, baseMockParams)) - assert.equal(baseMockParams.estimateGasMethod.callCount, 1) - assert.deepEqual( - baseMockParams.estimateGasMethod.getCall(0).args[0], - Object.assign({}, baseExpectedCall, { - gasPrice: undefined, - value: '0x0', - data: '0xa9059cbb104c', - to: 'mockAddress', - }) - ) - assert.equal(result, '0xabc16') - }) - - it(`should return ${SIMPLE_GAS_COST} if ethQuery.getCode does not return '0x'`, async () => { - assert.equal(baseMockParams.estimateGasMethod.callCount, 0) - const result = await estimateGas(Object.assign({}, baseMockParams, { to: '0x123' })) - assert.equal(result, SIMPLE_GAS_COST) - }) - - it(`should return ${SIMPLE_GAS_COST} if not passed a selectedToken or truthy to address`, async () => { - assert.equal(baseMockParams.estimateGasMethod.callCount, 0) - const result = await estimateGas(Object.assign({}, baseMockParams, { to: null })) - assert.equal(result, SIMPLE_GAS_COST) - }) - - it(`should not return ${SIMPLE_GAS_COST} if passed a selectedToken`, async () => { - assert.equal(baseMockParams.estimateGasMethod.callCount, 0) - const result = await estimateGas(Object.assign({}, baseMockParams, { to: '0x123', selectedToken: { address: '' } })) - assert.notEqual(result, SIMPLE_GAS_COST) - }) - - it(`should return ${BASE_TOKEN_GAS_COST} if passed a selectedToken but no to address`, async () => { - const result = await estimateGas(Object.assign({}, baseMockParams, { to: null, selectedToken: { address: '' } })) - assert.equal(result, BASE_TOKEN_GAS_COST) - }) - - it(`should return the adjusted blockGasLimit if it fails with a 'Transaction execution error.'`, async () => { - const result = await estimateGas(Object.assign({}, baseMockParams, { - to: 'isContract willFailBecauseOf:Transaction execution error.', - })) - assert.equal(result, '0x64x0.95') - }) - - it(`should return the adjusted blockGasLimit if it fails with a 'gas required exceeds allowance or always failing transaction.'`, async () => { - const result = await estimateGas(Object.assign({}, baseMockParams, { - to: 'isContract willFailBecauseOf:gas required exceeds allowance or always failing transaction.', - })) - assert.equal(result, '0x64x0.95') - }) - - it(`should reject other errors`, async () => { - try { - await estimateGas(Object.assign({}, baseMockParams, { - to: 'isContract willFailBecauseOf:some other error', - })) - } catch (err) { - assert.deepEqual(err, { message: 'some other error' }) - } - }) - }) - - describe('estimateGasPriceFromRecentBlocks', () => { - const ONE_GWEI_IN_WEI_HEX_PLUS_ONE = addCurrencies(ONE_GWEI_IN_WEI_HEX, '0x1', { - aBase: 16, - bBase: 16, - toNumericBase: 'hex', - }) - const ONE_GWEI_IN_WEI_HEX_PLUS_TWO = addCurrencies(ONE_GWEI_IN_WEI_HEX, '0x2', { - aBase: 16, - bBase: 16, - toNumericBase: 'hex', - }) - const ONE_GWEI_IN_WEI_HEX_MINUS_ONE = subtractCurrencies(ONE_GWEI_IN_WEI_HEX, '0x1', { - aBase: 16, - bBase: 16, - toNumericBase: 'hex', - }) - - it(`should return ${ONE_GWEI_IN_WEI_HEX} if recentBlocks is falsy`, () => { - assert.equal(estimateGasPriceFromRecentBlocks(), ONE_GWEI_IN_WEI_HEX) - }) - - it(`should return ${ONE_GWEI_IN_WEI_HEX} if recentBlocks is empty`, () => { - assert.equal(estimateGasPriceFromRecentBlocks([]), ONE_GWEI_IN_WEI_HEX) - }) - - it(`should estimate a block's gasPrice as ${ONE_GWEI_IN_WEI_HEX} if it has no gas prices`, () => { - const mockRecentBlocks = [ - { gasPrices: null }, - { gasPrices: [ ONE_GWEI_IN_WEI_HEX_PLUS_ONE ] }, - { gasPrices: [ ONE_GWEI_IN_WEI_HEX_MINUS_ONE ] }, - ] - assert.equal(estimateGasPriceFromRecentBlocks(mockRecentBlocks), ONE_GWEI_IN_WEI_HEX) - }) - - it(`should estimate a block's gasPrice as ${ONE_GWEI_IN_WEI_HEX} if it has empty gas prices`, () => { - const mockRecentBlocks = [ - { gasPrices: [] }, - { gasPrices: [ ONE_GWEI_IN_WEI_HEX_PLUS_ONE ] }, - { gasPrices: [ ONE_GWEI_IN_WEI_HEX_MINUS_ONE ] }, - ] - assert.equal(estimateGasPriceFromRecentBlocks(mockRecentBlocks), ONE_GWEI_IN_WEI_HEX) - }) - - it(`should return the middle value of all blocks lowest prices`, () => { - const mockRecentBlocks = [ - { gasPrices: [ ONE_GWEI_IN_WEI_HEX_PLUS_TWO ] }, - { gasPrices: [ ONE_GWEI_IN_WEI_HEX_MINUS_ONE ] }, - { gasPrices: [ ONE_GWEI_IN_WEI_HEX_PLUS_ONE ] }, - ] - assert.equal(estimateGasPriceFromRecentBlocks(mockRecentBlocks), ONE_GWEI_IN_WEI_HEX_PLUS_ONE) - }) - - it(`should work if a block has multiple gas prices`, () => { - const mockRecentBlocks = [ - { gasPrices: [ '0x1', '0x2', '0x3', '0x4', '0x5' ] }, - { gasPrices: [ '0x101', '0x100', '0x103', '0x104', '0x102' ] }, - { gasPrices: [ '0x150', '0x50', '0x100', '0x200', '0x5' ] }, - ] - assert.equal(estimateGasPriceFromRecentBlocks(mockRecentBlocks), '0x5') - }) - }) - - describe('getToAddressForGasUpdate()', () => { - it('should return empty string if all params are undefined or null', () => { - assert.equal(getToAddressForGasUpdate(undefined, null), '') - }) - - it('should return the first string that is not defined or null in lower case', () => { - assert.equal(getToAddressForGasUpdate('A', null), 'a') - assert.equal(getToAddressForGasUpdate(undefined, 'B'), 'b') - }) - }) -}) |