remove implementation tests for now

This commit is contained in:
mmv 2019-06-03 17:11:06 +04:00
parent bf174d6f94
commit 6523a25c9b
15 changed files with 2 additions and 1321 deletions

View File

@ -1,54 +0,0 @@
// @flow
/*
import addBalances from '~/routes/safe/store/actions/addBalances'
import { aNewStore } from '~/store'
import { buildMathPropsFrom } from '~/test/utils/buildReactRouterProps'
import { balanceSelector } from '../selectors'
const balanceSelectorTests = () => {
describe('Safe Selector[balanceSelector]', () => {
it('should return 0 when safe address is not found', () => {
// GIVEN
const safeAddress = 'foo'
const match = buildMathPropsFrom(safeAddress)
const store = aNewStore()
// WHEN
const balance = balanceSelector(store.getState(), { match })
// THEN
expect(balance).toBe('0')
})
it('should return 0 when safe has no funds', async () => {
// GIVEN
const safeAddress = 'foo'
const match = buildMathPropsFrom(safeAddress)
const store = aNewStore()
// WHEN
await store.dispatch(addBalances('bar', '1'))
const balance = balanceSelector(store.getState(), { match })
// THEN
expect(balance).toBe('0')
})
it('should return safe funds', async () => {
// GIVEN
const safeAddress = 'foo'
const match = buildMathPropsFrom(safeAddress)
const store = aNewStore()
// WHEN
await store.dispatch(addBalances(safeAddress, '1.3456'))
const balance = balanceSelector(store.getState(), { match })
// THEN
expect(balance).toBe('1.3456')
})
})
}
export default balanceSelectorTests
*/

View File

@ -1,59 +0,0 @@
// @flow
import SafeRecord, { type Safe } from '~/routes/safe/store/models/safe'
import { buildOwnersFrom } from '~/routes/safe/store/actions/addSafe'
class SafeBuilder {
safe: Safe
constructor() {
this.safe = SafeRecord()
}
withAddress(address: string) {
this.safe = this.safe.set('address', address)
return this
}
withName(name: string) {
this.safe = this.safe.set('name', name)
return this
}
withConfirmations(confirmations: number) {
this.safe = this.safe.set('threshold', confirmations)
return this
}
withOwner(names: string[], adresses: string[]) {
const owners = buildOwnersFrom(names, adresses)
this.safe = this.safe.set('owners', owners)
return this
}
get() {
return this.safe
}
}
const aSafe = () => new SafeBuilder()
export class SafeFactory {
static oneOwnerSafe = (ownerAddress: string = '0x03db1a8b26d08df23337e9276a36b474510f0023') => aSafe()
.withAddress('0x03db1a8b26d08df23337e9276a36b474510f0025')
.withName('Adol ICO Safe')
.withConfirmations(1)
.withOwner(['Adol Metamask'], [ownerAddress])
.get()
static twoOwnersSafe = (
firstOwner: string = '0x03db1a8b26d08df23337e9276a36b474510f0023',
secondOwner: string = '0x03db1a8b26d08df23337e9276a36b474510f0024',
) => aSafe()
.withAddress('0x03db1a8b26d08df23337e9276a36b474510f0026')
.withName('Adol & Tobias Safe')
.withConfirmations(2)
.withOwner(['Adol Metamask', 'Tobias Metamask'], [firstOwner, secondOwner])
.get()
}
export default aSafe

View File

@ -1,102 +0,0 @@
// @flow
/*
import { List, Map } from 'immutable'
import { makeTransaction, type Transaction } from '~/routes/safe/store/model/transaction'
import { type Confirmation, makeConfirmation } from '~/routes/safe/store/model/confirmation'
import { makeOwner } from '~/routes/safe/store/model/owner'
import { confirmationsTransactionSelector } from '~/routes/safe/store/selectors/index'
import { makeProvider } from '~/wallets/store/model/provider'
const grantedSelectorTests = () => {
describe('Safe Selector[confirmationsTransactionSelector]', () => {
it('returns 1 confirmation if safe has only one owner when tx is created', () => {
// GIVEN
const firstConfirmation: Confirmation = makeConfirmation({
owner: makeOwner(),
status: true,
hash: 'asdf',
})
const transaction: Transaction = makeTransaction({
name: 'Buy batteries',
nonce: 1,
value: 2,
confirmations: List([firstConfirmation]),
destination: 'destAddress',
threshold: 2,
tx: '',
})
const reduxStore = {
safes: Map(),
providers: makeProvider(),
tokens: Map(),
transactions: Map(),
}
// WHEN
const threshold = confirmationsTransactionSelector(reduxStore, { transaction })
// THEN
expect(threshold).toBe(1)
})
it('returns 1 confirmation if safe has two or more owners when multisig tx is created', () => {
// GIVEN
const firstConfirmation: Confirmation = makeConfirmation({
owner: makeOwner(),
status: true,
hash: 'asdf',
})
const secondConfirmation: Confirmation = makeConfirmation({
owner: makeOwner(),
status: false,
hash: '',
})
const transaction: Transaction = makeTransaction({
name: 'Buy batteries',
nonce: 1,
value: 2,
confirmations: List([firstConfirmation, secondConfirmation]),
destination: 'destAddress',
threshold: 2,
tx: '',
})
const reduxStore = {
safes: Map(),
providers: makeProvider(),
tokens: Map(),
transactions: Map(),
}
// WHEN
const threshold = confirmationsTransactionSelector(reduxStore, { transaction })
// THEN
expect(threshold).toBe(1)
})
it('should return 0 confirmations if not transaction is sent as prop to component', () => {
const reduxStore = {
safes: Map(),
providers: makeProvider(),
tokens: Map(),
transactions: Map(),
}
// WHEN
// $FlowFixMe
const threshold = confirmationsTransactionSelector(reduxStore, { transaction: undefined })
// THEN
expect(threshold).toBe(0)
})
})
}
export default grantedSelectorTests
*/

View File

@ -1,84 +0,0 @@
// @flow
import { Map } from 'immutable'
import { type Match } from 'react-router-dom'
import { SAFE_REDUCER_ID } from '~/routes/safe/store/reducer/safe'
import { type Safe } from '~/routes/safe/store/models/safe'
import { SafeFactory } from '~/routes/safe/store/test/builder/safe.builder'
import { buildMathPropsFrom } from '~/test/utils/buildReactRouterProps'
import { getProviderInfo } from '~/logic/wallets/getWeb3'
import { grantedSelector } from '~/routes/safe/container/selector'
import { makeProvider } from '~/logic/wallets/store/model/provider'
const grantedSelectorTests = () => {
let provider
beforeEach(async () => {
provider = await getProviderInfo()
})
describe('Safe Selector[grantedSelector]', () => {
it('should be granted to operate a safe when the user is owner', () => {
// GIVEN
let map: Map<string, Safe> = Map()
map = map.set('fooAddress', SafeFactory.oneOwnerSafe(provider.account))
const match: Match = buildMathPropsFrom('fooAddress')
const reduxStore = {
[SAFE_REDUCER_ID]: map,
providers: makeProvider(provider),
tokens: undefined,
transactions: undefined,
}
// WHEN
const granted = grantedSelector(reduxStore, { match })
// THEN
expect(granted).toBe(true)
})
it('should be granted to operate a safe when the user is owner in case-insensitive', () => {
// GIVEN
let map: Map<string, Safe> = Map()
map = map.set('fooAddress', SafeFactory.oneOwnerSafe(provider.account.toUpperCase()))
const match: Match = buildMathPropsFrom('fooAddress')
const reduxStore = {
[SAFE_REDUCER_ID]: map,
providers: makeProvider(provider),
tokens: undefined,
transactions: undefined,
}
// WHEN
const granted = grantedSelector(reduxStore, { match })
// THEN
expect(granted).toBe(true)
})
it('should NOT be granted to operate with a Safe when the user is NOT owner', () => {
// GIVEN
let map: Map<string, Safe> = Map()
map = map.set('fooAddress', SafeFactory.oneOwnerSafe('inventedOwner'))
const match: Match = buildMathPropsFrom('fooAddress')
const reduxStore = {
[SAFE_REDUCER_ID]: map,
providers: makeProvider(provider),
tokens: undefined,
transactions: undefined,
}
// WHEN
const granted = grantedSelector(reduxStore, { match })
// THEN
expect(granted).toBe(false)
})
})
}
export default grantedSelectorTests

View File

@ -1,60 +0,0 @@
// @flow
import {
combineReducers, createStore, applyMiddleware, compose,
} from 'redux'
import thunk from 'redux-thunk'
import safeReducer, { SAFE_REDUCER_ID } from '~/routes/safe/store/reducer/safe'
import addSafe from '~/routes/safe/store/actions/addSafe'
import * as SafeFields from '~/routes/open/components/fields'
import { getAccountsFrom, getNamesFrom } from '~/routes/open/utils/safeDataExtractor'
import { SafeFactory } from './builder/safe.builder'
const aStore = (initState) => {
const reducers = combineReducers({
[SAFE_REDUCER_ID]: safeReducer,
})
const middlewares = [thunk]
const enhancers = [applyMiddleware(...middlewares)]
return createStore(reducers, initState, compose(...enhancers))
}
const providerReducerTests = () => {
describe('Safe Actions[addSafe]', () => {
let store
let address
let formValues
beforeEach(() => {
store = aStore()
address = '0x03db1a8b26d08df23337e9276a36b474510f0025'
formValues = {
[SafeFields.FIELD_NAME]: 'Adol ICO Safe',
[SafeFields.FIELD_CONFIRMATIONS]: 1,
[SafeFields.FIELD_OWNERS]: 1,
[SafeFields.getOwnerAddressBy(0)]: '0x03db1a8b26d08df23337e9276a36b474510f0023',
[SafeFields.getOwnerNameBy(0)]: 'Adol Metamask',
address,
}
})
it('reducer should return SafeRecord from form values', () => {
// GIVEN in beforeEach method
// WHEN
store.dispatch(
addSafe(
formValues[SafeFields.FIELD_NAME],
formValues.address,
formValues[SafeFields.FIELD_CONFIRMATIONS],
getNamesFrom(formValues),
getAccountsFrom(formValues),
),
)
const safes = store.getState()[SAFE_REDUCER_ID]
// THEN
expect(safes.get(address)).toEqual(SafeFactory.oneOwnerSafe())
})
})
}
export default providerReducerTests

View File

@ -1,56 +0,0 @@
// @flow
import { Map } from 'immutable'
import { type Match } from 'react-router-dom'
import { SAFE_REDUCER_ID } from '~/routes/safe/store/reducer/safe'
import { type Safe } from '~/routes/safe/store/models/safe'
import { SafeFactory } from '~/routes/safe/store/test/builder/safe.builder'
import { buildMathPropsFrom } from '~/test/utils/buildReactRouterProps'
import { safeSelector } from '../selectors'
const safeSelectorTests = () => {
describe('Safe Selector[safeSelector]', () => {
it('should return empty list when no safes', () => {
// GIVEN
const reduxStore = {
[SAFE_REDUCER_ID]: Map(),
providers: undefined,
tokens: undefined,
transactions: undefined,
}
const match: Match = buildMathPropsFrom('fooAddress')
// WHEN
const safes = safeSelector(reduxStore, { match })
// THEN
expect(safes).toBe(undefined)
})
it('should return a list of size 2 when 2 safes are created', () => {
// GIVEN
let map: Map<string, Safe> = Map()
map = map.set('fooAddress', SafeFactory.oneOwnerSafe())
map = map.set('barAddress', SafeFactory.twoOwnersSafe())
const match: Match = buildMathPropsFrom('fooAddress')
const undefMatch: Match = buildMathPropsFrom('inventedAddress')
const reduxStore = {
[SAFE_REDUCER_ID]: map,
providers: undefined,
tokens: undefined,
transactions: undefined,
}
// WHEN
const oneOwnerSafe = safeSelector(reduxStore, { match })
const undefinedSafe = safeSelector(reduxStore, { match: undefMatch })
// THEN
expect(oneOwnerSafe).toEqual(SafeFactory.oneOwnerSafe())
expect(undefinedSafe).toBe(undefined)
})
})
}
export default safeSelectorTests

