WA-234 Refactor 1 owner 1 threshold DOM safe test

This commit is contained in:
apanizo 2018-06-14 15:50:18 +02:00
parent 1e51a48250
commit 9d27d7a7a7
27 changed files with 407 additions and 25 deletions

View File

@ -5,7 +5,7 @@ import * as TestUtils from 'react-dom/test-utils'
import Layout from '~/routes/open/components/Layout'
import { FIELD_CONFIRMATIONS, FIELD_OWNERS } from '~/routes/open/components/fields'
import { getProviderInfo } from '~/wallets/getWeb3'
import Wrapper from '~/test/Wrapper'
import Wrapper from '~/test/utils/Wrapper'
import { CONFIRMATIONS_ERROR } from '~/routes/open/components/SafeForm'
const obSubmitMock = () => {}

View File

@ -6,7 +6,7 @@ import GnoForm from '~/components/forms/GnoForm'
import { FIELD_OWNERS } from '~/routes/open/components/fields'
import { getAccountsFrom } from '~/routes/open/utils/safeDataExtractor'
import { getProviderInfo } from '~/wallets/getWeb3'
import Wrapper from '~/test/Wrapper'
import Wrapper from '~/test/utils/Wrapper'
import { ADDRESS_REPEATED_ERROR } from '~/components/forms/validator'
import Owners from './index'

View File

