Commit 1f7ba5ae authored by lynn's avatar lynn Committed by GitHub

chore: add token explore integration test (#5820)

* init

* fix

* fixes

* remove extraneous tokens test
parent 3686803c
import { getTestSelector, getTestSelectorStartsWith } from '../utils'
describe('Token explore', () => {
before(() => {
cy.visit('/')
})
it('should load token leaderboard', () => {
cy.visit('/tokens/ethereum')
cy.get(getTestSelectorStartsWith('token-table')).its('length').should('be.eq', 100)
// check sorted svg icon is present in volume cell, since tokens are sorted by volume by default
cy.get(getTestSelector('header-row')).find(getTestSelector('volume-cell')).find('svg').should('exist')
cy.get(getTestSelector('token-table-row-ETH')).find(getTestSelector('name-cell')).should('include.text', 'Ether')
cy.get(getTestSelector('token-table-row-ETH')).find(getTestSelector('volume-cell')).should('include.text', '$')
cy.get(getTestSelector('token-table-row-ETH')).find(getTestSelector('price-cell')).should('include.text', '$')
cy.get(getTestSelector('token-table-row-ETH')).find(getTestSelector('tvl-cell')).should('include.text', '$')
cy.get(getTestSelector('token-table-row-ETH'))
.find(getTestSelector('percent-change-cell'))
.should('include.text', '%')
cy.get(getTestSelector('header-row')).find(getTestSelector('price-cell')).click()
cy.get(getTestSelector('header-row')).find(getTestSelector('price-cell')).find('svg').should('exist')
})
it('should update when time window toggled', () => {
cy.visit('/tokens/ethereum')
cy.get(getTestSelector('time-selector')).should('contain', '1D')
cy.get(getTestSelector('token-table-row-ETH'))
.find(getTestSelector('volume-cell'))
.then(function ($elem) {
cy.wrap($elem.text()).as('dailyEthVol')
})
cy.get(getTestSelector('time-selector')).click()
cy.get(getTestSelector('1Y')).click()
cy.get(getTestSelector('token-table-row-ETH'))
.find(getTestSelector('volume-cell'))
.then(function ($elem) {
cy.wrap($elem.text()).as('yearlyEthVol')
})
expect(cy.get('@dailyEthVol')).to.not.equal(cy.get('@yearlyEthVol'))
})
it('should navigate to token detail page when row clicked', () => {
cy.visit('/tokens/ethereum')
cy.get(getTestSelector('token-table-row-ETH')).click()
cy.get(getTestSelector('token-details-about-section')).should('exist')
cy.get(getTestSelector('token-details-stats')).should('exist')
cy.get(getTestSelector('token-info-container')).should('exist')
cy.get(getTestSelector('chart-container')).should('exist')
cy.contains('Ethereum is a smart contract platform that enables developers to build tokens').should('exist')
cy.contains('Etherscan').should('exist')
})
it('should update when global network changed', () => {
cy.visit('/tokens/ethereum')
cy.get(getTestSelector('tokens-network-filter-selected')).should('contain', 'Ethereum')
cy.get(getTestSelector('token-table-row-ETH')).should('exist')
// note: cannot switch global chain via UI because we cannot approve the network switch
// in metamask modal using plain cypress. this is a workaround.
cy.visit('/tokens/polygon')
cy.get(getTestSelector('tokens-network-filter-selected')).should('contain', 'Polygon')
cy.get(getTestSelector('token-table-row-MATIC')).should('exist')
})
it('should update when token explore table network changed', () => {
cy.visit('/tokens/ethereum')
cy.get(getTestSelector('tokens-network-filter-selected')).click()
cy.get(getTestSelector('tokens-network-filter-option-optimism')).click()
cy.get(getTestSelector('tokens-network-filter-selected')).should('contain', 'Optimism')
cy.reload()
cy.get(getTestSelector('tokens-network-filter-selected')).should('contain', 'Optimism')
cy.get(getTestSelector('chain-selector')).last().should('contain', 'Ethereum')
})
})
import { getTestSelector, getTestSelectorStartsWith } from '../utils'
describe('Testing tokens on uniswap page', () => {
before(() => {
cy.visit('/')
})
it('should load token leaderboard', () => {
cy.visit('/tokens/ethereum')
cy.get(getTestSelectorStartsWith('token-table')).its('length').should('be.gte', 25)
})
it('should keep the same configuration when reloaded: ETH global, OP local', () => {
cy.visit('/tokens/ethereum')
cy.get(getTestSelector('tokens-network-filter-selected')).click()
cy.get(getTestSelector('tokens-network-filter-option-optimism')).click()
cy.reload()
cy.get(getTestSelector('tokens-network-filter-selected')).should('contain', 'Optimism')
})
it('should have the correct network configuration when reloaded: OP global, Polygon local', () => {
cy.get(getTestSelector('chain-selector')).last().click()
cy.get(getTestSelector('chain-selector-option-optimism')).click()
cy.visit('/tokens/ethereum')
cy.get(getTestSelector('tokens-network-filter-selected')).click()
cy.get(getTestSelector('tokens-network-filter-option-polygon')).click()
cy.reload()
cy.get(getTestSelector('tokens-network-filter-selected')).should('contain', 'Polygon')
// With no wallet connected, reloading the page resets the global network.
cy.get(getTestSelector('chain-selector')).last().should('contain', 'Ethereum')
})
it('should load go to ethereum token and return to token list page', () => {
cy.visit('/tokens/ethereum')
cy.get(getTestSelector('token-table-row-Ether')).click()
cy.get(getTestSelector('token-details-stats')).should('exist')
cy.get(getTestSelector('token-details-return-button')).click()
cy.get(getTestSelectorStartsWith('token-table')).its('length').should('be.gte', 25)
})
it('should go to native token on ethereum and render description', () => {
cy.visit('/tokens/ethereum/NATIVE')
cy.get(getTestSelector('token-details-about-section')).should('exist')
cy.contains('Ethereum is a smart contract platform that enables developers').should('exist')
cy.contains('Etherscan').should('exist')
})
it('should go to native token on polygon and render description and links', () => {
cy.visit('/tokens/polygon/NATIVE')
cy.get(getTestSelector('token-details-about-section')).should('exist')
cy.contains('Wrapped Matic on Polygon').should('exist')
cy.contains('Block Explorer').should('exist')
})
})
...@@ -58,7 +58,7 @@ function Chart({ ...@@ -58,7 +58,7 @@ function Chart({
const timePeriod = useAtomValue(pageTimePeriodAtom) const timePeriod = useAtomValue(pageTimePeriodAtom)
return ( return (
<ChartContainer> <ChartContainer data-testid="chart-container">
<ParentSize> <ParentSize>
{({ width }) => <PriceChart prices={prices ?? null} width={width} height={436} timePeriod={timePeriod} />} {({ width }) => <PriceChart prices={prices ?? null} width={width} height={436} timePeriod={timePeriod} />}
</ParentSize> </ParentSize>
......
...@@ -186,7 +186,7 @@ export default function TokenDetails({ ...@@ -186,7 +186,7 @@ export default function TokenDetails({
<BreadcrumbNavLink to={`/tokens/${chain.toLowerCase()}`}> <BreadcrumbNavLink to={`/tokens/${chain.toLowerCase()}`}>
<ArrowLeft data-testid="token-details-return-button" size={14} /> Tokens <ArrowLeft data-testid="token-details-return-button" size={14} /> Tokens
</BreadcrumbNavLink> </BreadcrumbNavLink>
<TokenInfoContainer> <TokenInfoContainer data-testid="token-info-container">
<TokenNameCell> <TokenNameCell>
<LogoContainer> <LogoContainer>
<CurrencyLogo currency={token} size="32px" /> <CurrencyLogo currency={token} size="32px" />
......
...@@ -111,7 +111,7 @@ export default function TimeSelector() { ...@@ -111,7 +111,7 @@ export default function TimeSelector() {
return ( return (
<StyledMenu ref={node}> <StyledMenu ref={node}>
<FilterOption onClick={toggleMenu} aria-label="timeSelector" active={open}> <FilterOption onClick={toggleMenu} aria-label="timeSelector" active={open} data-testid="time-selector">
<StyledMenuContent> <StyledMenuContent>
{DISPLAYS[activeTime]} {DISPLAYS[activeTime]}
<Chevron open={open}> <Chevron open={open}>
...@@ -128,6 +128,7 @@ export default function TimeSelector() { ...@@ -128,6 +128,7 @@ export default function TimeSelector() {
{ORDERED_TIMES.map((time) => ( {ORDERED_TIMES.map((time) => (
<InternalLinkMenuItem <InternalLinkMenuItem
key={DISPLAYS[time]} key={DISPLAYS[time]}
data-testid={DISPLAYS[time]}
onClick={() => { onClick={() => {
setTime(time) setTime(time)
toggleMenu() toggleMenu()
......
...@@ -378,15 +378,23 @@ function TokenRow({ ...@@ -378,15 +378,23 @@ function TokenRow({
const rowCells = ( const rowCells = (
<> <>
<ListNumberCell header={header}>{listNumber}</ListNumberCell> <ListNumberCell header={header}>{listNumber}</ListNumberCell>
<NameCell>{tokenInfo}</NameCell> <NameCell data-testid="name-cell">{tokenInfo}</NameCell>
<PriceCell sortable={header}>{price}</PriceCell> <PriceCell data-testid="price-cell" sortable={header}>
<PercentChangeCell sortable={header}>{percentChange}</PercentChangeCell> {price}
<TvlCell sortable={header}>{tvl}</TvlCell> </PriceCell>
<VolumeCell sortable={header}>{volume}</VolumeCell> <PercentChangeCell data-testid="percent-change-cell" sortable={header}>
{percentChange}
</PercentChangeCell>
<TvlCell data-testid="tvl-cell" sortable={header}>
{tvl}
</TvlCell>
<VolumeCell data-testid="volume-cell" sortable={header}>
{volume}
</VolumeCell>
<SparkLineCell>{sparkLine}</SparkLineCell> <SparkLineCell>{sparkLine}</SparkLineCell>
</> </>
) )
if (header) return <StyledHeaderRow>{rowCells}</StyledHeaderRow> if (header) return <StyledHeaderRow data-testid="header-row">{rowCells}</StyledHeaderRow>
return <StyledTokenRow {...rest}>{rowCells}</StyledTokenRow> return <StyledTokenRow {...rest}>{rowCells}</StyledTokenRow>
} }
...@@ -440,9 +448,6 @@ interface LoadedRowProps { ...@@ -440,9 +448,6 @@ interface LoadedRowProps {
/* Loaded State: row component with token information */ /* Loaded State: row component with token information */
export const LoadedRow = forwardRef((props: LoadedRowProps, ref: ForwardedRef<HTMLDivElement>) => { export const LoadedRow = forwardRef((props: LoadedRowProps, ref: ForwardedRef<HTMLDivElement>) => {
const { tokenListIndex, tokenListLength, token, volumeRank } = props const { tokenListIndex, tokenListLength, token, volumeRank } = props
const tokenAddress = token.address
const tokenName = token.name
const tokenSymbol = token.symbol
const filterString = useAtomValue(filterStringAtom) const filterString = useAtomValue(filterStringAtom)
const lowercaseChainName = useParams<{ chainName?: string }>().chainName?.toUpperCase() ?? 'ethereum' const lowercaseChainName = useParams<{ chainName?: string }>().chainName?.toUpperCase() ?? 'ethereum'
...@@ -457,8 +462,8 @@ export const LoadedRow = forwardRef((props: LoadedRowProps, ref: ForwardedRef<HT ...@@ -457,8 +462,8 @@ export const LoadedRow = forwardRef((props: LoadedRowProps, ref: ForwardedRef<HT
const exploreTokenSelectedEventProperties = { const exploreTokenSelectedEventProperties = {
chain_id: chainId, chain_id: chainId,
token_address: tokenAddress, token_address: token.address,
token_symbol: tokenSymbol, token_symbol: token.symbol,
token_list_index: tokenListIndex, token_list_index: tokenListIndex,
token_list_rank: volumeRank, token_list_rank: volumeRank,
token_list_length: tokenListLength, token_list_length: tokenListLength,
...@@ -468,7 +473,7 @@ export const LoadedRow = forwardRef((props: LoadedRowProps, ref: ForwardedRef<HT ...@@ -468,7 +473,7 @@ export const LoadedRow = forwardRef((props: LoadedRowProps, ref: ForwardedRef<HT
// TODO: currency logo sizing mobile (32px) vs. desktop (24px) // TODO: currency logo sizing mobile (32px) vs. desktop (24px)
return ( return (
<div ref={ref} data-testid={`token-table-row-${tokenName}`}> <div ref={ref} data-testid={`token-table-row-${token.symbol}`}>
<StyledLink <StyledLink
to={getTokenDetailsURL(token.address ?? '', token.chain)} to={getTokenDetailsURL(token.address ?? '', token.chain)}
onClick={() => onClick={() =>
...@@ -485,8 +490,8 @@ export const LoadedRow = forwardRef((props: LoadedRowProps, ref: ForwardedRef<HT ...@@ -485,8 +490,8 @@ export const LoadedRow = forwardRef((props: LoadedRowProps, ref: ForwardedRef<HT
<L2NetworkLogo networkUrl={L2Icon} /> <L2NetworkLogo networkUrl={L2Icon} />
</LogoContainer> </LogoContainer>
<TokenInfoCell> <TokenInfoCell>
<TokenName>{tokenName}</TokenName> <TokenName>{token.name}</TokenName>
<TokenSymbol>{tokenSymbol}</TokenSymbol> <TokenSymbol>{token.symbol}</TokenSymbol>
</TokenInfoCell> </TokenInfoCell>
</ClickableName> </ClickableName>
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment