diff options
Diffstat (limited to 'ui/app/ducks')
-rw-r--r-- | ui/app/ducks/confirm-transaction.duck.js | 386 | ||||
-rw-r--r-- | ui/app/ducks/send.duck.js | 7 | ||||
-rw-r--r-- | ui/app/ducks/tests/confirm-transaction.duck.test.js | 675 | ||||
-rw-r--r-- | ui/app/ducks/tests/send-duck.test.js | 10 |
4 files changed, 1078 insertions, 0 deletions
diff --git a/ui/app/ducks/confirm-transaction.duck.js b/ui/app/ducks/confirm-transaction.duck.js new file mode 100644 index 000000000..1885e12d1 --- /dev/null +++ b/ui/app/ducks/confirm-transaction.duck.js @@ -0,0 +1,386 @@ +import { + conversionRateSelector, + currentCurrencySelector, + unconfirmedTransactionsHashSelector, +} from '../selectors/confirm-transaction' + +import { + getTokenData, + getMethodData, + getTransactionAmount, + getTransactionFee, + getHexGasTotal, + addFiat, + addEth, + increaseLastGasPrice, + hexGreaterThan, +} from '../helpers/confirm-transaction/util' + +import { getSymbolAndDecimals } from '../token-util' +import { conversionUtil } from '../conversion-util' + +// Actions +const createActionType = action => `metamask/confirm-transaction/${action}` + +const UPDATE_TX_DATA = createActionType('UPDATE_TX_DATA') +const CLEAR_TX_DATA = createActionType('CLEAR_TX_DATA') +const UPDATE_TOKEN_DATA = createActionType('UPDATE_TOKEN_DATA') +const CLEAR_TOKEN_DATA = createActionType('CLEAR_TOKEN_DATA') +const UPDATE_METHOD_DATA = createActionType('UPDATE_METHOD_DATA') +const CLEAR_METHOD_DATA = createActionType('CLEAR_METHOD_DATA') +const CLEAR_CONFIRM_TRANSACTION = createActionType('CLEAR_CONFIRM_TRANSACTION') +const UPDATE_TRANSACTION_AMOUNTS = createActionType('UPDATE_TRANSACTION_AMOUNTS') +const UPDATE_TRANSACTION_FEES = createActionType('UPDATE_TRANSACTION_FEES') +const UPDATE_TRANSACTION_TOTALS = createActionType('UPDATE_TRANSACTION_TOTALS') +const UPDATE_HEX_GAS_TOTAL = createActionType('UPDATE_HEX_GAS_TOTAL') +const UPDATE_TOKEN_PROPS = createActionType('UPDATE_TOKEN_PROPS') +const UPDATE_NONCE = createActionType('UPDATE_NONCE') +const FETCH_METHOD_DATA_START = createActionType('FETCH_METHOD_DATA_START') +const FETCH_METHOD_DATA_END = createActionType('FETCH_METHOD_DATA_END') + +// Initial state +const initState = { + txData: {}, + tokenData: {}, + methodData: {}, + tokenProps: { + tokenDecimals: '', + tokenSymbol: '', + }, + fiatTransactionAmount: '', + fiatTransactionFee: '', + fiatTransactionTotal: '', + ethTransactionAmount: '', + ethTransactionFee: '', + ethTransactionTotal: '', + hexGasTotal: '', + nonce: '', + fetchingMethodData: false, +} + +// Reducer +export default function reducer ({ confirmTransaction: confirmState = initState }, action = {}) { + switch (action.type) { + case UPDATE_TX_DATA: + return { + ...confirmState, + txData: { + ...action.payload, + }, + } + case CLEAR_TX_DATA: + return { + ...confirmState, + txData: {}, + } + case UPDATE_TOKEN_DATA: + return { + ...confirmState, + tokenData: { + ...action.payload, + }, + } + case CLEAR_TOKEN_DATA: + return { + ...confirmState, + tokenData: {}, + } + case UPDATE_METHOD_DATA: + return { + ...confirmState, + methodData: { + ...action.payload, + }, + } + case CLEAR_METHOD_DATA: + return { + ...confirmState, + methodData: {}, + } + case UPDATE_TRANSACTION_AMOUNTS: + const { fiatTransactionAmount, ethTransactionAmount } = action.payload + return { + ...confirmState, + fiatTransactionAmount: fiatTransactionAmount || confirmState.fiatTransactionAmount, + ethTransactionAmount: ethTransactionAmount || confirmState.ethTransactionAmount, + } + case UPDATE_TRANSACTION_FEES: + const { fiatTransactionFee, ethTransactionFee } = action.payload + return { + ...confirmState, + fiatTransactionFee: fiatTransactionFee || confirmState.fiatTransactionFee, + ethTransactionFee: ethTransactionFee || confirmState.ethTransactionFee, + } + case UPDATE_TRANSACTION_TOTALS: + const { fiatTransactionTotal, ethTransactionTotal } = action.payload + return { + ...confirmState, + fiatTransactionTotal: fiatTransactionTotal || confirmState.fiatTransactionTotal, + ethTransactionTotal: ethTransactionTotal || confirmState.ethTransactionTotal, + } + case UPDATE_HEX_GAS_TOTAL: + return { + ...confirmState, + hexGasTotal: action.payload, + } + case UPDATE_TOKEN_PROPS: + const { tokenSymbol = '', tokenDecimals = '' } = action.payload + return { + ...confirmState, + tokenProps: { + ...confirmState.tokenProps, + tokenSymbol, + tokenDecimals, + }, + } + case UPDATE_NONCE: + return { + ...confirmState, + nonce: action.payload, + } + case FETCH_METHOD_DATA_START: + return { + ...confirmState, + fetchingMethodData: true, + } + case FETCH_METHOD_DATA_END: + return { + ...confirmState, + fetchingMethodData: false, + } + case CLEAR_CONFIRM_TRANSACTION: + return initState + default: + return confirmState + } +} + +// Action Creators +export function updateTxData (txData) { + return { + type: UPDATE_TX_DATA, + payload: txData, + } +} + +export function clearTxData () { + return { + type: CLEAR_TX_DATA, + } +} + +export function updateTokenData (tokenData) { + return { + type: UPDATE_TOKEN_DATA, + payload: tokenData, + } +} + +export function clearTokenData () { + return { + type: CLEAR_TOKEN_DATA, + } +} + +export function updateMethodData (methodData) { + return { + type: UPDATE_METHOD_DATA, + payload: methodData, + } +} + +export function clearMethodData () { + return { + type: CLEAR_METHOD_DATA, + } +} + +export function updateTransactionAmounts (amounts) { + return { + type: UPDATE_TRANSACTION_AMOUNTS, + payload: amounts, + } +} + +export function updateTransactionFees (fees) { + return { + type: UPDATE_TRANSACTION_FEES, + payload: fees, + } +} + +export function updateTransactionTotals (totals) { + return { + type: UPDATE_TRANSACTION_TOTALS, + payload: totals, + } +} + +export function updateHexGasTotal (hexGasTotal) { + return { + type: UPDATE_HEX_GAS_TOTAL, + payload: hexGasTotal, + } +} + +export function updateTokenProps (tokenProps) { + return { + type: UPDATE_TOKEN_PROPS, + payload: tokenProps, + } +} + +export function updateNonce (nonce) { + return { + type: UPDATE_NONCE, + payload: nonce, + } +} + +export function setFetchingMethodData (isFetching) { + return { + type: isFetching ? FETCH_METHOD_DATA_START : FETCH_METHOD_DATA_END, + } +} + +export function updateGasAndCalculate ({ gasLimit, gasPrice }) { + return (dispatch, getState) => { + const { confirmTransaction: { txData } } = getState() + const newTxData = { + ...txData, + txParams: { + ...txData.txParams, + gas: gasLimit, + gasPrice, + }, + } + + dispatch(updateTxDataAndCalculate(newTxData)) + } +} + +function increaseFromLastGasPrice (txData) { + const { lastGasPrice, txParams: { gasPrice: previousGasPrice } = {} } = txData + + // Set the minimum to a 10% increase from the lastGasPrice. + const minimumGasPrice = increaseLastGasPrice(lastGasPrice) + const gasPriceBelowMinimum = hexGreaterThan(minimumGasPrice, previousGasPrice) + const gasPrice = (!previousGasPrice || gasPriceBelowMinimum) ? minimumGasPrice : previousGasPrice + + return { + ...txData, + txParams: { + ...txData.txParams, + gasPrice, + }, + } +} + +export function updateTxDataAndCalculate (txData) { + return (dispatch, getState) => { + const state = getState() + const currentCurrency = currentCurrencySelector(state) + const conversionRate = conversionRateSelector(state) + + dispatch(updateTxData(txData)) + + const { txParams: { value, gas: gasLimit = '0x0', gasPrice = '0x0' } = {} } = txData + + const fiatTransactionAmount = getTransactionAmount({ + value, toCurrency: currentCurrency, conversionRate, numberOfDecimals: 2, + }) + const ethTransactionAmount = getTransactionAmount({ + value, toCurrency: 'ETH', conversionRate, numberOfDecimals: 6, + }) + + dispatch(updateTransactionAmounts({ fiatTransactionAmount, ethTransactionAmount })) + + const hexGasTotal = getHexGasTotal({ gasLimit, gasPrice }) + + dispatch(updateHexGasTotal(hexGasTotal)) + + const fiatTransactionFee = getTransactionFee({ + value: hexGasTotal, + toCurrency: currentCurrency, + numberOfDecimals: 2, + conversionRate, + }) + const ethTransactionFee = getTransactionFee({ + value: hexGasTotal, + toCurrency: 'ETH', + numberOfDecimals: 6, + conversionRate, + }) + + dispatch(updateTransactionFees({ fiatTransactionFee, ethTransactionFee })) + + const fiatTransactionTotal = addFiat(fiatTransactionFee, fiatTransactionAmount) + const ethTransactionTotal = addEth(ethTransactionFee, ethTransactionAmount) + + dispatch(updateTransactionTotals({ fiatTransactionTotal, ethTransactionTotal })) + } +} + +export function setTransactionToConfirm (transactionId) { + return async (dispatch, getState) => { + const state = getState() + const unconfirmedTransactionsHash = unconfirmedTransactionsHashSelector(state) + const transaction = unconfirmedTransactionsHash[transactionId] + + if (!transaction) { + console.error(`Transaction with id ${transactionId} not found`) + return + } + + if (transaction.txParams) { + const { lastGasPrice } = transaction + const txData = lastGasPrice ? increaseFromLastGasPrice(transaction) : transaction + dispatch(updateTxDataAndCalculate(txData)) + + const { txParams } = transaction + + if (txParams.data) { + const { tokens: existingTokens } = state + const { data, to: tokenAddress } = txParams + + try { + dispatch(setFetchingMethodData(true)) + const methodData = await getMethodData(data) + dispatch(updateMethodData(methodData)) + dispatch(setFetchingMethodData(false)) + } catch (error) { + dispatch(updateMethodData({})) + dispatch(setFetchingMethodData(false)) + } + + const tokenData = getTokenData(data) + dispatch(updateTokenData(tokenData)) + + try { + const tokenSymbolData = await getSymbolAndDecimals(tokenAddress, existingTokens) || {} + const { symbol: tokenSymbol = '', decimals: tokenDecimals = '' } = tokenSymbolData + dispatch(updateTokenProps({ tokenSymbol, tokenDecimals })) + } catch (error) { + dispatch(updateTokenProps({ tokenSymbol: '', tokenDecimals: '' })) + } + } + + if (txParams.nonce) { + const nonce = conversionUtil(txParams.nonce, { + fromNumericBase: 'hex', + toNumericBase: 'dec', + }) + + dispatch(updateNonce(nonce)) + } + } else { + dispatch(updateTxData(transaction)) + } + } +} + +export function clearConfirmTransaction () { + return { + type: CLEAR_CONFIRM_TRANSACTION, + } +} diff --git a/ui/app/ducks/send.duck.js b/ui/app/ducks/send.duck.js index 055cc05c1..db01bbaa9 100644 --- a/ui/app/ducks/send.duck.js +++ b/ui/app/ducks/send.duck.js @@ -6,6 +6,7 @@ const CLOSE_FROM_DROPDOWN = 'metamask/send/CLOSE_FROM_DROPDOWN' const OPEN_TO_DROPDOWN = 'metamask/send/OPEN_TO_DROPDOWN' const CLOSE_TO_DROPDOWN = 'metamask/send/CLOSE_TO_DROPDOWN' const UPDATE_SEND_ERRORS = 'metamask/send/UPDATE_SEND_ERRORS' +const RESET_SEND_STATE = 'metamask/send/RESET_SEND_STATE' // TODO: determine if this approach to initState is consistent with conventional ducks pattern const initState = { @@ -42,6 +43,8 @@ export default function reducer ({ send: sendState = initState }, action = {}) { ...action.value, }, }) + case RESET_SEND_STATE: + return extend({}, initState) default: return newState } @@ -70,3 +73,7 @@ export function updateSendErrors (errorObject) { value: errorObject, } } + +export function resetSendState () { + return { type: RESET_SEND_STATE } +} diff --git a/ui/app/ducks/tests/confirm-transaction.duck.test.js b/ui/app/ducks/tests/confirm-transaction.duck.test.js new file mode 100644 index 000000000..111674e33 --- /dev/null +++ b/ui/app/ducks/tests/confirm-transaction.duck.test.js @@ -0,0 +1,675 @@ +import assert from 'assert' +import configureMockStore from 'redux-mock-store' +import thunk from 'redux-thunk' + +import ConfirmTransactionReducer, * as actions from '../confirm-transaction.duck.js' + +const initialState = { + txData: {}, + tokenData: {}, + methodData: {}, + tokenProps: { + tokenDecimals: '', + tokenSymbol: '', + }, + fiatTransactionAmount: '', + fiatTransactionFee: '', + fiatTransactionTotal: '', + ethTransactionAmount: '', + ethTransactionFee: '', + ethTransactionTotal: '', + hexGasTotal: '', + nonce: '', + fetchingMethodData: false, +} + +const UPDATE_TX_DATA = 'metamask/confirm-transaction/UPDATE_TX_DATA' +const CLEAR_TX_DATA = 'metamask/confirm-transaction/CLEAR_TX_DATA' +const UPDATE_TOKEN_DATA = 'metamask/confirm-transaction/UPDATE_TOKEN_DATA' +const CLEAR_TOKEN_DATA = 'metamask/confirm-transaction/CLEAR_TOKEN_DATA' +const UPDATE_METHOD_DATA = 'metamask/confirm-transaction/UPDATE_METHOD_DATA' +const CLEAR_METHOD_DATA = 'metamask/confirm-transaction/CLEAR_METHOD_DATA' +const UPDATE_TRANSACTION_AMOUNTS = 'metamask/confirm-transaction/UPDATE_TRANSACTION_AMOUNTS' +const UPDATE_TRANSACTION_FEES = 'metamask/confirm-transaction/UPDATE_TRANSACTION_FEES' +const UPDATE_TRANSACTION_TOTALS = 'metamask/confirm-transaction/UPDATE_TRANSACTION_TOTALS' +const UPDATE_HEX_GAS_TOTAL = 'metamask/confirm-transaction/UPDATE_HEX_GAS_TOTAL' +const UPDATE_TOKEN_PROPS = 'metamask/confirm-transaction/UPDATE_TOKEN_PROPS' +const UPDATE_NONCE = 'metamask/confirm-transaction/UPDATE_NONCE' +const FETCH_METHOD_DATA_START = 'metamask/confirm-transaction/FETCH_METHOD_DATA_START' +const FETCH_METHOD_DATA_END = 'metamask/confirm-transaction/FETCH_METHOD_DATA_END' +const CLEAR_CONFIRM_TRANSACTION = 'metamask/confirm-transaction/CLEAR_CONFIRM_TRANSACTION' + +describe('Confirm Transaction Duck', () => { + describe('State changes', () => { + const mockState = { + confirmTransaction: { + txData: { + id: 1, + }, + tokenData: { + name: 'abcToken', + }, + methodData: { + name: 'approve', + }, + tokenProps: { + tokenDecimals: '3', + tokenSymbol: 'ABC', + }, + fiatTransactionAmount: '469.26', + fiatTransactionFee: '0.01', + fiatTransactionTotal: '1.000021', + ethTransactionAmount: '1', + ethTransactionFee: '0.000021', + ethTransactionTotal: '469.27', + hexGasTotal: '0x1319718a5000', + nonce: '0x0', + fetchingMethodData: false, + }, + } + + it('should initialize state', () => { + assert.deepEqual( + ConfirmTransactionReducer({}), + initialState + ) + }) + + it('should return state unchanged if it does not match a dispatched actions type', () => { + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: 'someOtherAction', + value: 'someValue', + }), + { ...mockState.confirmTransaction }, + ) + }) + + it('should set txData when receiving a UPDATE_TX_DATA action', () => { + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: UPDATE_TX_DATA, + payload: { + id: 2, + }, + }), + { + ...mockState.confirmTransaction, + txData: { + ...mockState.confirmTransaction.txData, + id: 2, + }, + } + ) + }) + + it('should clear txData when receiving a CLEAR_TX_DATA action', () => { + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: CLEAR_TX_DATA, + }), + { + ...mockState.confirmTransaction, + txData: {}, + } + ) + }) + + it('should set tokenData when receiving a UPDATE_TOKEN_DATA action', () => { + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: UPDATE_TOKEN_DATA, + payload: { + name: 'defToken', + }, + }), + { + ...mockState.confirmTransaction, + tokenData: { + ...mockState.confirmTransaction.tokenData, + name: 'defToken', + }, + } + ) + }) + + it('should clear tokenData when receiving a CLEAR_TOKEN_DATA action', () => { + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: CLEAR_TOKEN_DATA, + }), + { + ...mockState.confirmTransaction, + tokenData: {}, + } + ) + }) + + it('should set methodData when receiving a UPDATE_METHOD_DATA action', () => { + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: UPDATE_METHOD_DATA, + payload: { + name: 'transferFrom', + }, + }), + { + ...mockState.confirmTransaction, + methodData: { + ...mockState.confirmTransaction.methodData, + name: 'transferFrom', + }, + } + ) + }) + + it('should clear methodData when receiving a CLEAR_METHOD_DATA action', () => { + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: CLEAR_METHOD_DATA, + }), + { + ...mockState.confirmTransaction, + methodData: {}, + } + ) + }) + + it('should update transaction amounts when receiving an UPDATE_TRANSACTION_AMOUNTS action', () => { + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: UPDATE_TRANSACTION_AMOUNTS, + payload: { + fiatTransactionAmount: '123.45', + ethTransactionAmount: '.5', + }, + }), + { + ...mockState.confirmTransaction, + fiatTransactionAmount: '123.45', + ethTransactionAmount: '.5', + } + ) + }) + + it('should update transaction fees when receiving an UPDATE_TRANSACTION_FEES action', () => { + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: UPDATE_TRANSACTION_FEES, + payload: { + fiatTransactionFee: '123.45', + ethTransactionFee: '.5', + }, + }), + { + ...mockState.confirmTransaction, + fiatTransactionFee: '123.45', + ethTransactionFee: '.5', + } + ) + }) + + it('should update transaction totals when receiving an UPDATE_TRANSACTION_TOTALS action', () => { + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: UPDATE_TRANSACTION_TOTALS, + payload: { + fiatTransactionTotal: '123.45', + ethTransactionTotal: '.5', + }, + }), + { + ...mockState.confirmTransaction, + fiatTransactionTotal: '123.45', + ethTransactionTotal: '.5', + } + ) + }) + + it('should update hexGasTotal when receiving an UPDATE_HEX_GAS_TOTAL action', () => { + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: UPDATE_HEX_GAS_TOTAL, + payload: '0x0', + }), + { + ...mockState.confirmTransaction, + hexGasTotal: '0x0', + } + ) + }) + + it('should update tokenProps when receiving an UPDATE_TOKEN_PROPS action', () => { + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: UPDATE_TOKEN_PROPS, + payload: { + tokenSymbol: 'DEF', + tokenDecimals: '1', + }, + }), + { + ...mockState.confirmTransaction, + tokenProps: { + tokenSymbol: 'DEF', + tokenDecimals: '1', + }, + } + ) + }) + + it('should update nonce when receiving an UPDATE_NONCE action', () => { + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: UPDATE_NONCE, + payload: '0x1', + }), + { + ...mockState.confirmTransaction, + nonce: '0x1', + } + ) + }) + + it('should set fetchingMethodData to true when receiving a FETCH_METHOD_DATA_START action', () => { + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: FETCH_METHOD_DATA_START, + }), + { + ...mockState.confirmTransaction, + fetchingMethodData: true, + } + ) + }) + + it('should set fetchingMethodData to false when receiving a FETCH_METHOD_DATA_END action', () => { + assert.deepEqual( + ConfirmTransactionReducer({ confirmTransaction: { fetchingMethodData: true } }, { + type: FETCH_METHOD_DATA_END, + }), + { + fetchingMethodData: false, + } + ) + }) + + it('should clear confirmTransaction when receiving a FETCH_METHOD_DATA_END action', () => { + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: CLEAR_CONFIRM_TRANSACTION, + }), + { + ...initialState, + } + ) + }) + }) + + describe('Single actions', () => { + it('should create an action to update txData', () => { + const txData = { test: 123 } + const expectedAction = { + type: UPDATE_TX_DATA, + payload: txData, + } + + assert.deepEqual( + actions.updateTxData(txData), + expectedAction + ) + }) + + it('should create an action to clear txData', () => { + const expectedAction = { + type: CLEAR_TX_DATA, + } + + assert.deepEqual( + actions.clearTxData(), + expectedAction + ) + }) + + it('should create an action to update tokenData', () => { + const tokenData = { test: 123 } + const expectedAction = { + type: UPDATE_TOKEN_DATA, + payload: tokenData, + } + + assert.deepEqual( + actions.updateTokenData(tokenData), + expectedAction + ) + }) + + it('should create an action to clear tokenData', () => { + const expectedAction = { + type: CLEAR_TOKEN_DATA, + } + + assert.deepEqual( + actions.clearTokenData(), + expectedAction + ) + }) + + it('should create an action to update methodData', () => { + const methodData = { test: 123 } + const expectedAction = { + type: UPDATE_METHOD_DATA, + payload: methodData, + } + + assert.deepEqual( + actions.updateMethodData(methodData), + expectedAction + ) + }) + + it('should create an action to clear methodData', () => { + const expectedAction = { + type: CLEAR_METHOD_DATA, + } + + assert.deepEqual( + actions.clearMethodData(), + expectedAction + ) + }) + + it('should create an action to update transaction amounts', () => { + const transactionAmounts = { test: 123 } + const expectedAction = { + type: UPDATE_TRANSACTION_AMOUNTS, + payload: transactionAmounts, + } + + assert.deepEqual( + actions.updateTransactionAmounts(transactionAmounts), + expectedAction + ) + }) + + it('should create an action to update transaction fees', () => { + const transactionFees = { test: 123 } + const expectedAction = { + type: UPDATE_TRANSACTION_FEES, + payload: transactionFees, + } + + assert.deepEqual( + actions.updateTransactionFees(transactionFees), + expectedAction + ) + }) + + it('should create an action to update transaction totals', () => { + const transactionTotals = { test: 123 } + const expectedAction = { + type: UPDATE_TRANSACTION_TOTALS, + payload: transactionTotals, + } + + assert.deepEqual( + actions.updateTransactionTotals(transactionTotals), + expectedAction + ) + }) + + it('should create an action to update hexGasTotal', () => { + const hexGasTotal = '0x0' + const expectedAction = { + type: UPDATE_HEX_GAS_TOTAL, + payload: hexGasTotal, + } + + assert.deepEqual( + actions.updateHexGasTotal(hexGasTotal), + expectedAction + ) + }) + + it('should create an action to update tokenProps', () => { + const tokenProps = { + tokenDecimals: '1', + tokenSymbol: 'abc', + } + const expectedAction = { + type: UPDATE_TOKEN_PROPS, + payload: tokenProps, + } + + assert.deepEqual( + actions.updateTokenProps(tokenProps), + expectedAction + ) + }) + + it('should create an action to update nonce', () => { + const nonce = '0x1' + const expectedAction = { + type: UPDATE_NONCE, + payload: nonce, + } + + assert.deepEqual( + actions.updateNonce(nonce), + expectedAction + ) + }) + + it('should create an action to set fetchingMethodData to true', () => { + const expectedAction = { + type: FETCH_METHOD_DATA_START, + } + + assert.deepEqual( + actions.setFetchingMethodData(true), + expectedAction + ) + }) + + it('should create an action to set fetchingMethodData to false', () => { + const expectedAction = { + type: FETCH_METHOD_DATA_END, + } + + assert.deepEqual( + actions.setFetchingMethodData(false), + expectedAction + ) + }) + + it('should create an action to clear confirmTransaction', () => { + const expectedAction = { + type: CLEAR_CONFIRM_TRANSACTION, + } + + assert.deepEqual( + actions.clearConfirmTransaction(), + expectedAction + ) + }) + }) + + describe('Thunk actions', done => { + it('updates txData and gas on an existing transaction in confirmTransaction', () => { + const mockState = { + metamask: { + conversionRate: 468.58, + currentCurrency: 'usd', + }, + confirmTransaction: { + ethTransactionAmount: '1', + ethTransactionFee: '0.000021', + ethTransactionTotal: '1.000021', + fetchingMethodData: false, + fiatTransactionAmount: '469.26', + fiatTransactionFee: '0.01', + fiatTransactionTotal: '469.27', + hexGasTotal: '0x1319718a5000', + methodData: {}, + nonce: '', + tokenData: {}, + tokenProps: { + tokenDecimals: '', + tokenSymbol: '', + }, + txData: { + estimatedGas: '0x5208', + gasLimitSpecified: false, + gasPriceSpecified: false, + history: [], + id: 2603411941761054, + loadingDefaults: false, + metamaskNetworkId: '3', + origin: 'faucet.metamask.io', + simpleSend: true, + status: 'unapproved', + time: 1530838113716, + }, + }, + } + + const middlewares = [thunk] + const mockStore = configureMockStore(middlewares) + const store = mockStore(mockState) + const expectedActions = [ + 'metamask/confirm-transaction/UPDATE_TX_DATA', + 'metamask/confirm-transaction/UPDATE_TRANSACTION_AMOUNTS', + 'metamask/confirm-transaction/UPDATE_HEX_GAS_TOTAL', + 'metamask/confirm-transaction/UPDATE_TRANSACTION_FEES', + 'metamask/confirm-transaction/UPDATE_TRANSACTION_TOTALS', + ] + + store.dispatch(actions.updateGasAndCalculate({ gasLimit: '0x2', gasPrice: '0x25' })) + + const storeActions = store.getActions() + assert.equal(storeActions.length, expectedActions.length) + storeActions.forEach((action, index) => assert.equal(action.type, expectedActions[index])) + }) + + it('updates txData and updates gas values in confirmTransaction', () => { + const txData = { + estimatedGas: '0x5208', + gasLimitSpecified: false, + gasPriceSpecified: false, + history: [], + id: 2603411941761054, + loadingDefaults: false, + metamaskNetworkId: '3', + origin: 'faucet.metamask.io', + simpleSend: true, + status: 'unapproved', + time: 1530838113716, + txParams: { + from: '0xc5ae6383e126f901dcb06131d97a88745bfa88d6', + gas: '0x33450', + gasPrice: '0x2540be400', + to: '0x81b7e08f65bdf5648606c89998a9cc8164397647', + value: '0xde0b6b3a7640000', + }, + } + const mockState = { + metamask: { + conversionRate: 468.58, + currentCurrency: 'usd', + }, + confirmTransaction: { + ethTransactionAmount: '1', + ethTransactionFee: '0.000021', + ethTransactionTotal: '1.000021', + fetchingMethodData: false, + fiatTransactionAmount: '469.26', + fiatTransactionFee: '0.01', + fiatTransactionTotal: '469.27', + hexGasTotal: '0x1319718a5000', + methodData: {}, + nonce: '', + tokenData: {}, + tokenProps: { + tokenDecimals: '', + tokenSymbol: '', + }, + txData: { + ...txData, + txParams: { + ...txData.txParams, + }, + }, + }, + } + + const middlewares = [thunk] + const mockStore = configureMockStore(middlewares) + const store = mockStore(mockState) + const expectedActions = [ + 'metamask/confirm-transaction/UPDATE_TX_DATA', + 'metamask/confirm-transaction/UPDATE_TRANSACTION_AMOUNTS', + 'metamask/confirm-transaction/UPDATE_HEX_GAS_TOTAL', + 'metamask/confirm-transaction/UPDATE_TRANSACTION_FEES', + 'metamask/confirm-transaction/UPDATE_TRANSACTION_TOTALS', + ] + + store.dispatch(actions.updateTxDataAndCalculate(txData)) + + const storeActions = store.getActions() + assert.equal(storeActions.length, expectedActions.length) + storeActions.forEach((action, index) => assert.equal(action.type, expectedActions[index])) + }) + + it('updates confirmTransaction transaction', done => { + const mockState = { + metamask: { + conversionRate: 468.58, + currentCurrency: 'usd', + network: '3', + unapprovedTxs: { + 2603411941761054: { + estimatedGas: '0x5208', + gasLimitSpecified: false, + gasPriceSpecified: false, + history: [], + id: 2603411941761054, + loadingDefaults: false, + metamaskNetworkId: '3', + origin: 'faucet.metamask.io', + simpleSend: true, + status: 'unapproved', + time: 1530838113716, + txParams: { + from: '0xc5ae6383e126f901dcb06131d97a88745bfa88d6', + gas: '0x33450', + gasPrice: '0x2540be400', + to: '0x81b7e08f65bdf5648606c89998a9cc8164397647', + value: '0xde0b6b3a7640000', + }, + }, + }, + }, + confirmTransaction: {}, + } + + const middlewares = [thunk] + const mockStore = configureMockStore(middlewares) + const store = mockStore(mockState) + const expectedActions = [ + 'metamask/confirm-transaction/UPDATE_TX_DATA', + 'metamask/confirm-transaction/UPDATE_TRANSACTION_AMOUNTS', + 'metamask/confirm-transaction/UPDATE_HEX_GAS_TOTAL', + 'metamask/confirm-transaction/UPDATE_TRANSACTION_FEES', + 'metamask/confirm-transaction/UPDATE_TRANSACTION_TOTALS', + ] + + store.dispatch(actions.setTransactionToConfirm(2603411941761054)) + .then(() => { + const storeActions = store.getActions() + assert.equal(storeActions.length, expectedActions.length) + storeActions.forEach((action, index) => assert.equal(action.type, expectedActions[index])) + done() + }) + }) + }) +}) diff --git a/ui/app/ducks/tests/send-duck.test.js b/ui/app/ducks/tests/send-duck.test.js index c06cf55d2..c101132d9 100644 --- a/ui/app/ducks/tests/send-duck.test.js +++ b/ui/app/ducks/tests/send-duck.test.js @@ -24,6 +24,7 @@ describe('Send Duck', () => { const OPEN_TO_DROPDOWN = 'metamask/send/OPEN_TO_DROPDOWN' const CLOSE_TO_DROPDOWN = 'metamask/send/CLOSE_TO_DROPDOWN' const UPDATE_SEND_ERRORS = 'metamask/send/UPDATE_SEND_ERRORS' + const RESET_SEND_STATE = 'metamask/send/RESET_SEND_STATE' describe('SendReducer()', () => { it('should initialize state', () => { @@ -105,6 +106,15 @@ describe('Send Duck', () => { }) ) }) + + it('should return the initial state in response to a RESET_SEND_STATE action', () => { + assert.deepEqual( + SendReducer(mockState, { + type: RESET_SEND_STATE, + }), + Object.assign({}, initState) + ) + }) }) describe('openFromDropdown', () => { |