@ -45,7 +45,10 @@ const Owners = openHoc(({
</Avatar>
<ListItemText primary="Owners" secondary={`${owners.size} owners`} />
<ListItemIcon>
{open ? <ExpandLess /> : <ExpandMore />}
{open
? <IconButton disableRipple><ExpandLess /></IconButton>
: <IconButton disableRipple><ExpandMore /></IconButton>
}
</ListItemIcon>
<Button
variant="raised"

View File

@ -3,6 +3,7 @@ import * as React from 'react'
import openHoc, { type Open } from '~/components/hoc/OpenHoc'
import { withStyles } from '@material-ui/core/styles'
import Collapse from '@material-ui/core/Collapse'
import IconButton from '@material-ui/core/IconButton'
import ListItemText from '~/components/List/ListItemText'
import List from '@material-ui/core/List'
import ListItem from '@material-ui/core/ListItem'
@ -57,7 +58,10 @@ const Confirmaitons = openHoc(({
</Avatar>
<ListItemText primary="Threshold" secondary={`${threshold} confirmation${threshold === 1 ? '' : 's'} needed`} />
<ListItemIcon>
{open ? <ExpandLess /> : <ExpandMore />}
{open
? <IconButton disableRipple><ExpandLess /></IconButton>
: <IconButton disableRipple><ExpandMore /></IconButton>
}
</ListItemIcon>
</ListItem>
<Collapse in={open} timeout="auto" unmountOnExit>

View File

@ -5,6 +5,7 @@ import { connect } from 'react-redux'
import openHoc, { type Open } from '~/components/hoc/OpenHoc'
import ExpandLess from '@material-ui/icons/ExpandLess'
import ExpandMore from '@material-ui/icons/ExpandMore'
import IconButton from '@material-ui/core/IconButton'
import ListItemText from '~/components/List/ListItemText'
import Row from '~/components/layout/Row'
import ListItem from '@material-ui/core/ListItem'
@ -62,7 +63,10 @@ class GnoTransaction extends React.PureComponent<Props, {}> {
</Avatar>
<ListItemText primary="Status" secondary={confirmationText} />
<ListItemIcon>
{open ? <ExpandLess /> : <ExpandMore />}
{open
? <IconButton disableRipple><ExpandLess /></IconButton>
: <IconButton disableRipple><ExpandMore /></IconButton>
}
</ListItemIcon>
</ListItem>
</Row>

View File

@ -1,6 +1,6 @@
// @flow
import { aNewStore } from '~/store'
import { addEtherTo } from '~/test/addEtherTo'
import { addEtherTo } from '~/test/utils/addEtherTo'
import { aDeployedSafe, executeWithdrawnOn } from '~/routes/safe/store/test/builder/deployedSafe.builder'
describe('Safe Blockchain Test', () => {

View File

@ -2,7 +2,7 @@
import { BALANCE_REDUCER_ID } from '~/routes/safe/store/reducer/balances'
import fetchBalance from '~/routes/safe/store/actions/fetchBalance'
import { aNewStore } from '~/store'
import { addEtherTo } from '~/test/addEtherTo'
import { addEtherTo } from '~/test/utils/addEtherTo'
import { aDeployedSafe } from './builder/deployedSafe.builder'
const balanceReducerTests = () => {

View File

@ -1,7 +1,7 @@
// @flow
import addBalance from '~/routes/safe/store/actions/addBalance'
import { aNewStore } from '~/store'
import { buildMathPropsFrom } from '~/test/buildReactRouterProps'
import { buildMathPropsFrom } from '~/test/utils/buildReactRouterProps'
import { balanceSelector } from '../selectors'
const balanceSelectorTests = () => {

View File

@ -4,7 +4,7 @@ import { type Match } from 'react-router-dom'
import { SAFE_REDUCER_ID } from '~/routes/safe/store/reducer/safe'
import { type Safe } from '~/routes/safe/store/model/safe'
import { SafeFactory } from '~/routes/safe/store/test/builder/safe.builder'
import { buildMathPropsFrom } from '~/test/buildReactRouterProps'
import { buildMathPropsFrom } from '~/test/utils/buildReactRouterProps'
import { getProviderInfo } from '~/wallets/getWeb3'
import { grantedSelector } from '~/routes/safe/container/selector'
import { makeProvider } from '~/wallets/store/model/provider'

View File

@ -4,7 +4,7 @@ import { type Match } from 'react-router-dom'
import { SAFE_REDUCER_ID } from '~/routes/safe/store/reducer/safe'
import { type Safe } from '~/routes/safe/store/model/safe'
import { SafeFactory } from '~/routes/safe/store/test/builder/safe.builder'
import { buildMathPropsFrom } from '~/test/buildReactRouterProps'
import { buildMathPropsFrom } from '~/test/utils/buildReactRouterProps'
import { safeSelector } from '../selectors'
const safeSelectorTests = () => {

View File

@ -5,7 +5,7 @@ import { Provider } from 'react-redux'
import { ConnectedRouter } from 'react-router-redux'
import Button from '~/components/layout/Button'
import { aNewStore, history } from '~/store'
import { addEtherTo } from '~/test/addEtherTo'
import { addEtherTo } from '~/test/utils/addEtherTo'
import { aDeployedSafe } from '~/routes/safe/store/test/builder/deployedSafe.builder'
import { SAFELIST_ADDRESS } from '~/routes/routes'
import SafeView from '~/routes/safe/component/Safe'

View File

@ -8,7 +8,7 @@ import { promisify } from '~/utils/promisify'
import { processTransaction } from '~/routes/safe/component/Transactions/processTransactions'
import { confirmationsTransactionSelector, safeSelector, safeTransactionsSelector } from '~/routes/safe/store/selectors/index'
import { getTransactionFromReduxStore } from '~/routes/safe/test/testMultisig'
import { buildMathPropsFrom } from '~/test/buildReactRouterProps'
import { buildMathPropsFrom } from '~/test/utils/buildReactRouterProps'
import { createTransaction } from '~/routes/safe/component/AddTransaction/createTransactions'
import fetchTransactions from '~/routes/safe/store/actions/fetchTransactions'
import { type GlobalState } from '~/store/index'

View File

@ -8,7 +8,7 @@ import { promisify } from '~/utils/promisify'
import { processTransaction } from '~/routes/safe/component/Transactions/processTransactions'
import { confirmationsTransactionSelector, safeSelector, safeTransactionsSelector } from '~/routes/safe/store/selectors/index'
import { getTransactionFromReduxStore } from '~/routes/safe/test/testMultisig'
import { buildMathPropsFrom } from '~/test/buildReactRouterProps'
import { buildMathPropsFrom } from '~/test/utils/buildReactRouterProps'
import { createTransaction } from '~/routes/safe/component/AddTransaction/createTransactions'
import { getGnosisSafeContract } from '~/wallets/safeContracts'
import fetchTransactions from '~/routes/safe/store/actions/fetchTransactions'

View File

@ -5,7 +5,7 @@ import { Provider } from 'react-redux'
import { ConnectedRouter } from 'react-router-redux'
import Button from '~/components/layout/Button'
import { aNewStore, history } from '~/store'
import { addEtherTo } from '~/test/addEtherTo'
import { addEtherTo } from '~/test/utils/addEtherTo'
import { aDeployedSafe, executeWithdrawnOn } from '~/routes/safe/store/test/builder/deployedSafe.builder'
import { SAFELIST_ADDRESS } from '~/routes/routes'
import SafeView from '~/routes/safe/component/Safe'

View File

@ -4,7 +4,7 @@ import { sleep } from '~/utils/timer'
import { getBalanceInEtherOf } from '~/wallets/getWeb3'
import Button from '~/components/layout/Button'
import { ADD_MULTISIG_BUTTON_TEXT, SEE_MULTISIG_BUTTON_TEXT } from '~/routes/safe/component/Safe/MultisigTx'
import { addEtherTo } from '~/test/addEtherTo'
import { addEtherTo } from '~/test/utils/addEtherTo'
import SafeView from '~/routes/safe/component/Safe'
import TransactionsComponent from '~/routes/safe/component/Transactions'
import TransactionComponent from '~/routes/safe/component/Transactions/Transaction'

View File

@ -1,10 +0,0 @@
// @flow
import { getWeb3 } from '~/wallets/getWeb3'
import { promisify } from '~/utils/promisify'
export const addEtherTo = async (address: string, eth: string) => {
const web3 = getWeb3()
const accounts = await promisify(cb => web3.eth.getAccounts(cb))
const txData = { from: accounts[0], to: address, value: web3.toWei(eth, 'ether') }
return promisify(cb => web3.eth.sendTransaction(txData, cb))
}

View File

@ -0,0 +1,141 @@
// @flow
import * as React from 'react'
import { type Store } from 'redux'
import TestUtils from 'react-dom/test-utils'
import { Provider } from 'react-redux'
import { ConnectedRouter } from 'react-router-redux'
import { DEPLOYED_COMPONENT_ID } from '~/routes/open/components/FormConfirmation'
import Open from '~/routes/open/container/Open'
import SafeView from '~/routes/safe/component/Safe'
import { aNewStore, history, type GlobalState } from '~/store'
import { sleep } from '~/utils/timer'
import { getProviderInfo, getWeb3 } from '~/wallets/getWeb3'
import addProvider from '~/wallets/store/actions/addProvider'
import { makeProvider } from '~/wallets/store/model/provider'
import AppRoutes from '~/routes'
import { SAFELIST_ADDRESS } from '~/routes/routes'
import { promisify } from '~/utils/promisify'
import { addEtherTo } from '~/test/utils/addEtherTo'
const fillOpenSafeForm = async (localStore: Store<GlobalState>) => {
const provider = await getProviderInfo()
const walletRecord = makeProvider(provider)
localStore.dispatch(addProvider(walletRecord))
return (
TestUtils.renderIntoDocument((
<Provider store={localStore}>
<ConnectedRouter history={history}>
<Open />
</ConnectedRouter>
</Provider>
))
)
}
const deploySafe = async (safe: React$Component<{}>, dailyLimit: string, threshold: number, numOwners: number) => {
expect(threshold).toBeLessThanOrEqual(numOwners)
const inputs = TestUtils.scryRenderedDOMComponentsWithTag(safe, 'input')
const fieldName = inputs[0]
const fieldOwners = inputs[1]
const fieldConfirmations = inputs[2]
const fieldDailyLimit = inputs[3]
const web3 = getWeb3()
const accounts = await promisify(cb => web3.eth.getAccounts(cb))
TestUtils.Simulate.change(fieldOwners, { target: { value: `${numOwners}` } })
await sleep(800)
const inputsExpanded = TestUtils.scryRenderedDOMComponentsWithTag(safe, 'input')
expect(inputsExpanded.length).toBe((numOwners * 2) + 4) // 2 per owner + name, dailyLimit, confirmations, numOwners
for (let i = 0; i < numOwners; i += 1) {
const nameIndex = (i * 2) + 2
const addressIndex = (i * 2) + 3
const ownerName = inputsExpanded[nameIndex]
const account = inputsExpanded[addressIndex]
TestUtils.Simulate.change(ownerName, { target: { value: `Adolfo ${i + 1} Eth Account` } })
TestUtils.Simulate.change(account, { target: { value: accounts[i] } })
}
TestUtils.Simulate.change(fieldName, { target: { value: 'Adolfo Safe' } })
TestUtils.Simulate.change(fieldConfirmations, { target: { value: `${threshold}` } })
TestUtils.Simulate.change(fieldDailyLimit, { target: { value: dailyLimit } })
const form = TestUtils.findRenderedDOMComponentWithTag(safe, 'form')
TestUtils.Simulate.submit(form) // fill the form
TestUtils.Simulate.submit(form) // confirming data
TestUtils.Simulate.submit(form) // Executing transaction
// giving some time to the component for updating its state with safe
// before destroying its context
await sleep(9000)
// THEN
const deployed = TestUtils.findRenderedDOMComponentWithClass(safe, DEPLOYED_COMPONENT_ID)
if (!deployed) {
throw new Error()
}
const transactionHash = JSON.parse(deployed.getElementsByTagName('pre')[0].innerHTML)
delete transactionHash.receipt.logsBloom
return transactionHash
}
const aDeployedSafe = async (
specificStore: Store<GlobalState>,
dailyLimit?: number = 0.5,
threshold?: number = 1,
numOwners?: number = 1,
) => {
const safe: React$Component<{}> = await fillOpenSafeForm(specificStore)
const deployedSafe = await deploySafe(safe, `${dailyLimit}`, threshold, numOwners)
return deployedSafe.logs[1].args.proxy
}
export type DomSafe = {
address: string,
safeButtons: Element[],
safe: React$Component<any, any>,
accounts: string[],
}
export const renderSafeInDom = async (
owners: number,
threshold: number,
dailyLimit: number = 0.5,
): Promise<DomSafe> => {
// create store
const store = aNewStore()
// deploy safe updating store
const address = await aDeployedSafe(store, dailyLimit, threshold, owners)
// have available accounts
const accounts = await promisify(cb => getWeb3().eth.getAccounts(cb))
// navigate to SAFE route
history.push(`${SAFELIST_ADDRESS}/${address}`)
const SafeDom = TestUtils.renderIntoDocument((
<Provider store={store}>
<ConnectedRouter history={history}>
<AppRoutes />
</ConnectedRouter>
</Provider>
))
// add funds to safe
await addEtherTo(address, '0.1')
// wait until funds are displayed and buttons are enabled
await sleep(3000)
// $FlowFixMe
const Safe = TestUtils.findRenderedComponentWithType(SafeDom, SafeView)
// $FlowFixMe
const buttons = TestUtils.scryRenderedDOMComponentsWithTag(Safe, 'button')
return {
address, safeButtons: buttons, safe: SafeDom, accounts,
}
}

View File

@ -0,0 +1,35 @@
// @flow
import TestUtils from 'react-dom/test-utils'
import { SEE_MULTISIG_BUTTON_TEXT } from '~/routes/safe/component/Safe/MultisigTx'
import { sleep } from '~/utils/timer'
export const EXPAND_OWNERS_INDEX = 0
export const ADD_OWNERS_INDEX = 1
export const EDIT_THRESHOLD_INDEX = 2
export const WITHDRAWN_INDEX = 3
export const MOVE_FUNDS_INDEX = 4
export const LIST_TXS_INDEX = 5
export const listTxsClickingOn = async (seeTxsButton: Element) => {
expect(seeTxsButton.getElementsByTagName('span')[0].innerHTML).toEqual(SEE_MULTISIG_BUTTON_TEXT)
TestUtils.Simulate.click(seeTxsButton)
// give some time to expand the transactions
await sleep(1500)
}
export const checkMinedTx = (Transaction: React$Component<any, any>, name: string) => {
const paragraphs = TestUtils.scryRenderedDOMComponentsWithTag(Transaction, 'p')
const status = 'Already executed'
const nameParagraph = paragraphs[0].innerHTML
const statusParagraph = paragraphs[2].innerHTML
const hashParagraph = paragraphs[3].innerHTML
expect(nameParagraph).toBe(name)
expect(statusParagraph).toContain(status)
expect(hashParagraph).not.toBe('')
expect(hashParagraph).not.toBe(undefined)
expect(hashParagraph).not.toBe(null)
expect(hashParagraph).toContain('0x')
}

34
src/test/safe.dom.test.js Normal file
View File

@ -0,0 +1,34 @@
// @flow
import TestUtils from 'react-dom/test-utils'
import Transaction from '~/routes/safe/component/Transactions/Transaction'
import { listTxsClickingOn, LIST_TXS_INDEX, MOVE_FUNDS_INDEX, ADD_OWNERS_INDEX, EXPAND_OWNERS_INDEX } from '~/test/builder/safe.dom.utils'
import { renderSafeInDom, type DomSafe } from '~/test/builder/safe.dom.builder'
import { sendMoveFundsForm, checkMinedMoveFundsTx } from '~/test/utils/transactions/moveFunds.helper'
import { sendAddOwnerForm, checkMinedAddOwnerTx } from '~/test/utils/transactions/addOwner.helper'
import { sendRemoveOwnerForm, checkMinedRemoveOwnerTx } from '~/test/utils/transactions/removeOwner.helper'
describe('DOM > Feature > SAFE MULTISIG TX 1 Owner 1 Threshold', () => {
let domSafe: DomSafe
it('process correctly all multisig txs in a 1 owner & 1 threshold safe', async () => {
// GIVEN one safe with 1 owner and 1 threshold
const owners = 1
const threshold = 1
domSafe = await renderSafeInDom(owners, threshold)
const { safe: SafeDom, safeButtons, accounts } = domSafe
// WHEN
await sendMoveFundsForm(SafeDom, safeButtons[MOVE_FUNDS_INDEX], 'Move funds', '0.01', accounts[1])
await sendAddOwnerForm(SafeDom, safeButtons[ADD_OWNERS_INDEX], 'Adol Metamask 2', accounts[1])
await sendRemoveOwnerForm(SafeDom, safeButtons[EXPAND_OWNERS_INDEX])
// await sendChangeThresholdForm(SafeDom, safeButtons[EDIT_THRESHOLD_INDEX], 'Change Threshold to 2')
// THEN
await listTxsClickingOn(safeButtons[LIST_TXS_INDEX])
const transactions = TestUtils.scryRenderedComponentsWithType(SafeDom, Transaction)
checkMinedMoveFundsTx(transactions[0], 'Move funds')
checkMinedAddOwnerTx(transactions[1], 'Add Owner Adol Metamask 2')
checkMinedRemoveOwnerTx(transactions[2], 'Remove Owner Adol Metamask 2')
// checkThresholdTx(transactions[3], 'Change Threshold to 2', done)
})
})

View File

@ -0,0 +1,23 @@
// @flow
import { getProviderInfo, getWeb3 } from '~/wallets/getWeb3'
import { promisify } from '~/utils/promisify'
import withdrawn, { DESTINATION_PARAM, VALUE_PARAM } from '~/routes/safe/component/Withdrawn/withdrawn'
export const addEtherTo = async (address: string, eth: string) => {
const web3 = getWeb3()
const accounts = await promisify(cb => web3.eth.getAccounts(cb))
const txData = { from: accounts[0], to: address, value: web3.toWei(eth, 'ether') }
return promisify(cb => web3.eth.sendTransaction(txData, cb))
}
export const executeWithdrawnOn = async (safeAddress: string, value: number) => {
const providerInfo = await getProviderInfo()
const userAddress = providerInfo.account
const values = {
[DESTINATION_PARAM]: userAddress,
[VALUE_PARAM]: `${value}`,
}
return withdrawn(values, safeAddress, userAddress)
}

View File

@ -0,0 +1,37 @@
// @flow
import TestUtils from 'react-dom/test-utils'
import { sleep } from '~/utils/timer'
import { checkMinedTx } from '~/test/builder/safe.dom.utils'
export const sendAddOwnerForm = (
SafeDom: React$Component<any, any>,
addOwner: React$Component<any, any>,
ownerName: string,
ownerAddress: string,
) => {
// load add multisig form component
TestUtils.Simulate.click(addOwner)
// give time to re-render it
sleep(1500)
// fill the form
const inputs = TestUtils.scryRenderedDOMComponentsWithTag(SafeDom, 'input')
const nameInput = inputs[0]
const addressInput = inputs[1]
TestUtils.Simulate.change(nameInput, { target: { value: ownerName } })
TestUtils.Simulate.change(addressInput, { target: { value: ownerAddress } })
// $FlowFixMe
const form = TestUtils.findRenderedDOMComponentWithTag(SafeDom, 'form')
// submit it
TestUtils.Simulate.submit(form)
TestUtils.Simulate.submit(form)
// give time to process transaction
return sleep(4000)
}
export const checkMinedAddOwnerTx = (Transaction: React$Component<any, any>, name: string) => {
checkMinedTx(Transaction, name)
}

View File

@ -0,0 +1,39 @@
// @flow
import TestUtils from 'react-dom/test-utils'
import { sleep } from '~/utils/timer'
import { checkMinedTx } from '~/test/builder/safe.dom.utils'
export const sendMoveFundsForm = (
SafeDom: React$Component<any, any>,
multisigButton: React$Component<any, any>,
txName: string,
value: string,
destination: string,
) => {
// load add multisig form component
TestUtils.Simulate.click(multisigButton)
// give time to re-render it
sleep(1500)
// fill the form
const inputs = TestUtils.scryRenderedDOMComponentsWithTag(SafeDom, 'input')
const nameInput = inputs[0]
const destinationInput = inputs[1]
const amountInEthInput = inputs[2]
TestUtils.Simulate.change(nameInput, { target: { value: txName } })
TestUtils.Simulate.change(amountInEthInput, { target: { value } })
TestUtils.Simulate.change(destinationInput, { target: { value: destination } })
// $FlowFixMe
const form = TestUtils.findRenderedDOMComponentWithTag(SafeDom, 'form')
// submit it
TestUtils.Simulate.submit(form)
TestUtils.Simulate.submit(form)
// give time to process transaction
return sleep(4000)
}
export const checkMinedMoveFundsTx = (Transaction: React$Component<any, any>, name: string) => {
checkMinedTx(Transaction, name)
}

View File

@ -0,0 +1,36 @@
// @flow
import TestUtils from 'react-dom/test-utils'
import { sleep } from '~/utils/timer'
import { checkMinedTx, EXPAND_OWNERS_INDEX } from '~/test/builder/safe.dom.utils'
export const sendRemoveOwnerForm = (
SafeDom: React$Component<any, any>,
expandOwners: React$Component<any, any>,
) => {
// Expand owners
TestUtils.Simulate.click(expandOwners)
sleep(1500)
// Get delete button user
const buttons = TestUtils.scryRenderedDOMComponentsWithTag(SafeDom, 'button')
const removeUserButton = buttons[EXPAND_OWNERS_INDEX + 2] // + 2 one the Add and the next delete
expect(removeUserButton.getAttribute('aria-label')).toBe('Delete')
// render form for deleting the user
TestUtils.Simulate.click(removeUserButton)
sleep(1500)
// $FlowFixMe
const form = TestUtils.findRenderedDOMComponentWithTag(SafeDom, 'form')
// submit it
TestUtils.Simulate.submit(form)
TestUtils.Simulate.submit(form)
// give time to process transaction
return sleep(4000)
}
export const checkMinedRemoveOwnerTx = (Transaction: React$Component<any, any>, name: string) => {
checkMinedTx(Transaction, name)
}

View File

@ -0,0 +1,36 @@
// @flow
import TestUtils from 'react-dom/test-utils'
import { sleep } from '~/utils/timer'
import { checkMinedTx, EXPAND_OWNERS_INDEX } from '~/test/builder/safe.dom.utils'
export const sendChangeThresholdForm = (
SafeDom: React$Component<any, any>,
expandOwners: React$Component<any, any>,
) => {
// Expand owners
TestUtils.Simulate.click(expandOwners)
sleep(1500)
// Get delete button user
const buttons = TestUtils.scryRenderedDOMComponentsWithTag(SafeDom, 'button')
const removeUserButton = buttons[EXPAND_OWNERS_INDEX + 2] // + 2 one the Add and the next delete
expect(removeUserButton.getAttribute('aria-label')).toBe('Delete')
// render form for deleting the user
TestUtils.Simulate.click(removeUserButton)
sleep(1500)
// $FlowFixMe
const form = TestUtils.findRenderedDOMComponentWithTag(SafeDom, 'form')
// submit it
TestUtils.Simulate.submit(form)
TestUtils.Simulate.submit(form)
// give time to process transaction
return sleep(4000)
}
export const checkMinedRemoveOwnerTx = (Transaction: React$Component<any, any>, name: string) => {
checkMinedTx(Transaction, name)
}