Commit 0a115fab authored by cartcrom's avatar cartcrom Committed by GitHub

fix: unsupported chain displays message instead of crash (#4054)

* made initial changes for pools page displaying w/ unsupported chains
* condensed styling
* added chain validation to CTACards and wrote tests for both CTAcards and Pools page
* linted changes
* switched from snapshot to text matching tests
* switched test to use check for text instead of testid
parent 882147b5
import * as useV3Positions from 'hooks/useV3Positions'
import { BrowserRouter as Router } from 'react-router-dom'
import { render, screen } from 'test-utils'
import * as switchChain from 'utils/switchChain'
import CTACards from './CTACards'
jest.mock('@web3-react/core', () => {
const web3React = jest.requireActual('@web3-react/core')
return {
...web3React,
useWeb3React: () => ({
chainId: 10,
}),
}
})
describe('CTAcard links', () => {
it('renders mainnet link when chain is not supported', () => {
jest.spyOn(switchChain, 'isChainAllowed').mockReturnValue(false)
jest.spyOn(useV3Positions, 'useV3Positions').mockImplementation(() => {
return { loading: false, positions: undefined }
})
render(
<Router>
<CTACards />
</Router>
)
expect(screen.getByTestId('cta-infolink')).toHaveAttribute('href', 'https://info.uniswap.org/#/pools')
})
it('renders specific link when chain is supported', () => {
jest.spyOn(switchChain, 'isChainAllowed').mockReturnValue(true)
jest.spyOn(useV3Positions, 'useV3Positions').mockImplementation(() => {
return { loading: false, positions: undefined }
})
render(
<Router>
<CTACards />
</Router>
)
expect(screen.getByTestId('cta-infolink')).toHaveAttribute('href', 'https://info.uniswap.org/#/optimism/pools')
})
})
......@@ -5,6 +5,7 @@ import { CHAIN_INFO } from 'constants/chainInfo'
import { SupportedChainId } from 'constants/chains'
import styled from 'styled-components/macro'
import { ThemedText } from 'theme'
import { isChainAllowed } from 'utils/switchChain'
import { ExternalLink } from '../../theme'
......@@ -93,8 +94,9 @@ const ResponsiveColumn = styled(AutoColumn)`
`
export default function CTACards() {
const { chainId } = useWeb3React()
const { infoLink } = CHAIN_INFO[chainId ? chainId : SupportedChainId.MAINNET]
const { chainId, connector } = useWeb3React()
const { infoLink } = CHAIN_INFO[chainId && isChainAllowed(connector, chainId) ? chainId : SupportedChainId.MAINNET]
return (
<CTASection>
<CTA1 href={'https://help.uniswap.org/en/articles/5391541-providing-liquidity-on-uniswap-v3'}>
......@@ -107,7 +109,7 @@ export default function CTACards() {
</ThemedText.Body>
</ResponsiveColumn>
</CTA1>
<CTA2 href={infoLink + 'pools'}>
<CTA2 data-testid="cta-infolink" href={infoLink + 'pools'}>
<ResponsiveColumn>
<HeaderText style={{ alignSelf: 'flex-start' }}>
<Trans>Top pools</Trans>
......
import * as useV3Positions from 'hooks/useV3Positions'
import { BrowserRouter as Router } from 'react-router-dom'
import { render, screen } from 'test-utils'
import * as switchChain from 'utils/switchChain'
import Pool from '.'
jest.mock('@web3-react/core', () => {
const web3React = jest.requireActual('@web3-react/core')
return {
...web3React,
useWeb3React: () => ({
chainId: 1,
}),
}
})
describe('networks', () => {
it('renders error card when unsupported chain is selected', () => {
jest.spyOn(switchChain, 'isChainAllowed').mockReturnValue(false)
jest.spyOn(useV3Positions, 'useV3Positions').mockImplementation(() => {
return { loading: false, positions: undefined }
})
render(
<Router>
<Pool />
</Router>
)
expect(
screen.getByText('Your connected network is unsupported. Request support', { exact: false })
).toBeInTheDocument()
})
it('renders empty positions card when on supported chain with no positions', () => {
jest.spyOn(switchChain, 'isChainAllowed').mockReturnValue(true)
jest.spyOn(useV3Positions, 'useV3Positions').mockImplementation(() => {
return { loading: false, positions: undefined }
})
render(
<Router>
<Pool />
</Router>
)
expect(screen.getByText('Your active V3 liquidity positions will appear here.')).toBeInTheDocument()
})
})
......@@ -9,13 +9,14 @@ import { RowBetween, RowFixed } from 'components/Row'
import { SwitchLocaleLink } from 'components/SwitchLocaleLink'
import { useV3Positions } from 'hooks/useV3Positions'
import { useContext } from 'react'
import { BookOpen, ChevronDown, ChevronsRight, Inbox, Layers, PlusCircle } from 'react-feather'
import { Activity, BookOpen, ChevronDown, ChevronsRight, Inbox, Layers, PlusCircle } from 'react-feather'
import { Link } from 'react-router-dom'
import { useToggleWalletModal } from 'state/application/hooks'
import { useUserHideClosedPositions } from 'state/user/hooks'
import styled, { ThemeContext } from 'styled-components/macro'
import { HideSmall, ThemedText } from 'theme'
import styled, { css, ThemeContext } from 'styled-components/macro'
import { ExternalLink, HideSmall, ThemedText } from 'theme'
import { PositionDetails } from 'types/position'
import { isChainAllowed } from 'utils/switchChain'
import { V2_FACTORY_ADDRESSES } from '../../constants/addresses'
import CTACards from './CTACards'
......@@ -80,7 +81,13 @@ const MoreOptionsButton = styled(ButtonGray)`
background-color: ${({ theme }) => theme.bg0};
margin-right: 8px;
`
const NoLiquidity = styled.div`
const MoreOptionsText = styled(ThemedText.Body)`
align-items: center;
display: flex;
`
const ErrorContainer = styled.div`
align-items: center;
display: flex;
flex-direction: column;
......@@ -89,6 +96,21 @@ const NoLiquidity = styled.div`
max-width: 300px;
min-height: 25vh;
`
const IconStyle = css`
width: 48px;
height: 48px;
margin-bottom: 0.5rem;
`
const NetworkIcon = styled(Activity)`
${IconStyle}
`
const InboxIcon = styled(Inbox)`
${IconStyle}
`
const ResponsiveButtonPrimary = styled(ButtonPrimary)`
border-radius: 12px;
padding: 6px 8px;
......@@ -126,8 +148,43 @@ function PositionsLoadingPlaceholder() {
)
}
function WrongNetworkCard() {
const theme = useContext(ThemeContext)
return (
<>
<PageWrapper>
<SwapPoolTabs active="pool" />
<AutoColumn gap="lg" justify="center">
<AutoColumn gap="lg" style={{ width: '100%' }}>
<TitleRow style={{ marginTop: '1rem' }} padding={'0'}>
<ThemedText.Body fontSize={'20px'}>
<Trans>Pools Overview</Trans>
</ThemedText.Body>
</TitleRow>
<MainContentWrapper>
<ErrorContainer>
<ThemedText.Body color={theme.text3} textAlign="center">
<NetworkIcon strokeWidth={1.2} />
<div data-testid="pools-unsupported-err">
<Trans>
Your connected network is unsupported. Request support{' '}
<ExternalLink href="https://uniswap.canny.io/feature-requests">here</ExternalLink>.
</Trans>
</div>
</ThemedText.Body>
</ErrorContainer>
</MainContentWrapper>
</AutoColumn>
</AutoColumn>
</PageWrapper>
<SwitchLocaleLink />
</>
)
}
export default function Pool() {
const { account, chainId } = useWeb3React()
const { account, chainId, connector } = useWeb3React()
const toggleWalletModal = useToggleWalletModal()
const theme = useContext(ThemeContext)
......@@ -135,6 +192,10 @@ export default function Pool() {
const { positions, loading: positionsLoading } = useV3Positions(account)
if (chainId && !isChainAllowed(connector, chainId)) {
return <WrongNetworkCard />
}
const [openPositions, closedPositions] = positions?.reduce<[PositionDetails[], PositionDetails[]]>(
(acc, p) => {
acc[p.liquidity?.isZero() ? 1 : 0].push(p)
......@@ -193,7 +254,7 @@ export default function Pool() {
return (
<>
<PageWrapper>
<SwapPoolTabs active={'pool'} />
<SwapPoolTabs active="pool" />
<AutoColumn gap="lg" justify="center">
<AutoColumn gap="lg" style={{ width: '100%' }}>
<TitleRow style={{ marginTop: '1rem' }} padding={'0'}>
......@@ -207,10 +268,10 @@ export default function Pool() {
flyoutAlignment={FlyoutAlignment.LEFT}
ToggleUI={(props: any) => (
<MoreOptionsButton {...props}>
<ThemedText.Body style={{ alignItems: 'center', display: 'flex' }}>
<MoreOptionsText>
<Trans>More</Trans>
<ChevronDown size={15} />
</ThemedText.Body>
</MoreOptionsText>
</MoreOptionsButton>
)}
/>
......@@ -231,9 +292,9 @@ export default function Pool() {
userHideClosedPositions={userHideClosedPositions}
/>
) : (
<NoLiquidity>
<ErrorContainer>
<ThemedText.Body color={theme.text3} textAlign="center">
<Inbox size={48} strokeWidth={1} style={{ marginBottom: '.5rem' }} />
<InboxIcon strokeWidth={1} />
<div>
<Trans>Your active V3 liquidity positions will appear here.</Trans>
</div>
......@@ -251,7 +312,7 @@ export default function Pool() {
<Trans>Connect a wallet</Trans>
</ButtonPrimary>
)}
</NoLiquidity>
</ErrorContainer>
)}
</MainContentWrapper>
<HideSmall>
......
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