add a test for adding custom token

This commit is contained in:
Mikhail Mikheev 2019-06-05 15:52:15 +04:00
parent 4b0cac5eb0
commit 4625ed1aa5
9 changed files with 108 additions and 69 deletions

View File

@ -29,6 +29,7 @@ class TextField extends React.PureComponent<TextFieldProps> {
text,
inputAdornment,
classes,
testId,
...rest
} = this.props
const helperText = value ? text : undefined
@ -36,7 +37,7 @@ class TextField extends React.PureComponent<TextFieldProps> {
const underline = meta.active || (meta.visited && !meta.valid)
const inputRoot = helperText ? classes.root : undefined
const inputProps = { ...restInput, autoComplete: 'off' }
const inputProps = { ...restInput, autoComplete: 'off', 'data-testid': testId }
const inputRootProps = { ...inputAdornment, disableUnderline: !underline, className: inputRoot }
return (
@ -51,6 +52,7 @@ class TextField extends React.PureComponent<TextFieldProps> {
inputProps={inputProps}
onChange={onChange}
value={value}
// data-testid={testId}
/>
)
}

View File

@ -12,6 +12,7 @@ const styles = {
type Props = {
minWidth?: number,
minHeight?: number,
testId: string,
}
const calculateStyleBased = (minWidth, minHeight) => ({
@ -19,10 +20,10 @@ const calculateStyleBased = (minWidth, minHeight) => ({
minHeight: minHeight && `${minHeight}px`,
})
const GnoButton = ({ minWidth, minHeight, ...props }: Props) => {
const GnoButton = ({ minWidth, minHeight, testId = '', ...props }: Props) => {
const style = calculateStyleBased(minWidth, minHeight)
return <Button style={style} {...props} />
return <Button style={style} data-testid={testId} {...props} />
}
export default withStyles(styles)(GnoButton)

View File

@ -1,6 +1,5 @@
// @flow
/* eslint-disable react/button-has-type */
/* eslint-disable react/default-props-match-prop-types */
import * as React from 'react'
import cn from 'classnames/bind'
import styles from './index.scss'
@ -12,20 +11,16 @@ type Props = {
size?: 'sm' | 'md' | 'lg' | 'xl' | 'xxl',
weight?: 'light' | 'regular' | 'bolder' | 'bold',
color?: 'soft' | 'medium' | 'dark' | 'white' | 'fancy' | 'primary' | 'secondary' | 'warning' | 'disabled',
testId?: string,
}
const GnoButtonLink = ({
type, size, weight, color, ...props
}: Props) => (
<button type={type} className={cx(styles.btnLink, size, color, weight)} {...props} />
)
GnoButtonLink.defaultProps = {
type: 'button',
size: 'md',
weight: 'regular',
color: 'secondary',
}
type = 'button',
size = 'md',
weight = 'regular',
color = 'secondary',
testId = '',
...props
}: Props) => <button type={type} className={cx(styles.btnLink, size, color, weight)} data-testid={testId} {...props} />
export default GnoButtonLink

View File

@ -23,6 +23,11 @@ import { addressIsTokenContract, doesntExistInTokenList } from './validators'
import { styles } from './style'
import { getSymbolAndDecimalsFromContract } from './utils'
export const ADD_CUSTOM_TOKEN_ADDRESS_INPUT_TEST_ID = 'add-custom-token-address-input'
export const ADD_CUSTOM_TOKEN_SYMBOLS_INPUT_TEST_ID = 'add-custom-token-symbols-input'
export const ADD_CUSTOM_TOKEN_DECIMALS_INPUT_TEST_ID = 'add-custom-token-decimals-input'
export const ADD_CUSTOM_TOKEN_FORM = 'add-custom-token-form'
type Props = {
classes: Object,
addToken: Function,
@ -115,7 +120,7 @@ const AddCustomToken = (props: Props) => {
return (
<React.Fragment>
<GnoForm onSubmit={handleSubmit} initialValues={formValues}>
<GnoForm onSubmit={handleSubmit} initialValues={formValues} testId={ADD_CUSTOM_TOKEN_FORM}>
{() => (
<React.Fragment>
<Block className={classes.formContainer}>
@ -135,6 +140,7 @@ const AddCustomToken = (props: Props) => {
placeholder="Token contract address*"
text="Token contract address*"
className={classes.addressInput}
testId={ADD_CUSTOM_TOKEN_ADDRESS_INPUT_TEST_ID}
/>
<FormSpy
subscription={{
@ -156,6 +162,7 @@ const AddCustomToken = (props: Props) => {
placeholder="Token symbol*"
text="Token symbol"
className={classes.addressInput}
testId={ADD_CUSTOM_TOKEN_SYMBOLS_INPUT_TEST_ID}
/>
<Field
name="decimals"
@ -165,6 +172,7 @@ const AddCustomToken = (props: Props) => {
placeholder="Token decimals*"
text="Token decimals*"
className={classes.addressInput}
testId={ADD_CUSTOM_TOKEN_DECIMALS_INPUT_TEST_ID}
/>
<Block align="left">
<Field name="showForAllSafes" component={Checkbox} type="checkbox" className={classes.checkbox} />

View File

@ -24,6 +24,8 @@ import { type Token } from '~/logic/tokens/store/model/token'
import { setImageToPlaceholder } from '~/routes/safe/components/Balances/utils'
import { styles } from './style'
export const ADD_CUSTOM_TOKEN_BUTTON_TEST_ID = 'add-custom-token-btn'
type Props = {
classes: Object,
tokens: List<Token>,
@ -141,6 +143,7 @@ class Tokens extends React.Component<Props, State> {
color="secondary"
className={classes.add}
onClick={switchToAddCustomTokenScreen}
testId={ADD_CUSTOM_TOKEN_BUTTON_TEST_ID}
>
+ ADD CUSTOM TOKEN
</Button>

View File

@ -26,6 +26,9 @@ import SendModal from './SendModal'
import Receive from './Receive'
import { styles } from './style'
export const MANAGE_TOKENS_BUTTON_TEST_ID = 'manage-tokens-btn'
export const BALANCE_ROW_TEST_ID = 'balance-row'
type State = {
hideZero: boolean,
showToken: boolean,
@ -128,7 +131,7 @@ class Balances extends React.Component<Props, State> {
<Paragraph className={classes.zero}>Hide zero balances</Paragraph>
</Col>
<Col xs={6} end="sm">
<ButtonLink onClick={this.onShow('Token')}>Manage Tokens</ButtonLink>
<ButtonLink onClick={this.onShow('Token')} testId="manage-tokens-btn">Manage Tokens</ButtonLink>
<Modal
title="Manage Tokens"
description="Enable and disable tokens to be listed"
@ -153,7 +156,7 @@ class Balances extends React.Component<Props, State> {
defaultFixed
>
{(sortedData: Array<BalanceRow>) => sortedData.map((row: any, index: number) => (
<TableRow tabIndex={-1} key={index} className={classes.hide} data-testid="balance-row">
<TableRow tabIndex={-1} key={index} className={classes.hide} data-testid={BALANCE_ROW_TEST_ID}>
{autoColumns.map((column: Column) => (
<TableCell key={column.id} style={cellWidth(column.width)} align={column.align} component="td">
{column.id === BALANCE_TABLE_ASSET_ID ? <AssetTableCell asset={row[column.id]} /> : row[column.id]}

View File

@ -13,6 +13,7 @@ import { calculateBalanceOf } from '~/routes/safe/store/actions/fetchTokenBalanc
import updateActiveTokens from '~/routes/safe/store/actions/updateActiveTokens'
import 'jest-dom/extend-expect'
import updateSafe from '~/routes/safe/store/actions/updateSafe'
import { BALANCE_ROW_TEST_ID } from '~/routes/safe/components/Balances'
afterEach(cleanup)
@ -37,7 +38,7 @@ describe('DOM > Feature > Funds', () => {
await sleep(1300)
// Open send funds modal
const balanceRows = SafeDom.getAllByTestId('balance-row')
const balanceRows = SafeDom.getAllByTestId(BALANCE_ROW_TEST_ID)
expect(balanceRows[0]).toHaveTextContent(`${ethAmount} ETH`)
const sendButton = SafeDom.getByTestId('balance-send-btn')
fireEvent.click(sendButton)
@ -91,7 +92,7 @@ describe('DOM > Feature > Funds', () => {
await sleep(1000)
// Open send funds modal
const balanceRows = SafeDom.getAllByTestId('balance-row')
const balanceRows = SafeDom.getAllByTestId(BALANCE_ROW_TEST_ID)
expect(balanceRows.length).toBe(2)
const sendButtons = SafeDom.getAllByTestId('balance-send-btn')
expect(sendButtons.length).toBe(2)

View File

@ -1,65 +1,83 @@
// @flow
import { getWeb3 } from '~/logic/wallets/getWeb3'
import { type Match } from 'react-router-dom'
import { getFirstTokenContract, getSecondTokenContract } from '~/test/utils/tokenMovements'
import { fireEvent } from '@testing-library/react'
import { getFirstTokenContract } from '~/test/utils/tokenMovements'
import { aNewStore } from '~/store'
import { aMinedSafe } from '~/test/builder/safe.redux.builder'
import { travelToTokens } from '~/test/builder/safe.dom.utils'
import { renderSafeView } from '~/test/builder/safe.dom.utils'
import { sleep } from '~/utils/timer'
import { buildMatchPropsFrom } from '~/test/utils/buildReactRouterProps'
import { tokenListSelector } from '~/logic/tokens/store/selectors'
import { testToken } from '~/test/builder/tokens.dom.utils'
import { clickOnManageTokens, clickOnAddCustomToken } from '~/test/utils/DOMNavigation'
import * as fetchTokensModule from '~/logic/tokens/store/actions/fetchTokens'
import * as enhancedFetchModule from '~/utils/fetch'
import {
ADD_CUSTOM_TOKEN_ADDRESS_INPUT_TEST_ID,
ADD_CUSTOM_TOKEN_SYMBOLS_INPUT_TEST_ID,
ADD_CUSTOM_TOKEN_DECIMALS_INPUT_TEST_ID,
ADD_CUSTOM_TOKEN_FORM,
} from '~/routes/safe/components/Balances/Tokens/screens/AddCustomToken'
import { BALANCE_ROW_TEST_ID } from '~/routes/safe/components/Balances/'
import 'jest-dom/extend-expect'
describe('DOM > Feature > Add new ERC 20 Tokens', () => {
// https://github.com/testing-library/@testing-library/react/issues/281
const originalError = console.error
beforeAll(() => {
console.error = (...args) => {
if (/Warning.*not wrapped in act/.test(args[0])) {
return
}
originalError.call(console, ...args)
}
})
afterAll(() => {
console.error = originalError
})
describe('DOM > Feature > Add custom ERC 20 Tokens', () => {
let web3
let accounts
let firstErc20Token
let secondErc20Token
let erc20Token
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',
},
],
}))
erc20Token = await getFirstTokenContract(web3, accounts[0])
})
it('adds a second erc 20 token filling the form', async () => {
it('adds and displays an erc 20 token after filling the form', async () => {
// GIVEN
const store = aNewStore()
const safeAddress = await aMinedSafe(store)
await store.dispatch(fetchTokensModule.fetchTokens(safeAddress))
const TokensDom = await travelToTokens(store, safeAddress)
await store.dispatch(fetchTokensModule.fetchTokens())
const TokensDom = renderSafeView(store, safeAddress)
await sleep(400)
const tokens = TestUtils.scryRenderedComponentsWithType(TokensDom, TokenComponent)
expect(tokens.length).toBe(2)
testToken(tokens[0].props.token, 'FTE', false)
testToken(tokens[1].props.token, 'ETH', true)
// WHEN
await clickOnAddToken(TokensDom)
await fillAddress(TokensDom, secondErc20Token)
await fillHumanReadableInfo(TokensDom)
// THEN
const match: Match = buildMathPropsFrom(safeAddress)
const tokenList = tokenListSelector(store.getState(), { match })
expect(tokenList.count()).toBe(3)
testToken(tokenList.get(0), 'FTE', false)
testToken(tokenList.get(1), 'ETH', true)
testToken(tokenList.get(2), 'TKN', true)
clickOnManageTokens(TokensDom)
clickOnAddCustomToken(TokensDom)
await sleep(200)
// Fill address
const addTokenForm = TokensDom.getByTestId(ADD_CUSTOM_TOKEN_FORM)
const addressInput = TokensDom.getByTestId(ADD_CUSTOM_TOKEN_ADDRESS_INPUT_TEST_ID)
fireEvent.change(addressInput, { target: { value: erc20Token.address } })
await sleep(500)
// Check if it loaded symbol/decimals correctly
const symbolInput = TokensDom.getByTestId(ADD_CUSTOM_TOKEN_SYMBOLS_INPUT_TEST_ID)
const decimalsInput = TokensDom.getByTestId(ADD_CUSTOM_TOKEN_DECIMALS_INPUT_TEST_ID)
const tokenSymbol = await erc20Token.symbol()
const tokenDecimals = await erc20Token.decimals()
expect(symbolInput.value).toBe(tokenSymbol)
expect(decimalsInput.value).toBe(tokenDecimals.toString())
// Submit form
fireEvent.submit(addTokenForm)
await sleep(300)
// check if token is displayed
const balanceRows = TokensDom.getAllByTestId(BALANCE_ROW_TEST_ID)
expect(balanceRows.length).toBe(2)
expect(balanceRows[1]).toHaveTextContent(tokenSymbol)
})
})

View File

@ -1,8 +1,16 @@
// @flow
import { fireEvent } from '@testing-library/reactß'
import { fireEvent } from '@testing-library/react'
import { MANAGE_TOKENS_BUTTON_TEST_ID } from '~/routes/safe/components/Balances'
import { ADD_CUSTOM_TOKEN_BUTTON_TEST_ID } from '~/routes/safe/components/Balances/Tokens/screens/TokenList'
const clickOnManageTokens = (dom) => {
const btn = dom.findByTestId()
export const clickOnManageTokens = (dom: any): void => {
const btn = dom.getByTestId(MANAGE_TOKENS_BUTTON_TEST_ID)
}
fireEvent.click(btn)
}
export const clickOnAddCustomToken = (dom: any): void => {
const btn = dom.getByTestId(ADD_CUSTOM_TOKEN_BUTTON_TEST_ID)
fireEvent.click(btn)
}