remove implementation tests for now
This commit is contained in:
parent
bf174d6f94
commit
6523a25c9b
|
@ -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
|
|
||||||
*/
|
|
|
@ -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
|
|
|
@ -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
|
|
||||||
*/
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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()
|
|
||||||
})
|
|
|
@ -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
|
|
||||||
*/
|
|
|
@ -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)
|
||||||
|
|
|
@ -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))
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -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)
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -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))
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -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
|
|
||||||
*/
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -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)
|
|
||||||
// })
|
|
||||||
})
|
|
|
@ -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)
|
|
||||||
// })
|
|
||||||
})
|
|
Loading…
Reference in New Issue