From 7c490098548522c16be1b1e84bce37f5bf87f1f4 Mon Sep 17 00:00:00 2001 From: Dan Date: Sat, 5 May 2018 11:11:53 -0400 Subject: Unit tests for containers, utils and selectors in send_/ --- .../send_/send-footer/send-footer.container.js | 4 +- .../send_/send-footer/send-footer.selectors.js | 2 +- .../send_/send-footer/send-footer.utils.js | 10 +- .../tests/send-footer-container.test.js | 202 +++++++++++++++++ .../tests/send-footer-selectors.test.js | 0 .../send-footer/tests/send-footer-utils.test.js | 242 +++++++++++++++++++++ 6 files changed, 453 insertions(+), 7 deletions(-) delete mode 100644 ui/app/components/send_/send-footer/tests/send-footer-selectors.test.js (limited to 'ui/app/components/send_/send-footer') diff --git a/ui/app/components/send_/send-footer/send-footer.container.js b/ui/app/components/send_/send-footer/send-footer.container.js index 022b2db08..0242dfa54 100644 --- a/ui/app/components/send_/send-footer/send-footer.container.js +++ b/ui/app/components/send_/send-footer/send-footer.container.js @@ -20,10 +20,8 @@ import { getSendToAccounts, getTokenBalance, getUnapprovedTxs, -} from '../send.selectors' -import { isSendFormInError, -} from './send-footer.selectors' +} from '../send.selectors' import { addressIsNew, constructTxParams, diff --git a/ui/app/components/send_/send-footer/send-footer.selectors.js b/ui/app/components/send_/send-footer/send-footer.selectors.js index e8fef6be6..15a053ae0 100644 --- a/ui/app/components/send_/send-footer/send-footer.selectors.js +++ b/ui/app/components/send_/send-footer/send-footer.selectors.js @@ -1,4 +1,4 @@ -import { getSendErrors } from '../send.selectors' +const { getSendErrors } = require('../send.selectors') const selectors = { isSendFormInError, diff --git a/ui/app/components/send_/send-footer/send-footer.utils.js b/ui/app/components/send_/send-footer/send-footer.utils.js index 353c0e347..149d9e357 100644 --- a/ui/app/components/send_/send-footer/send-footer.utils.js +++ b/ui/app/components/send_/send-footer/send-footer.utils.js @@ -1,6 +1,6 @@ -import ethAbi from 'ethereumjs-abi' -import ethUtil from 'ethereumjs-util' -import { TOKEN_TRANSFER_FUNCTION_SIGNATURE } from '../send.constants' +const ethAbi = require('ethereumjs-abi') +const ethUtil = require('ethereumjs-util') +const { TOKEN_TRANSFER_FUNCTION_SIGNATURE } = require('../send.constants') function formShouldBeDisabled ({ inError, selectedToken, tokenBalance, gasTotal }) { const missingTokenBalance = selectedToken && !tokenBalance @@ -47,6 +47,7 @@ function constructUpdatedTx ({ } if (selectedToken) { + console.log(`ethAbi.rawEncode`, ethAbi.rawEncode) const data = TOKEN_TRANSFER_FUNCTION_SIGNATURE + Array.prototype.map.call( ethAbi.rawEncode(['address', 'uint256'], [to, ethUtil.addHexPrefix(amount)]), x => ('00' + x.toString(16)).slice(-2) @@ -70,6 +71,8 @@ function constructUpdatedTx ({ delete editingTx.txParams.data } } + + return editingTx } function addressIsNew (toAccounts, newAddress) { @@ -81,4 +84,5 @@ module.exports = { formShouldBeDisabled, constructTxParams, constructUpdatedTx, + addHexPrefixToObjectValues, } 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 index e69de29bb..e9d4eb04d 100644 --- 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 @@ -0,0 +1,202 @@ +import assert from 'assert' +import proxyquire from 'proxyquire' +import sinon from 'sinon' + +let mapStateToProps +let mapDispatchToProps + +const actionSpies = { + addToAddressBook: sinon.spy(), + clearSend: sinon.spy(), + signTokenTx: sinon.spy(), + signTx: sinon.spy(), + updateTransaction: sinon.spy(), +} +const utilsStubs = { + addressIsNew: sinon.stub().returns(true), + constructTxParams: sinon.stub().returns('mockConstructedTxParams'), + constructUpdatedTx: sinon.stub().returns('mockConstructedUpdatedTxParams'), + formShouldBeDisabled: sinon.stub().returns('mockFormShouldBeDisabled'), +} + +proxyquire('../send-footer.container.js', { + 'react-redux': { + connect: (ms, md) => { + mapStateToProps = ms + mapDispatchToProps = md + return () => ({}) + }, + }, + '../../../actions': actionSpies, + '../send.selectors': { + getGasLimit: (s) => `mockGasLimit:${s}`, + getGasPrice: (s) => `mockGasPrice:${s}`, + getGasTotal: (s) => `mockGasTotal:${s}`, + getSelectedToken: (s) => `mockSelectedToken:${s}`, + getSendAmount: (s) => `mockAmount:${s}`, + getSendEditingTransactionId: (s) => `mockEditingTransactionId:${s}`, + getSendFromObject: (s) => `mockFromObject:${s}`, + getSendTo: (s) => `mockTo:${s}`, + getSendToAccounts: (s) => `mockToAccounts:${s}`, + getTokenBalance: (s) => `mockTokenBalance:${s}`, + getUnapprovedTxs: (s) => `mockUnapprovedTxs:${s}`, + isSendFormInError: (s) => `mockInError:${s}`, + }, + './send-footer.selectors': { isSendFormInError: () => {} }, + './send-footer.utils': utilsStubs, +}) + +describe('send-footer container', () => { + + describe('mapStateToProps()', () => { + + it('should map the correct properties to props', () => { + assert.deepEqual(mapStateToProps('mockState'), { + amount: 'mockAmount:mockState', + disabled: 'mockFormShouldBeDisabled', + selectedToken: 'mockSelectedToken:mockState', + editingTransactionId: 'mockEditingTransactionId:mockState', + from: 'mockFromObject:mockState', + gasLimit: 'mockGasLimit:mockState', + gasPrice: 'mockGasPrice:mockState', + inError: 'mockInError:mockState', + isToken: true, + to: 'mockTo:mockState', + toAccounts: 'mockToAccounts:mockState', + unapprovedTxs: 'mockUnapprovedTxs:mockState', + }) + assert.deepEqual( + utilsStubs.formShouldBeDisabled.getCall(0).args[0], + { + inError: 'mockInError:mockState', + selectedToken: 'mockSelectedToken:mockState', + tokenBalance: 'mockTokenBalance:mockState', + gasTotal: 'mockGasTotal:mockState', + } + ) + }) + + }) + + describe('mapDispatchToProps()', () => { + let dispatchSpy + let mapDispatchToPropsObject + + beforeEach(() => { + dispatchSpy = sinon.spy() + mapDispatchToPropsObject = mapDispatchToProps(dispatchSpy) + }) + + describe('clearSend()', () => { + it('should dispatch an action', () => { + mapDispatchToPropsObject.clearSend() + assert(dispatchSpy.calledOnce) + assert(actionSpies.clearSend.calledOnce) + }) + }) + + describe('sign()', () => { + it('should dispatch a signTokenTx action if selectedToken is defined', () => { + mapDispatchToPropsObject.sign({ + selectedToken: { + address: '0xabc', + }, + to: 'mockTo', + amount: 'mockAmount', + from: 'mockFrom', + gas: 'mockGas', + gasPrice: 'mockGasPrice', + }) + assert(dispatchSpy.calledOnce) + assert.deepEqual( + utilsStubs.constructTxParams.getCall(0).args[0], + { + selectedToken: { + address: '0xabc', + }, + to: 'mockTo', + amount: 'mockAmount', + from: 'mockFrom', + gas: 'mockGas', + gasPrice: 'mockGasPrice', + } + ) + assert.deepEqual( + actionSpies.signTokenTx.getCall(0).args, + [ '0xabc', 'mockTo', 'mockAmount', 'mockConstructedTxParams' ] + ) + }) + + it('should dispatch a sign action if selectedToken is not defined', () => { + utilsStubs.constructTxParams.resetHistory() + mapDispatchToPropsObject.sign({ + to: 'mockTo', + amount: 'mockAmount', + from: 'mockFrom', + gas: 'mockGas', + gasPrice: 'mockGasPrice', + }) + assert(dispatchSpy.calledOnce) + assert.deepEqual( + utilsStubs.constructTxParams.getCall(0).args[0], + { + selectedToken: undefined, + to: 'mockTo', + amount: 'mockAmount', + from: 'mockFrom', + gas: 'mockGas', + gasPrice: 'mockGasPrice', + } + ) + assert.deepEqual( + actionSpies.signTx.getCall(0).args, + [ 'mockConstructedTxParams' ] + ) + }) + }) + + describe('update()', () => { + it('should dispatch an updateTransaction action', () => { + mapDispatchToPropsObject.update({ + to: 'mockTo', + amount: 'mockAmount', + from: 'mockFrom', + gas: 'mockGas', + gasPrice: 'mockGasPrice', + editingTransactionId: 'mockEditingTransactionId', + selectedToken: 'mockSelectedToken', + unapprovedTxs: 'mockUnapprovedTxs', + }) + assert(dispatchSpy.calledOnce) + assert.deepEqual( + utilsStubs.constructUpdatedTx.getCall(0).args[0], + { + to: 'mockTo', + amount: 'mockAmount', + from: 'mockFrom', + gas: 'mockGas', + gasPrice: 'mockGasPrice', + editingTransactionId: 'mockEditingTransactionId', + selectedToken: 'mockSelectedToken', + unapprovedTxs: 'mockUnapprovedTxs', + } + ) + assert.equal(actionSpies.updateTransaction.getCall(0).args[0], 'mockConstructedUpdatedTxParams') + }) + }) + + describe('addToAddressBookIfNew()', () => { + it('should dispatch an action', () => { + mapDispatchToPropsObject.addToAddressBookIfNew('mockNewAddress', 'mockToAccounts', 'mockNickname') + assert(dispatchSpy.calledOnce) + assert.equal(utilsStubs.addressIsNew.getCall(0).args[0], 'mockToAccounts') + assert.deepEqual( + actionSpies.addToAddressBook.getCall(0).args, + [ '0xmockNewAddress', 'mockNickname' ] + ) + }) + }) + + }) + +}) 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 e69de29bb..000000000 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 index e69de29bb..b235ea5e5 100644 --- 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 @@ -0,0 +1,242 @@ +import assert from 'assert' +import proxyquire from 'proxyquire' +import sinon from 'sinon' +const { TOKEN_TRANSFER_FUNCTION_SIGNATURE } = require('../../send.constants') + +const stubs = { + rawEncode: sinon.stub().callsFake((arr1, arr2) => { + return [ ...arr1, ...arr2 ] + }), +} + +const sendUtils = proxyquire('../send-footer.utils.js', { + 'ethereumjs-abi': { + rawEncode: stubs.rawEncode, + }, +}) +const { + addressIsNew, + formShouldBeDisabled, + constructTxParams, + constructUpdatedTx, + addHexPrefixToObjectValues, +} = sendUtils + +describe('send-footer utils', () => { + + describe('addHexPrefixToObjectValues()', () => { + it('should return a new object with the same properties with a 0x prefix', () => { + assert.deepEqual( + addHexPrefixToObjectValues({ + prop1: '0x123', + prop2: '456', + prop3: 'x', + }), + { + prop1: '0x123', + prop2: '0x456', + prop3: '0xx', + } + ) + }) + }) + + describe('addressIsNew()', () => { + it('should return false if the address exists in toAccounts', () => { + assert.equal( + addressIsNew([ + { address: '0xabc' }, + { address: '0xdef' }, + { address: '0xghi' }, + ], '0xdef'), + false + ) + }) + + it('should return true if the address does not exists in toAccounts', () => { + assert.equal( + addressIsNew([ + { address: '0xabc' }, + { address: '0xdef' }, + { address: '0xghi' }, + ], '0xxyz'), + true + ) + }) + }) + + describe('formShouldBeDisabled()', () => { + const config = { + 'should return true if inError is truthy': { + inError: true, + expectedResult: true, + }, + 'should return true if gasTotal is falsy': { + inError: false, + gasTotal: false, + expectedResult: true, + }, + 'should return true if selectedToken is truthy and tokenBalance is falsy': { + selectedToken: true, + tokenBalance: null, + expectedResult: true, + }, + 'should return false if inError is false and all other params are truthy': { + inError: false, + gasTotal: '0x123', + selectedToken: true, + tokenBalance: 123, + expectedResult: false, + }, + } + Object.entries(config).map(([description, obj]) => { + it(description, () => { + assert.equal(formShouldBeDisabled(obj), obj.expectedResult) + }) + }) + }) + + describe('constructTxParams()', () => { + it('should return a new txParams object with value and to properties if there is no selectedToken', () => { + assert.deepEqual( + constructTxParams({ + selectedToken: false, + to: 'mockTo', + amount: 'mockAmount', + from: 'mockFrom', + gas: 'mockGas', + gasPrice: 'mockGasPrice', + }), + { + to: '0xmockTo', + value: '0xmockAmount', + from: '0xmockFrom', + gas: '0xmockGas', + gasPrice: '0xmockGasPrice', + } + ) + }) + + it('should return a new txParams object without a to property and a 0 value if there is a selectedToken', () => { + assert.deepEqual( + constructTxParams({ + selectedToken: true, + to: 'mockTo', + amount: 'mockAmount', + from: 'mockFrom', + gas: 'mockGas', + gasPrice: 'mockGasPrice', + }), + { + value: '0x0', + from: '0xmockFrom', + gas: '0xmockGas', + gasPrice: '0xmockGasPrice', + } + ) + }) + }) + + describe('constructUpdatedTx()', () => { + it('should return a new object with an updated txParams', () => { + const result = constructUpdatedTx({ + amount: 'mockAmount', + editingTransactionId: '0x456', + from: 'mockFrom', + gas: 'mockGas', + gasPrice: 'mockGasPrice', + selectedToken: false, + to: 'mockTo', + unapprovedTxs: { + '0x123': {}, + '0x456': { + unapprovedTxParam: 'someOtherParam', + txParams: { + data: 'someData', + }, + }, + }, + }) + + assert.deepEqual(result, { + unapprovedTxParam: 'someOtherParam', + txParams: { + from: '0xmockFrom', + gas: '0xmockGas', + gasPrice: '0xmockGasPrice', + value: '0xmockAmount', + to: '0xmockTo', + data: '0xsomeData', + }, + }) + }) + + it('should not have data property if there is non in the original tx', () => { + const result = constructUpdatedTx({ + amount: 'mockAmount', + editingTransactionId: '0x456', + from: 'mockFrom', + gas: 'mockGas', + gasPrice: 'mockGasPrice', + selectedToken: false, + to: 'mockTo', + unapprovedTxs: { + '0x123': {}, + '0x456': { + unapprovedTxParam: 'someOtherParam', + txParams: { + from: 'oldFrom', + gas: 'oldGas', + gasPrice: 'oldGasPrice', + }, + }, + }, + }) + + assert.deepEqual(result, { + unapprovedTxParam: 'someOtherParam', + txParams: { + from: '0xmockFrom', + gas: '0xmockGas', + gasPrice: '0xmockGasPrice', + value: '0xmockAmount', + to: '0xmockTo', + }, + }) + }) + + it('should have token property values if selectedToken is truthy', () => { + const result = constructUpdatedTx({ + amount: 'mockAmount', + editingTransactionId: '0x456', + from: 'mockFrom', + gas: 'mockGas', + gasPrice: 'mockGasPrice', + selectedToken: { + address: 'mockTokenAddress', + }, + to: 'mockTo', + unapprovedTxs: { + '0x123': {}, + '0x456': { + unapprovedTxParam: 'someOtherParam', + txParams: {}, + }, + }, + }) + + assert.deepEqual(result, { + unapprovedTxParam: 'someOtherParam', + txParams: { + from: '0xmockFrom', + gas: '0xmockGas', + gasPrice: '0xmockGasPrice', + value: '0x0', + to: '0xmockTokenAddress', + data: `${TOKEN_TRANSFER_FUNCTION_SIGNATURE}ss56Tont`, + }, + }) + }) + }) + +}) -- cgit