View File

@ -1,27 +0,0 @@
// @flow
import safeReducerTests from './safe.reducer'
// import balanceSelectorTests from './balance.selector'
import safeSelectorTests from './safe.selector'
import grantedSelectorTests from './granted.selector'
// import confirmationsSelectorTests from './confirmations.selector'
// import transactionsSelectorTests from './transactions.selector'
describe('Safe Test suite', () => {
// ACTIONS AND REDUCERS
safeReducerTests()
// SAFE SELECTOR
safeSelectorTests()
// BALANCE SELECTOR
// balanceSelectorTests()
// GRANTED SELECTOR
grantedSelectorTests()
// CONFIRMATIONS SELECTOR
// confirmationsSelectorTests()
// TRANSACTIONS SELECTOR
// transactionsSelectorTests()
})

View File

@ -1,131 +0,0 @@
// @flow
/*
import { List, Map } from 'immutable'
import { SAFE_REDUCER_ID } from '~/routes/safe/store/reducer/safe'
import { safeTransactionsSelector } from '~/routes/safe/store/selectors/index'
import { makeProvider } from '~/wallets/store/model/provider'
import { makeConfirmation, type Confirmation } from '~/routes/safe/store/model/confirmation'
import { makeOwner } from '~/routes/safe/store/model/owner'
import { makeTransaction, type Transaction } from '~/routes/safe/store/model/transaction'
const grantedSelectorTests = () => {
describe('Safe Selector[safeTransactionsSelector]', () => {
it('should return empty list if no transactions in store', () => {
// GIVEN
const reduxStore = {
[SAFE_REDUCER_ID]: Map(),
providers: makeProvider(),
tokens: undefined,
transactions: Map(),
}
// WHEN
const transactions = safeTransactionsSelector(reduxStore, { safeAddress: 'fooAddress' })
// THEN
expect(transactions).toEqual(List([]))
})
it('should return empty list if transactions in store but not safe address in props', () => {
// GIVEN
const firstConfirmation: Confirmation = makeConfirmation({
owner: makeOwner(),
status: true,
hash: 'asdf',
})
const transaction: Transaction = makeTransaction({
name: 'Buy batteries',
nonce: 1,
value: 2,
confirmations: List([firstConfirmation]),
destination: 'destAddress',
threshold: 2,
tx: '',
})
const reduxStore = {
[SAFE_REDUCER_ID]: Map(),
providers: makeProvider(),
tokens: undefined,
transactions: Map({ fooAddress: List([transaction]) }),
}
// WHEN
const transactionsEmpty = safeTransactionsSelector(reduxStore, { safeAddress: '' })
// $FlowFixMe
const transactionsUndefined = safeTransactionsSelector(reduxStore, { safeAddress: undefined })
// THEN
expect(transactionsEmpty).toEqual(List([]))
expect(transactionsUndefined).toEqual(List([]))
})
it('should return empty list if there are transactions belonging to different address', () => {
// GIVEN
const firstConfirmation: Confirmation = makeConfirmation({
owner: makeOwner(),
status: true,
hash: 'asdf',
})
const transaction: Transaction = makeTransaction({
name: 'Buy batteries',
nonce: 1,
value: 2,
confirmations: List([firstConfirmation]),
destination: 'destAddress',
threshold: 2,
tx: '',
})
const reduxStore = {
[SAFE_REDUCER_ID]: Map(),
providers: makeProvider(),
tokens: undefined,
transactions: Map({ fooAddress: List([transaction]) }),
}
// WHEN
const transactions = safeTransactionsSelector(reduxStore, { safeAddress: 'invented' })
// THEN
expect(transactions).toEqual(List([]))
})
it('should return transactions of safe', () => {
// GIVEN
const firstConfirmation: Confirmation = makeConfirmation({
owner: makeOwner(),
status: true,
hash: 'asdf',
})
const transaction: Transaction = makeTransaction({
name: 'Buy batteries',
nonce: 1,
value: 2,
confirmations: List([firstConfirmation]),
destination: 'destAddress',
threshold: 2,
tx: '',
})
const reduxStore = {
[SAFE_REDUCER_ID]: Map(),
providers: makeProvider(),
tokens: undefined,
transactions: Map({ fooAddress: List([transaction]) }),
}
// WHEN
const transactions = safeTransactionsSelector(reduxStore, { safeAddress: 'fooAddress' })
// THEN
expect(transactions).toEqual(List([transaction]))
})
})
}
export default grantedSelectorTests
*/

View File

