mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 01:39:44 +01:00
Created "Token details" page (#13216)
* Created new screen/page "Token details" * Change color in scss * Modify elements to the latest requirements and added unit tests * Review requested changes * Condensing files into one component * Added unit tests for token details page * Added redirection when switching networks, added image for a token and update unit tests * Requested review changes * Modify index.scss regarding of the requested review * Delete data-testid's from Typography and token-details-page.js * Requested review changes
This commit is contained in:
parent
3735a601d9
commit
2cd242252f
12
app/_locales/en/messages.json
generated
12
app/_locales/en/messages.json
generated
@ -1360,6 +1360,9 @@
|
||||
"hide": {
|
||||
"message": "Hide"
|
||||
},
|
||||
"hideToken": {
|
||||
"message": "Hide token"
|
||||
},
|
||||
"hideTokenPrompt": {
|
||||
"message": "Hide Token?"
|
||||
},
|
||||
@ -1833,6 +1836,9 @@
|
||||
"negativeETH": {
|
||||
"message": "Can not send negative amounts of ETH."
|
||||
},
|
||||
"network": {
|
||||
"message": "Network:"
|
||||
},
|
||||
"networkDetails": {
|
||||
"message": "Network Details"
|
||||
},
|
||||
@ -3275,6 +3281,12 @@
|
||||
"tokenDecimalFetchFailed": {
|
||||
"message": "Token decimal required."
|
||||
},
|
||||
"tokenDecimalTitle": {
|
||||
"message": "Token Decimal:"
|
||||
},
|
||||
"tokenDetails": {
|
||||
"message": "Token details"
|
||||
},
|
||||
"tokenDetectionAnnouncement": {
|
||||
"message": "New! Improved token detection is available on Ethereum Mainnet as an experimental feature. $1"
|
||||
},
|
||||
|
@ -4,10 +4,12 @@ import { connect } from 'react-redux';
|
||||
import * as actions from '../../../../store/actions';
|
||||
import Identicon from '../../../ui/identicon';
|
||||
import Button from '../../../ui/button';
|
||||
import { DEFAULT_ROUTE } from '../../../../helpers/constants/routes';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
token: state.appState.modal.modalState.props.token,
|
||||
history: state.appState.modal.modalState.props.history,
|
||||
};
|
||||
}
|
||||
|
||||
@ -35,12 +37,13 @@ class HideTokenConfirmationModal extends Component {
|
||||
address: PropTypes.string,
|
||||
image: PropTypes.string,
|
||||
}),
|
||||
history: PropTypes.object,
|
||||
};
|
||||
|
||||
state = {};
|
||||
|
||||
render() {
|
||||
const { token, hideToken, hideModal } = this.props;
|
||||
const { token, hideToken, hideModal, history } = this.props;
|
||||
const { symbol, address, image } = token;
|
||||
|
||||
return (
|
||||
@ -72,7 +75,10 @@ class HideTokenConfirmationModal extends Component {
|
||||
type="primary"
|
||||
className="hide-token-confirmation__button"
|
||||
data-testid="hide-token-confirmation__hide"
|
||||
onClick={() => hideToken(address)}
|
||||
onClick={() => {
|
||||
hideToken(address);
|
||||
history.push(DEFAULT_ROUTE);
|
||||
}}
|
||||
>
|
||||
{this.context.t('hide')}
|
||||
</Button>
|
||||
|
@ -28,6 +28,7 @@ const NEW_ACCOUNT_ROUTE = '/new-account';
|
||||
const IMPORT_ACCOUNT_ROUTE = '/new-account/import';
|
||||
const CONNECT_HARDWARE_ROUTE = '/new-account/connect';
|
||||
const SEND_ROUTE = '/send';
|
||||
const TOKEN_DETAILS = '/token-details';
|
||||
const CONNECT_ROUTE = '/connect';
|
||||
const CONNECT_CONFIRM_PERMISSIONS_ROUTE = '/confirm-permissions';
|
||||
///: BEGIN:ONLY_INCLUDE_IN(flask)
|
||||
@ -123,6 +124,7 @@ const PATH_NAME_MAP = {
|
||||
[IMPORT_ACCOUNT_ROUTE]: 'Import Account Page',
|
||||
[CONNECT_HARDWARE_ROUTE]: 'Connect Hardware Wallet Page',
|
||||
[SEND_ROUTE]: 'Send Page',
|
||||
[TOKEN_DETAILS]: 'Token Details Page',
|
||||
[`${CONNECT_ROUTE}/:id`]: 'Connect To Site Confirmation Page',
|
||||
[`${CONNECT_ROUTE}/:id${CONNECT_CONFIRM_PERMISSIONS_ROUTE}`]: 'Grant Connected Site Permissions Confirmation Page',
|
||||
[CONNECTED_ROUTE]: 'Sites Connected To This Account Page',
|
||||
@ -181,6 +183,7 @@ export {
|
||||
IMPORT_ACCOUNT_ROUTE,
|
||||
CONNECT_HARDWARE_ROUTE,
|
||||
SEND_ROUTE,
|
||||
TOKEN_DETAILS,
|
||||
INITIALIZE_ROUTE,
|
||||
INITIALIZE_WELCOME_ROUTE,
|
||||
INITIALIZE_UNLOCK_ROUTE,
|
||||
|
@ -8,6 +8,7 @@ const AssetOptions = ({
|
||||
onRemove,
|
||||
onClickBlockExplorer,
|
||||
onViewAccountDetails,
|
||||
onViewTokenDetails,
|
||||
tokenSymbol,
|
||||
isNativeAsset,
|
||||
isEthNetwork,
|
||||
@ -66,6 +67,18 @@ const AssetOptions = ({
|
||||
{t('hideTokenSymbol', [tokenSymbol])}
|
||||
</MenuItem>
|
||||
)}
|
||||
{isNativeAsset ? null : (
|
||||
<MenuItem
|
||||
iconClassName="fas fa-info-circle asset-options__icon"
|
||||
data-testid="asset-options__token-details"
|
||||
onClick={() => {
|
||||
setAssetOptionsOpen(false);
|
||||
onViewTokenDetails();
|
||||
}}
|
||||
>
|
||||
{t('tokenDetails')}
|
||||
</MenuItem>
|
||||
)}
|
||||
</Menu>
|
||||
) : null}
|
||||
</>
|
||||
@ -78,6 +91,7 @@ AssetOptions.propTypes = {
|
||||
onRemove: PropTypes.func.isRequired,
|
||||
onClickBlockExplorer: PropTypes.func.isRequired,
|
||||
onViewAccountDetails: PropTypes.func.isRequired,
|
||||
onViewTokenDetails: PropTypes.func.isRequired,
|
||||
tokenSymbol: PropTypes.string,
|
||||
};
|
||||
|
||||
|
@ -10,10 +10,14 @@ import {
|
||||
getSelectedIdentity,
|
||||
getRpcPrefsForCurrentProvider,
|
||||
} from '../../../selectors/selectors';
|
||||
import { DEFAULT_ROUTE } from '../../../helpers/constants/routes';
|
||||
import {
|
||||
DEFAULT_ROUTE,
|
||||
TOKEN_DETAILS,
|
||||
} from '../../../helpers/constants/routes';
|
||||
import { getURLHostName } from '../../../helpers/utils/util';
|
||||
import { showModal } from '../../../store/actions';
|
||||
import { useNewMetricEvent } from '../../../hooks/useMetricEvent';
|
||||
import { ASSET_TYPES, updateSendAsset } from '../../../ducks/send';
|
||||
|
||||
import AssetNavigation from './asset-navigation';
|
||||
import AssetOptions from './asset-options';
|
||||
@ -53,7 +57,9 @@ export default function TokenAsset({ token }) {
|
||||
optionsButton={
|
||||
<AssetOptions
|
||||
onRemove={() =>
|
||||
dispatch(showModal({ name: 'HIDE_TOKEN_CONFIRMATION', token }))
|
||||
dispatch(
|
||||
showModal({ name: 'HIDE_TOKEN_CONFIRMATION', token, history }),
|
||||
)
|
||||
}
|
||||
isEthNetwork={!rpcPrefs.blockExplorerUrl}
|
||||
onClickBlockExplorer={() => {
|
||||
@ -63,6 +69,16 @@ export default function TokenAsset({ token }) {
|
||||
onViewAccountDetails={() => {
|
||||
dispatch(showModal({ name: 'ACCOUNT_DETAILS' }));
|
||||
}}
|
||||
onViewTokenDetails={() => {
|
||||
dispatch(
|
||||
updateSendAsset({
|
||||
type: ASSET_TYPES.TOKEN,
|
||||
details: { ...token },
|
||||
}),
|
||||
).then(() => {
|
||||
history.push(TOKEN_DETAILS);
|
||||
});
|
||||
}}
|
||||
tokenSymbol={token.symbol}
|
||||
/>
|
||||
}
|
||||
|
@ -20,5 +20,6 @@
|
||||
@import 'send/send';
|
||||
@import 'settings/index';
|
||||
@import 'swaps/index';
|
||||
@import 'token-details/index';
|
||||
@import 'unlock-page/index';
|
||||
@import 'onboarding-flow/index';
|
||||
|
@ -33,6 +33,7 @@ import UnlockPage from '../unlock-page';
|
||||
import Alerts from '../../components/app/alerts';
|
||||
import Asset from '../asset';
|
||||
import OnboardingAppHeader from '../onboarding-flow/onboarding-app-header/onboarding-app-header';
|
||||
import TokenDetailsPage from '../token-details';
|
||||
|
||||
import {
|
||||
IMPORT_TOKEN_ROUTE,
|
||||
@ -57,6 +58,7 @@ import {
|
||||
INITIALIZE_ROUTE,
|
||||
ONBOARDING_ROUTE,
|
||||
ADD_COLLECTIBLE_ROUTE,
|
||||
TOKEN_DETAILS,
|
||||
} from '../../helpers/constants/routes';
|
||||
|
||||
import {
|
||||
@ -152,6 +154,11 @@ export default class Routes extends Component {
|
||||
component={SendTransactionScreen}
|
||||
exact
|
||||
/>
|
||||
<Authenticated
|
||||
path={TOKEN_DETAILS}
|
||||
component={TokenDetailsPage}
|
||||
exact
|
||||
/>
|
||||
<Authenticated path={SWAPS_ROUTE} component={Swaps} />
|
||||
<Authenticated
|
||||
path={IMPORT_TOKEN_ROUTE}
|
||||
|
1
ui/pages/token-details/index.js
Normal file
1
ui/pages/token-details/index.js
Normal file
@ -0,0 +1 @@
|
||||
export { default } from './token-details-page';
|
49
ui/pages/token-details/index.scss
Normal file
49
ui/pages/token-details/index.scss
Normal file
@ -0,0 +1,49 @@
|
||||
.token-details {
|
||||
&__title {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
&__closeButton {
|
||||
float: right;
|
||||
width: 10px;
|
||||
margin-top: -17px;
|
||||
margin-inline-end: -8px;
|
||||
|
||||
&::after {
|
||||
font-size: 24px;
|
||||
content: '\00D7';
|
||||
color: var(--black);
|
||||
}
|
||||
}
|
||||
|
||||
&__token-value {
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
&__token-address {
|
||||
width: 222px;
|
||||
}
|
||||
|
||||
&__copy-icon {
|
||||
float: right;
|
||||
margin-inline-start: 62px;
|
||||
|
||||
@media screen and (min-width: $break-large) {
|
||||
margin-inline-start: 112px;
|
||||
}
|
||||
}
|
||||
|
||||
&__hide-token-button {
|
||||
width: 319px;
|
||||
height: 39px;
|
||||
margin-top: 70px;
|
||||
|
||||
@media screen and (min-width: $break-large) {
|
||||
margin-inline-start: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.btn--rounded.btn-primary {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
200
ui/pages/token-details/token-details-page.js
Normal file
200
ui/pages/token-details/token-details-page.js
Normal file
@ -0,0 +1,200 @@
|
||||
import React, { useContext } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { Redirect, useHistory } from 'react-router-dom';
|
||||
import { getTokens } from '../../ducks/metamask/metamask';
|
||||
import { getSendAssetAddress } from '../../ducks/send';
|
||||
import { getUseTokenDetection, getTokenList } from '../../selectors';
|
||||
import { useCopyToClipboard } from '../../hooks/useCopyToClipboard';
|
||||
import { isEqualCaseInsensitive } from '../../helpers/utils/util';
|
||||
import Identicon from '../../components/ui/identicon/identicon.component';
|
||||
import { I18nContext } from '../../contexts/i18n';
|
||||
import { useTokenTracker } from '../../hooks/useTokenTracker';
|
||||
import { useTokenFiatAmount } from '../../hooks/useTokenFiatAmount';
|
||||
import { showModal } from '../../store/actions';
|
||||
import { NETWORK_TYPE_RPC } from '../../../shared/constants/network';
|
||||
import { ASSET_ROUTE, DEFAULT_ROUTE } from '../../helpers/constants/routes';
|
||||
import Tooltip from '../../components/ui/tooltip';
|
||||
import Button from '../../components/ui/button';
|
||||
import CopyIcon from '../../components/ui/icon/copy-icon.component';
|
||||
import Box from '../../components/ui/box';
|
||||
import Typography from '../../components/ui/typography';
|
||||
import {
|
||||
COLORS,
|
||||
TYPOGRAPHY,
|
||||
FONT_WEIGHT,
|
||||
DISPLAY,
|
||||
TEXT_ALIGN,
|
||||
OVERFLOW_WRAP,
|
||||
} from '../../helpers/constants/design-system';
|
||||
|
||||
export default function TokenDetailsPage() {
|
||||
const dispatch = useDispatch();
|
||||
const history = useHistory();
|
||||
const t = useContext(I18nContext);
|
||||
|
||||
const tokens = useSelector(getTokens);
|
||||
const tokenList = useSelector(getTokenList);
|
||||
const useTokenDetection = useSelector(getUseTokenDetection);
|
||||
|
||||
const assetAddress = useSelector((state) => ({
|
||||
asset: getSendAssetAddress(state),
|
||||
}));
|
||||
|
||||
const { asset: tokenAddress } = assetAddress;
|
||||
|
||||
const tokenMetadata = tokenList[tokenAddress];
|
||||
const fileName = tokenMetadata?.iconUrl;
|
||||
const imagePath = useTokenDetection
|
||||
? fileName
|
||||
: `images/contract/${fileName}`;
|
||||
|
||||
const token = tokens.find(({ address }) =>
|
||||
isEqualCaseInsensitive(address, tokenAddress),
|
||||
);
|
||||
|
||||
const { tokensWithBalances } = useTokenTracker([token]);
|
||||
const tokenBalance = tokensWithBalances[0]?.string;
|
||||
const tokenCurrencyBalance = useTokenFiatAmount(
|
||||
token?.address,
|
||||
tokenBalance,
|
||||
token?.symbol,
|
||||
);
|
||||
|
||||
const currentNetwork = useSelector((state) => ({
|
||||
nickname: state.metamask.provider.nickname,
|
||||
type: state.metamask.provider.type,
|
||||
}));
|
||||
|
||||
const { nickname: networkNickname, type: networkType } = currentNetwork;
|
||||
|
||||
const [copied, handleCopy] = useCopyToClipboard();
|
||||
|
||||
if (!token) {
|
||||
return <Redirect to={{ pathname: DEFAULT_ROUTE }} />;
|
||||
}
|
||||
return (
|
||||
<Box className="page-container token-details">
|
||||
<Box marginLeft={5} marginRight={6}>
|
||||
<Typography
|
||||
fontWeight={FONT_WEIGHT.BOLD}
|
||||
margin={[4, 0, 0, 0]}
|
||||
variant={TYPOGRAPHY.H6}
|
||||
color={COLORS.BLACK}
|
||||
className="token-details__title"
|
||||
>
|
||||
{t('tokenDetails')}
|
||||
<Button
|
||||
type="link"
|
||||
onClick={() => history.push(`${ASSET_ROUTE}/${token.address}`)}
|
||||
className="token-details__closeButton"
|
||||
/>
|
||||
</Typography>
|
||||
<Box display={DISPLAY.FLEX} marginTop={4}>
|
||||
<Typography
|
||||
align={TEXT_ALIGN.CENTER}
|
||||
fontWeight={FONT_WEIGHT.BOLD}
|
||||
margin={[0, 5, 0, 0]}
|
||||
variant={TYPOGRAPHY.H4}
|
||||
color={COLORS.BLACK}
|
||||
className="token-details__token-value"
|
||||
>
|
||||
{tokenBalance}
|
||||
</Typography>
|
||||
<Box marginTop={1}>
|
||||
<Identicon
|
||||
diameter={32}
|
||||
address={token.address}
|
||||
image={tokenMetadata ? imagePath : token.image}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
<Typography
|
||||
margin={[4, 0, 0, 0]}
|
||||
variant={TYPOGRAPHY.H7}
|
||||
color={COLORS.UI4}
|
||||
>
|
||||
{tokenCurrencyBalance || ''}
|
||||
</Typography>
|
||||
<Typography
|
||||
margin={[6, 0, 0, 0]}
|
||||
variant={TYPOGRAPHY.H9}
|
||||
color={COLORS.UI4}
|
||||
fontWeight={FONT_WEIGHT.BOLD}
|
||||
>
|
||||
{t('tokenContractAddress')}
|
||||
</Typography>
|
||||
<Box display={DISPLAY.FLEX}>
|
||||
<Typography
|
||||
variant={TYPOGRAPHY.H7}
|
||||
margin={[2, 0, 0, 0]}
|
||||
color={COLORS.BLACK}
|
||||
overflowWrap={OVERFLOW_WRAP.BREAK_WORD}
|
||||
className="token-details__token-address"
|
||||
>
|
||||
{token.address}
|
||||
</Typography>
|
||||
<Tooltip
|
||||
position="bottom"
|
||||
title={copied ? t('copiedExclamation') : t('copyToClipboard')}
|
||||
containerClassName="token-details__copy-icon"
|
||||
>
|
||||
<Button
|
||||
type="link"
|
||||
className="token-details__copyIcon"
|
||||
onClick={() => {
|
||||
handleCopy(token.address);
|
||||
}}
|
||||
>
|
||||
<CopyIcon size={11} color="#037DD6" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
<Typography
|
||||
variant={TYPOGRAPHY.H9}
|
||||
margin={[4, 0, 0, 0]}
|
||||
color={COLORS.UI4}
|
||||
fontWeight={FONT_WEIGHT.BOLD}
|
||||
>
|
||||
{t('tokenDecimalTitle')}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant={TYPOGRAPHY.H7}
|
||||
margin={[1, 0, 0, 0]}
|
||||
color={COLORS.BLACK}
|
||||
>
|
||||
{token.decimals}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant={TYPOGRAPHY.H9}
|
||||
margin={[4, 0, 0, 0]}
|
||||
color={COLORS.UI4}
|
||||
fontWeight={FONT_WEIGHT.BOLD}
|
||||
>
|
||||
{t('network')}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant={TYPOGRAPHY.H7}
|
||||
margin={[1, 0, 0, 0]}
|
||||
color={COLORS.BLACK}
|
||||
>
|
||||
{networkType === NETWORK_TYPE_RPC
|
||||
? networkNickname ?? t('privateNetwork')
|
||||
: t(networkType)}
|
||||
</Typography>
|
||||
<Button
|
||||
type="primary"
|
||||
className="token-details__hide-token-button"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
showModal({ name: 'HIDE_TOKEN_CONFIRMATION', token, history }),
|
||||
);
|
||||
}}
|
||||
>
|
||||
<Typography variant={TYPOGRAPHY.H6} color={COLORS.PRIMARY1}>
|
||||
{t('hideToken')}
|
||||
</Typography>
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
211
ui/pages/token-details/token-details-page.test.js
Normal file
211
ui/pages/token-details/token-details-page.test.js
Normal file
@ -0,0 +1,211 @@
|
||||
import React from 'react';
|
||||
import configureMockStore from 'redux-mock-store';
|
||||
import { fireEvent } from '@testing-library/react';
|
||||
import { renderWithProvider } from '../../../test/lib/render-helpers';
|
||||
import Identicon from '../../components/ui/identicon/identicon.component';
|
||||
import TokenDetailsPage from './token-details-page';
|
||||
|
||||
const state = {
|
||||
metamask: {
|
||||
selectedAddress: '0xAddress',
|
||||
contractExchangeRates: {
|
||||
'0xAnotherToken': 0.015,
|
||||
},
|
||||
useTokenDetection: true,
|
||||
tokenList: {
|
||||
'0x6b175474e89094c44da98b954eedeac495271d0f': {
|
||||
address: '0x6b175474e89094c44da98b954eedeac495271d0f',
|
||||
symbol: 'META',
|
||||
decimals: 18,
|
||||
image: 'metamark.svg',
|
||||
unlisted: false,
|
||||
},
|
||||
'0xB8c77482e45F1F44dE1745F52C74426C631bDD52': {
|
||||
address: '0xB8c77482e45F1F44dE1745F52C74426C631bDD52',
|
||||
symbol: '0X',
|
||||
decimals: 18,
|
||||
image: '0x.svg',
|
||||
unlisted: false,
|
||||
},
|
||||
'0x1f9840a85d5af5bf1d1762f925bdaddc4201f984': {
|
||||
address: '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984',
|
||||
symbol: 'AST',
|
||||
decimals: 18,
|
||||
image: 'ast.png',
|
||||
unlisted: false,
|
||||
},
|
||||
'0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2': {
|
||||
address: '0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2',
|
||||
symbol: 'BAT',
|
||||
decimals: 18,
|
||||
image: 'BAT_icon.svg',
|
||||
unlisted: false,
|
||||
},
|
||||
'0xe83cccfabd4ed148903bf36d4283ee7c8b3494d1': {
|
||||
address: '0xe83cccfabd4ed148903bf36d4283ee7c8b3494d1',
|
||||
symbol: 'CVL',
|
||||
decimals: 18,
|
||||
image: 'CVL_token.svg',
|
||||
unlisted: false,
|
||||
},
|
||||
'0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e': {
|
||||
address: '0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e',
|
||||
symbol: 'GLA',
|
||||
decimals: 18,
|
||||
image: 'gladius.svg',
|
||||
unlisted: false,
|
||||
},
|
||||
'0x467Bccd9d29f223BcE8043b84E8C8B282827790F': {
|
||||
address: '0x467Bccd9d29f223BcE8043b84E8C8B282827790F',
|
||||
symbol: 'GNO',
|
||||
decimals: 18,
|
||||
image: 'gnosis.svg',
|
||||
unlisted: false,
|
||||
},
|
||||
'0xff20817765cb7f73d4bde2e66e067e58d11095c2': {
|
||||
address: '0xff20817765cb7f73d4bde2e66e067e58d11095c2',
|
||||
symbol: 'OMG',
|
||||
decimals: 18,
|
||||
image: 'omg.jpg',
|
||||
unlisted: false,
|
||||
},
|
||||
'0x8e870d67f660d95d5be530380d0ec0bd388289e1': {
|
||||
address: '0x8e870d67f660d95d5be530380d0ec0bd388289e1',
|
||||
symbol: 'WED',
|
||||
decimals: 18,
|
||||
image: 'wed.png',
|
||||
unlisted: false,
|
||||
},
|
||||
},
|
||||
provider: {
|
||||
type: 'mainnet',
|
||||
nickname: '',
|
||||
},
|
||||
preferences: {
|
||||
showFiatInTestnets: true,
|
||||
},
|
||||
tokens: [
|
||||
{
|
||||
address: '0xaD6D458402F60fD3Bd25163575031ACDce07538A',
|
||||
symbol: 'DAA',
|
||||
decimals: 18,
|
||||
image: null,
|
||||
isERC721: false,
|
||||
},
|
||||
{
|
||||
address: '0xaD6D458402F60fD3Bd25163575031ACDce07538U',
|
||||
symbol: 'DAU',
|
||||
decimals: 18,
|
||||
image: null,
|
||||
isERC721: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
send: {
|
||||
asset: {
|
||||
balance: '0x0',
|
||||
type: 'TOKEN',
|
||||
details: {
|
||||
address: '0xaD6D458402F60fD3Bd25163575031ACDce07538A',
|
||||
decimals: 18,
|
||||
image: null,
|
||||
isERC721: false,
|
||||
symbol: 'DAI',
|
||||
},
|
||||
},
|
||||
},
|
||||
token: {
|
||||
address: '0x6b175474e89094c44da98b954eedeac495271d0f',
|
||||
decimals: 18,
|
||||
image: './images/eth_logo.svg',
|
||||
isERC721: false,
|
||||
symbol: 'ETH',
|
||||
},
|
||||
};
|
||||
|
||||
describe('TokenDetailsPage', () => {
|
||||
it('should render title "Token details" in token details page', () => {
|
||||
const store = configureMockStore()(state);
|
||||
const { getByText } = renderWithProvider(<TokenDetailsPage />, store);
|
||||
expect(getByText('Token details')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should close token details page when close button is clicked', () => {
|
||||
const store = configureMockStore()(state);
|
||||
const { container } = renderWithProvider(<TokenDetailsPage />, store);
|
||||
const onCloseBtn = container.querySelector('.token-details__closeButton');
|
||||
fireEvent.click(onCloseBtn);
|
||||
expect(onCloseBtn).toBeDefined();
|
||||
});
|
||||
|
||||
it('should render an icon image', () => {
|
||||
const image = (
|
||||
<Identicon
|
||||
diameter={32}
|
||||
address={state.send.asset.details.address}
|
||||
image={state.token.image}
|
||||
/>
|
||||
);
|
||||
expect(image).toBeDefined();
|
||||
});
|
||||
|
||||
it('should render token contract address title in token details page', () => {
|
||||
const store = configureMockStore()(state);
|
||||
const { getByText } = renderWithProvider(<TokenDetailsPage />, store);
|
||||
expect(getByText('Token Contract Address')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render token contract address in token details page', () => {
|
||||
const store = configureMockStore()(state);
|
||||
const { getByText } = renderWithProvider(<TokenDetailsPage />, store);
|
||||
expect(getByText(state.send.asset.details.address)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should call copy button when click is simulated', () => {
|
||||
const store = configureMockStore()(state);
|
||||
const { container } = renderWithProvider(<TokenDetailsPage />, store);
|
||||
const handleCopyBtn = container.querySelector('.token-details__copyIcon');
|
||||
fireEvent.click(handleCopyBtn);
|
||||
expect(handleCopyBtn).toBeDefined();
|
||||
});
|
||||
|
||||
it('should render token decimal title in token details page', () => {
|
||||
const store = configureMockStore()(state);
|
||||
const { getByText } = renderWithProvider(<TokenDetailsPage />, store);
|
||||
expect(getByText('Token Decimal:')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render number of token decimals in token details page', () => {
|
||||
const store = configureMockStore()(state);
|
||||
const { getByText } = renderWithProvider(<TokenDetailsPage />, store);
|
||||
expect(getByText('18')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render current network title in token details page', () => {
|
||||
const store = configureMockStore()(state);
|
||||
const { getByText } = renderWithProvider(<TokenDetailsPage />, store);
|
||||
expect(getByText('Network:')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render current network in token details page', () => {
|
||||
const store = configureMockStore()(state);
|
||||
const { getByText } = renderWithProvider(<TokenDetailsPage />, store);
|
||||
expect(getByText('Ethereum Mainnet')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should call hide token button when button is clicked in token details page', () => {
|
||||
const store = configureMockStore()(state);
|
||||
const { container } = renderWithProvider(<TokenDetailsPage />, store);
|
||||
const hideTokenBtn = container.querySelector(
|
||||
'.token-details__hide-token-button',
|
||||
);
|
||||
fireEvent.click(hideTokenBtn);
|
||||
expect(hideTokenBtn).toBeDefined();
|
||||
});
|
||||
|
||||
it('should render label of hide token button in token details page', () => {
|
||||
const store = configureMockStore()(state);
|
||||
const { getByText } = renderWithProvider(<TokenDetailsPage />, store);
|
||||
expect(getByText('Hide token')).toBeInTheDocument();
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user