@ -23,7 +23,7 @@ describe('DOM > Feature > Funds', () => {
accounts = await getWeb3().eth.getAccounts() accounts = await getWeb3().eth.getAccounts()
}) })
it('Sends ETH', async () => { it('Sends ETH with threshold = 1', async () => {
// GIVEN // GIVEN
const ethAmount = '5' const ethAmount = '5'
await sendEtherTo(safeAddress, ethAmount) await sendEtherTo(safeAddress, ethAmount)
@ -64,7 +64,7 @@ describe('DOM > Feature > Funds', () => {
) )
}) })
it('Sends Tokens', async () => { it('Sends Tokens with threshold = 1', async () => {
// GIVEN // GIVEN
const numTokens = '100' const numTokens = '100'
const tokenAddress = await sendTokenTo(safeAddress, numTokens) const tokenAddress = await sendTokenTo(safeAddress, numTokens)

View File

@ -1,72 +0,0 @@
// @flow
import { Map } from 'immutable'
import * as fetchTokensAction from '~/logic/tokens/store/actions/fetchTokens'
import { aNewStore } from '~/store'
import { aMinedSafe } from '~/test/builder/safe.redux.builder'
import { type Token } from '~/logic/tokens/store/model/token'
import { TOKEN_REDUCER_ID } from '~/logic/tokens/store/reducer/tokens'
import { sendEtherTo, sendTokenTo } from '~/test/utils/tokenMovements'
import { dispatchTknBalance } from '~/test/utils/transactions/moveTokens.helper'
import { ETH_ADDRESS } from '~/logic/tokens/utils/tokenHelpers'
describe('Safe - redux balance property', () => {
let store
let address: string
beforeEach(async () => {
store = aNewStore()
address = await aMinedSafe(store)
})
it('reducer should return 0 to just deployed safe', async () => {
// WHEN
await store.dispatch(fetchTokensAction.fetchTokens(address))
// THEN
const tokens: Map<string, Map<string, Token>> | typeof undefined = store.getState()[TOKEN_REDUCER_ID]
if (!tokens) throw new Error()
const safeBalances: Map<string, Token> | typeof undefined = tokens.get(address)
if (!safeBalances) throw new Error('No tokens available, probably failed to fetch')
expect(safeBalances.size).toBe(11)
// safeBalances.forEach((token: string) => {
// const record = safeBalances.get(token)
// if (!record) throw new Error()
// expect(record.get('funds')).toBe('0')
// })
})
it('reducer should return 0.03456 ETH as funds to safe with 0.03456 ETH', async () => {
// WHEN
await sendEtherTo(address, '0.03456')
await store.dispatch(fetchTokensAction.fetchTokens(address))
// THEN
const tokens: Map<string, Map<string, Token>> | typeof undefined = store.getState()[TOKEN_REDUCER_ID]
if (!tokens) throw new Error()
const safeBalances: Map<string, Token> | typeof undefined = tokens.get(address)
if (!safeBalances) throw new Error()
expect(safeBalances.size).toBe(11)
const ethBalance = safeBalances.get(ETH_ADDRESS)
if (!ethBalance) throw new Error()
expect(ethBalance.get('funds')).toBe('0.03456')
})
it('reducer should return 100 TKN when safe has 100 TKN', async () => {
// GIVEN
const numTokens = '100'
const tokenAddress = await sendTokenTo(address, numTokens)
// WHEN
await dispatchTknBalance(store, tokenAddress, address)
// THEN
const safeBalances = store.getState()[TOKEN_REDUCER_ID].get(address)
expect(safeBalances.size).toBe(1)
const tknBalance = safeBalances.get('TKN')
expect(tknBalance.get('funds')).toBe(String(numTokens))
})
})

View File

@ -1,112 +0,0 @@
// @flow
import { Map, List } from 'immutable'
import { type Safe } from '~/routes/safe/store/models/safe'
import { aNewStore } from '~/store'
import { aMinedSafe } from '~/test/builder/safe.redux.builder'
import updateSafe from '~/routes/safe/store/actions/updateSafe'
import { loadSafe } from '~/routes/load/container/Load'
import { safesMapSelector } from '~/routes/safeList/store/selectors'
import { makeOwner, type Owner } from '~/routes/safe/store/models/owner'
import { getWeb3 } from '~/logic/wallets/getWeb3'
import { safesInitialState } from '~/routes/safe/store/reducer/safe'
import { setOwners, OWNERS_KEY } from '~/utils/storage'
describe('Safe - redux load safe', () => {
let store
let address: string
let accounts
beforeEach(async () => {
store = aNewStore()
address = await aMinedSafe(store)
localStorage.clear()
accounts = await getWeb3().eth.getAccounts()
})
it('if safe is not present, store and persist it with default names', async () => {
const safeName = 'Loaded Safe'
const safeAddress = address
const updateSafeFn: any = (...args) => store.dispatch(updateSafe(...args))
await loadSafe(safeName, safeAddress, updateSafeFn)
const safes: Map<string, Safe> = safesMapSelector(store.getState())
expect(safes.size).toBe(1)
if (!safes) throw new Error()
const safe = safes.get(safeAddress)
if (!safe) throw new Error()
expect(safe.get('name')).toBe(safeName)
expect(safe.get('threshold')).toBe(1)
expect(safe.get('address')).toBe(safeAddress)
expect(safe.get('owners')).toEqual(List([makeOwner({ name: 'UNKNOWN', address: accounts[0] })]))
expect(await safesInitialState()).toEqual(safes)
})
it('if safe is not present but owners, store and persist it with stored names', async () => {
const safeName = 'Loaded Safe'
const safeAddress = address
const ownerName = 'Foo Bar Restores'
const updateSafeFn: any = (...args) => store.dispatch(updateSafe(...args))
const owner: Owner = makeOwner({ name: ownerName, address: accounts[0] })
setOwners(safeAddress, List([owner]))
await loadSafe(safeName, safeAddress, updateSafeFn)
const safes: Map<string, Safe> = safesMapSelector(store.getState())
expect(safes.size).toBe(1)
if (!safes) throw new Error()
const safe = safes.get(safeAddress)
if (!safe) throw new Error()
expect(safe.get('name')).toBe(safeName)
expect(safe.get('threshold')).toBe(1)
expect(safe.get('address')).toBe(safeAddress)
expect(safe.get('owners')).toEqual(List([makeOwner({ name: ownerName, address: accounts[0] })]))
expect(await safesInitialState()).toEqual(safes)
})
it('if safe is present but no owners, store and persist it with default names', async () => {
const safeAddress = await aMinedSafe(store)
localStorage.removeItem(`${OWNERS_KEY}-${safeAddress}`)
const safeName = 'Loaded Safe'
const updateSafeFn: any = (...args) => store.dispatch(updateSafe(...args))
await loadSafe(safeName, safeAddress, updateSafeFn)
const safes: Map<string, Safe> = safesMapSelector(store.getState())
expect(safes.size).toBe(2)
if (!safes) throw new Error()
const safe = safes.get(safeAddress)
if (!safe) throw new Error()
expect(safe.get('name')).toBe(safeName)
expect(safe.get('threshold')).toBe(1)
expect(safe.get('address')).toBe(safeAddress)
expect(safe.get('owners')).toEqual(List([makeOwner({ name: 'UNKNOWN', address: accounts[0] })]))
expect(await safesInitialState()).toEqual(safes)
})
it('if safe is present but owners, store and persist it with stored names', async () => {
const safeAddress = await aMinedSafe(store)
const safeName = 'Loaded Safe'
const updateSafeFn: any = (...args) => store.dispatch(updateSafe(...args))
await loadSafe(safeName, safeAddress, updateSafeFn)
const safes: Map<string, Safe> = safesMapSelector(store.getState())
expect(safes.size).toBe(2)
if (!safes) throw new Error()
const safe = safes.get(safeAddress)
if (!safe) throw new Error()
expect(safe.get('name')).toBe(safeName)
expect(safe.get('threshold')).toBe(1)
expect(safe.get('address')).toBe(safeAddress)
expect(safe.get('owners')).toEqual(List([makeOwner({ name: 'Adol 1 Eth Account', address: accounts[0] })]))
expect(await safesInitialState()).toEqual(safes)
})
})

View File

@ -1,237 +0,0 @@
// @flow
import { List } from 'immutable'
import { aNewStore } from '~/store'
import { getWeb3 } from '~/logic/wallets/getWeb3'
import { confirmationsTransactionSelector, safeTransactionsSelector } from '~/routes/safe/store/selectors'
import fetchTransactions from '~/routes/safe/store/actions/fetchTransactions'
import { type Safe } from '~/routes/safe/store/models/safe'
import { getGnosisSafeInstanceAt } from '~/logic/contracts/safeContracts'
import { aMinedSafe } from '~/test/builder/safe.redux.builder'
import { NAME_PARAM, OWNER_ADDRESS_PARAM, INCREASE_PARAM } from '~/routes/safe/components/AddOwner/AddOwnerForm'
import { addOwner } from '~/routes/safe/components/AddOwner/index'
import fetchSafe from '~/routes/safe/store/actions/fetchSafe'
import { removeOwner, shouldDecrease, initialValuesFrom } from '~/routes/safe/components/RemoveOwner'
import { DECREASE_PARAM } from '~/routes/safe/components/RemoveOwner/RemoveOwnerForm'
import { getSafeFrom } from '~/test/utils/safeHelper'
import { getOwnerNameBy, getOwnerAddressBy } from '~/routes/open/components/fields'
import { processTransaction } from '~/logic/safe/safeFrontendOperations'
import { allowedRemoveSenderInTxHistoryService } from '~/config'
import { calculateValuesAfterRemoving } from '~/routes/open/components/SafeOwnersForm'
describe('React DOM TESTS > Add and remove owners', () => {
const processOwnerModification = async (store, safeAddress, executor, threshold, alreadyConfirmed) => {
const reduxTransactions = safeTransactionsSelector(store.getState(), { safeAddress })
const tx = reduxTransactions.get(0)
if (!tx) throw new Error()
const confirmed = confirmationsTransactionSelector(store.getState(), { transaction: tx })
const data = tx.get('data')
expect(data).not.toBe(null)
expect(data).not.toBe(undefined)
expect(data).not.toBe('')
return processTransaction(safeAddress, tx, confirmed, executor, threshold, alreadyConfirmed)
}
const assureThresholdIs = async (gnosisSafe, threshold: number) => {
const safeThreshold = await gnosisSafe.getThreshold()
expect(Number(safeThreshold)).toEqual(threshold)
}
const assureOwnersAre = async (gnosisSafe, ...owners) => {
const safeOwners = await gnosisSafe.getOwners()
expect(safeOwners.length).toEqual(owners.length)
for (let i = 0; i < owners.length; i += 1) {
expect(safeOwners[i]).toBe(owners[i])
}
}
const getAddressesFrom = (safe: Safe) => safe.get('owners').map(owner => owner.get('address'))
it.only('creates initialValues removing last owner', () => {
const numOwners = 3
const values = {
moe: 'Bart',
[getOwnerNameBy(0)]: 'Foo',
[getOwnerAddressBy(0)]: '0x1',
[getOwnerNameBy(1)]: 'Bar',
[getOwnerAddressBy(1)]: '0x2',
[getOwnerNameBy(2)]: 'Baz',
[getOwnerAddressBy(2)]: '0x3',
}
const indexToRemove = 2
const initialValues = calculateValuesAfterRemoving(indexToRemove, numOwners, values)
expect(initialValues).toEqual({
moe: 'Bart',
[getOwnerNameBy(0)]: 'Foo',
[getOwnerAddressBy(0)]: '0x1',
[getOwnerNameBy(1)]: 'Bar',
[getOwnerAddressBy(1)]: '0x2',
})
})
it.only('creates initialValues removing middle owner', () => {
const numOwners = 3
const values = {
moe: 'Bart',
[getOwnerNameBy(0)]: 'Foo',
[getOwnerAddressBy(0)]: '0x1',
[getOwnerNameBy(1)]: 'Bar',
[getOwnerAddressBy(1)]: '0x2',
[getOwnerNameBy(2)]: 'Baz',
[getOwnerAddressBy(2)]: '0x3',
}
const indexToRemove = 1
const initialValues = calculateValuesAfterRemoving(indexToRemove, numOwners, values)
expect(initialValues).toEqual({
moe: 'Bart',
[getOwnerNameBy(0)]: 'Foo',
[getOwnerAddressBy(0)]: '0x1',
[getOwnerNameBy(1)]: 'Baz',
[getOwnerAddressBy(1)]: '0x3',
})
})
it('adds owner without increasing the threshold', async () => {
// GIVEN
const numOwners = 2
const threshold = 1
const store = aNewStore()
const address = await aMinedSafe(store, numOwners, threshold)
const accounts = await getWeb3().eth.getAccounts()
const gnosisSafe = await getGnosisSafeInstanceAt(address)
const values = {
[NAME_PARAM]: 'Adol 3 Metamask',
[OWNER_ADDRESS_PARAM]: accounts[2],
[INCREASE_PARAM]: false,
}
// WHEN
let safe = getSafeFrom(store.getState(), address)
await addOwner(values, safe, threshold, accounts[0])
// THEN
await assureThresholdIs(gnosisSafe, 1)
await assureOwnersAre(gnosisSafe, accounts[2], accounts[0], accounts[1])
await store.dispatch(fetchSafe(safe.get('address')))
safe = getSafeFrom(store.getState(), address)
expect(safe.get('owners').count()).toBe(3)
await assureOwnersAre(gnosisSafe, ...getAddressesFrom(safe))
})
it('adds owner increasing the threshold', async () => {
// GIVEN
const numOwners = 2
const threshold = 1
const store = aNewStore()
const address = await aMinedSafe(store, numOwners, threshold)
const accounts = await getWeb3().eth.getAccounts()
const gnosisSafe = await getGnosisSafeInstanceAt(address)
const values = {
[NAME_PARAM]: 'Adol 3 Metamask',
[OWNER_ADDRESS_PARAM]: accounts[2],
[INCREASE_PARAM]: true,
}
// WHEN
let safe = getSafeFrom(store.getState(), address)
await addOwner(values, safe, threshold, accounts[0])
// THEN
await assureThresholdIs(gnosisSafe, 2)
await assureOwnersAre(gnosisSafe, accounts[2], accounts[0], accounts[1])
await store.dispatch(fetchSafe(safe.get('address')))
safe = getSafeFrom(store.getState(), address)
expect(safe.get('owners').count()).toBe(3)
await assureOwnersAre(gnosisSafe, ...getAddressesFrom(safe))
})
it('remove owner decreasing owner automatically', async () => {
if (!allowedRemoveSenderInTxHistoryService()) {
return
}
const numOwners = 2
const threshold = 2
const store = aNewStore()
const address = await aMinedSafe(store, numOwners, threshold)
const accounts = await getWeb3().eth.getAccounts()
const gnosisSafe = await getGnosisSafeInstanceAt(address)
const decrease = shouldDecrease(numOwners, threshold)
const values = initialValuesFrom(decrease)
expect(values[DECREASE_PARAM]).toBe(true)
let safe = getSafeFrom(store.getState(), address)
await removeOwner(values, safe, threshold, accounts[1], 'Adol Metamask 2', accounts[0])
await store.dispatch(fetchTransactions(address))
await processOwnerModification(store, address, accounts[1], 2, List([accounts[0]]))
await assureThresholdIs(gnosisSafe, 1)
await assureOwnersAre(gnosisSafe, accounts[0])
await store.dispatch(fetchSafe(safe.get('address')))
safe = getSafeFrom(store.getState(), address)
expect(safe.get('owners').count()).toBe(1)
await assureOwnersAre(gnosisSafe, ...getAddressesFrom(safe))
})
it('remove owner decreasing threshold', async () => {
const numOwners = 3
const threshold = 2
const store = aNewStore()
const address = await aMinedSafe(store, numOwners, threshold)
const accounts = await getWeb3().eth.getAccounts()
const gnosisSafe = await getGnosisSafeInstanceAt(address)
const decrease = true
const values = initialValuesFrom(decrease)
let safe = getSafeFrom(store.getState(), address)
await removeOwner(values, safe, threshold, accounts[2], 'Adol Metamask 3', accounts[0])
await store.dispatch(fetchTransactions(address))
await processOwnerModification(store, address, accounts[1], 2, List([accounts[0]]))
await assureThresholdIs(gnosisSafe, 1)
await assureOwnersAre(gnosisSafe, accounts[0], accounts[1])
await store.dispatch(fetchSafe(safe.get('address')))
safe = getSafeFrom(store.getState(), address)
expect(safe.get('owners').count()).toBe(2)
await assureOwnersAre(gnosisSafe, ...getAddressesFrom(safe))
})
it('remove owner without decreasing threshold', async () => {
const numOwners = 3
const threshold = 2
const store = aNewStore()
const address = await aMinedSafe(store, numOwners, threshold)
const accounts = await getWeb3().eth.getAccounts()
const gnosisSafe = await getGnosisSafeInstanceAt(address)
const decrease = shouldDecrease(numOwners, threshold)
const values = initialValuesFrom(decrease)
expect(values[DECREASE_PARAM]).toBe(false)
let safe = getSafeFrom(store.getState(), address)
await removeOwner(values, safe, threshold, accounts[2], 'Adol Metamask 3', accounts[0])
await store.dispatch(fetchTransactions(address))
await processOwnerModification(store, address, accounts[1], 2, List([accounts[0]]))
await assureThresholdIs(gnosisSafe, 2)
await assureOwnersAre(gnosisSafe, accounts[0], accounts[1])
await store.dispatch(fetchSafe(safe.get('address')))
safe = getSafeFrom(store.getState(), address)
expect(safe.get('owners').count()).toBe(2)
await assureOwnersAre(gnosisSafe, ...getAddressesFrom(safe))
})
})

View File

@ -1,178 +0,0 @@
// @flow
import { List } from 'immutable'
import { createTransaction } from '~/logic/safe/safeFrontendOperations'
import { getGnosisSafeInstanceAt } from '~/logic/contracts/safeContracts'
import { type Safe } from '~/routes/safe/store/models/safe'
import { makeOwner } from '~/routes/safe/store/models/owner'
import fetchTransactions from '~/routes/safe/store/actions/fetchTransactions'
import { makeConfirmation } from '~/routes/safe/store/models/confirmation'
import { aNewStore } from '~/store'
import { aMinedSafe } from '~/test/builder/safe.redux.builder'
import { getSafeFrom } from '~/test/utils/safeHelper'
import { getWeb3 } from '~/logic/wallets/getWeb3'
import { safeTransactionsSelector } from '~/routes/safe/store/selectors'
import fetchSafe from '~/routes/safe/store/actions/fetchSafe'
import { testTransactionFrom, testSizeOfTransactions } from './utils/historyServiceHelper'
describe('Transactions Suite', () => {
let store: Store
let safeAddress: string
let accounts: string[]
beforeAll(async () => {
accounts = await getWeb3().eth.getAccounts()
})
beforeEach(async () => {
localStorage.clear()
store = aNewStore()
safeAddress = await aMinedSafe(store)
})
it('retrieves tx info from service having subject available', async () => {
let safe: Safe = getSafeFrom(store.getState(), safeAddress)
const gnosisSafe = await getGnosisSafeInstanceAt(safeAddress)
const firstTxData = gnosisSafe.contract.methods.addOwnerWithThreshold(accounts[1], 2).encodeABI()
const executor = accounts[0]
const nonce = await gnosisSafe.nonce()
const firstTxHash = await createTransaction(
safe,
'Add Owner Second account',
safeAddress,
'0',
nonce,
executor,
firstTxData,
)
await store.dispatch(fetchSafe(safe.get('address')))
safe = getSafeFrom(store.getState(), safeAddress)
const secondTxData = gnosisSafe.contract.methods.addOwnerWithThreshold(accounts[2], 2).encodeABI()
const secondTxHash = await createTransaction(
safe,
'Add Owner Third account',
safeAddress,
'0',
nonce + 100,
executor,
secondTxData,
)
await store.dispatch(fetchSafe(safe.get('address')))
safe = getSafeFrom(store.getState(), safeAddress)
// WHEN
await store.dispatch(fetchTransactions(safeAddress))
let transactions = safeTransactionsSelector(store.getState(), { safeAddress })
testSizeOfTransactions(transactions, 2)
// THEN
const firstTxConfirmations = List([
makeConfirmation({
owner: makeOwner({ address: getWeb3().toChecksumAddress(executor), name: 'Adol 1 Eth Account' }),
type: 'execution',
hash: firstTxHash,
}),
])
testTransactionFrom(
transactions,
0,
'Add Owner Second account',
nonce,
0,
safeAddress,
firstTxData,
true,
firstTxConfirmations,
)
const secondTxConfirmations = List([
makeConfirmation({
owner: makeOwner({ address: getWeb3().toChecksumAddress(accounts[0]), name: 'Adol 1 Eth Account' }),
type: 'confirmation',
hash: secondTxHash,
}),
])
testTransactionFrom(
transactions,
1,
'Add Owner Third account',
nonce + 100,
0,
safeAddress,
secondTxData,
false,
secondTxConfirmations,
)
localStorage.clear()
await store.dispatch(fetchTransactions(safeAddress))
transactions = safeTransactionsSelector(store.getState(), { safeAddress })
testSizeOfTransactions(transactions, 2)
const firstTxConfWithoutStorage = List([
makeConfirmation({
owner: makeOwner({ address: getWeb3().toChecksumAddress(executor), name: 'UNKNOWN' }),
type: 'execution',
hash: firstTxHash,
}),
])
testTransactionFrom(transactions, 0, 'Unknown', nonce, 0, safeAddress, firstTxData, true, firstTxConfWithoutStorage)
const secondTxConfWithoutStorage = List([
makeConfirmation({
owner: makeOwner({ address: getWeb3().toChecksumAddress(executor), name: 'UNKNOWN' }),
type: 'confirmation',
hash: secondTxHash,
}),
])
testTransactionFrom(
transactions,
1,
'Unknown',
nonce + 100,
0,
safeAddress,
secondTxData,
false,
secondTxConfWithoutStorage,
)
})
it('returns empty list of trnsactions when safe is not configured', async () => {
// routes/safe/transactions.selector.js the 4 cases
// confirmations.selector.js the last one
})
it('pending transactions are treated correctly', async () => {
// create a safe 3 owners 3 threshold
// create a tx adding 4th owner
// confirm tx and check on every step
})
it('returns count of confirmed but not executed txs', async () => {
// pendingTransactionSelector
})
it('returns count of executed txs', async () => {
// confirmationsTransactionSelector
})
it('returns correctly transaction list when safe is not available', async () => {
// routes/safe/test/transactions.selector.js
})
it('process only updated txs', async () => {
// Basically I would like when I call the GET TXs endpoint to retrieve those transactions ORDERED based on
// when they have been updated (just created, or just added another extra confirmation).
// In that way I do not need to parse and threat all txs in client side and also we mitigate the risk of
// do not get old txs updates. For doing that I would need to keep stored a number indicating
// if the tx has been updated in DB.
// For instance:
/*
create tx1 ---> [{ tx:1, updated: 1 }]
create tx2 ---> [{ tx:2, updated: 1 }, { tx:1, updated: 1 }]
user 2 confirms tx1 ---> [{ tx:1, updated: 2 }, { tx:2, updated: 1 }]
In that way I keep stored tx1 -> 1 and if I see tx2 -> 2 I do not skip it
*/
})
})

View File

@ -1,64 +0,0 @@
// @flow
import { getWeb3 } from '~/logic/wallets/getWeb3'
import { type Match } from 'react-router-dom'
import { getFirstTokenContract, getSecondTokenContract } from '~/test/utils/tokenMovements'
import { aNewStore } from '~/store'
import { aMinedSafe } from '~/test/builder/safe.redux.builder'
import { renderSafeView } from '~/test/builder/safe.dom.utils'
import { buildMathPropsFrom } from '~/test/utils/buildReactRouterProps'
import { testToken } from '~/test/builder/tokens.dom.utils'
import * as fetchTokensModule from '~/logic/tokens/store/actions/fetchTokens'
import * as enhancedFetchModule from '~/utils/fetch'
import addToken from '~/logic/tokens/store/actions/addToken'
describe('DOM > Feature > Add new ERC 20 Tokens', () => {
// let web3
// let accounts
// let firstErc20Token
// let secondErc20Token
// beforeAll(async () => {
// web3 = getWeb3()
// accounts = await web3.eth.getAccounts()
// firstErc20Token = await getFirstTokenContract(web3, accounts[0])
// secondErc20Token = await getSecondTokenContract(web3, accounts[0])
// // $FlowFixMe
// enhancedFetchModule.enhancedFetch = jest.fn()
// enhancedFetchModule.enhancedFetch.mockImplementation(() => Promise.resolve({
// results: [
// {
// address: firstErc20Token.address,
// name: 'First Token Example',
// symbol: 'FTE',
// decimals: 18,
// logoUri: 'https://upload.wikimedia.org/wikipedia/commons/c/c0/Earth_simple_icon.png',
// },
// ],
// }))
// })
// it('persist added custom ERC 20 tokens as active when reloading the page', async () => {
// // GIVEN
// const store = aNewStore()
// const safeAddress = await aMinedSafe(store)
// await store.dispatch(fetchTokensModule.fetchTokens(safeAddress))
// const values = {
// [TOKEN_ADRESS_PARAM]: secondErc20Token.address,
// [TOKEN_NAME_PARAM]: 'Custom ERC20 Token',
// [TOKEN_SYMBOL_PARAM]: 'CTS',
// [TOKEN_DECIMALS_PARAM]: '10',
// [TOKEN_LOGO_URL_PARAM]: 'https://example.com',
// }
// const customAddTokensFn: any = (...args) => store.dispatch(addToken(...args))
// await addTokenFnc(values, customAddTokensFn, safeAddress)
// renderSafeView(store, safeAddress)
// // WHEN
// const reloadedStore = aNewStore()
// await reloadedStore.dispatch(fetchTokensModule.fetchTokens(safeAddress))
// renderSafeView(reloadedStore, safeAddress) // reload
// // THEN
// const match: Match = buildMathPropsFrom(safeAddress)
// const activeTokenList = activeTokensSelector(reloadedStore.getState(), { match })
// expect(activeTokenList.count()).toBe(2)
// testToken(activeTokenList.get(0), 'CTS', true)
// testToken(activeTokenList.get(1), 'ETH', true)
// })
})

View File

@ -1,83 +0,0 @@
// @flow
import { getWeb3 } from '~/logic/wallets/getWeb3'
import { type Match } from 'react-router-dom'
import { getFirstTokenContract, getSecondTokenContract } from '~/test/utils/tokenMovements'
import { aNewStore } from '~/store'
import { aMinedSafe } from '~/test/builder/safe.redux.builder'
import { renderSafeView } from '~/test/builder/safe.dom.utils'
import { buildMathPropsFrom } from '~/test/utils/buildReactRouterProps'
import { testToken } from '~/test/builder/tokens.dom.utils'
import * as fetchTokensModule from '~/logic/tokens/store/actions/fetchTokens'
import * as enhancedFetchModule from '~/utils/fetch'
import addToken from '~/logic/tokens/store/actions/addToken'
import removeTokenAction from '~/logic/tokens/store/actions/removeToken'
import { makeToken } from '~/logic/tokens/store/model/token'
describe('DOM > Feature > Add new ERC 20 Tokens', () => {
// let web3
// let accounts
// let firstErc20Token
// let secondErc20Token
// beforeAll(async () => {
// web3 = getWeb3()
// accounts = await web3.eth.getAccounts()
// firstErc20Token = await getFirstTokenContract(web3, accounts[0])
// secondErc20Token = await getSecondTokenContract(web3, accounts[0])
// // $FlowFixMe
// enhancedFetchModule.enhancedFetch = jest.fn()
// enhancedFetchModule.enhancedFetch.mockImplementation(() => Promise.resolve({
// results: [
// {
// address: firstErc20Token.address,
// name: 'First Token Example',
// symbol: 'FTE',
// decimals: 18,
// logoUri: 'https://upload.wikimedia.org/wikipedia/commons/c/c0/Earth_simple_icon.png',
// },
// ],
// }))
// })
// const checkTokensOf = (store: Store, safeAddress: string) => {
// const match: Match = buildMathPropsFrom(safeAddress)
// const activeTokenList = activeTokensSelector(store.getState(), { match })
// expect(activeTokenList.count()).toBe(1)
// testToken(activeTokenList.get(0), 'ETH', true)
// const tokenList = tokenListSelector(store.getState(), { match })
// expect(tokenList.count()).toBe(2)
// testToken(tokenList.get(0), 'FTE', false)
// testToken(tokenList.get(1), 'ETH', true)
// }
// it('removes custom ERC 20 including page reload', async () => {
// // GIVEN
// const store = aNewStore()
// const safeAddress = await aMinedSafe(store)
// await store.dispatch(fetchTokensModule.fetchTokens(safeAddress))
// const values = {
// [TOKEN_ADRESS_PARAM]: secondErc20Token.address,
// [TOKEN_NAME_PARAM]: 'Custom ERC20 Token',
// [TOKEN_SYMBOL_PARAM]: 'CTS',
// [TOKEN_DECIMALS_PARAM]: '10',
// [TOKEN_LOGO_URL_PARAM]: 'https://example.com',
// }
// const customAddTokensFn: any = (...args) => store.dispatch(addToken(...args))
// await addTokenFnc(values, customAddTokensFn, safeAddress)
// const token = makeToken({
// address: secondErc20Token.address,
// name: 'Custom ERC20 Token',
// symbol: 'CTS',
// decimals: 10,
// logoUri: 'https://example.com',
// status: true,
// removable: true,
// })
// const customRemoveTokensFnc: any = (...args) => store.dispatch(removeTokenAction(...args))
// await removeToken(safeAddress, token, customRemoveTokensFnc)
// checkTokensOf(store, safeAddress)
// // WHEN
// const reloadedStore = aNewStore()
// await reloadedStore.dispatch(fetchTokensModule.fetchTokens(safeAddress))
// renderSafeView(reloadedStore, safeAddress) // reload
// // THEN
// checkTokensOf(reloadedStore, safeAddress)
// })
})