Skip to content

Commit

Permalink
feat: show injected options in wallet browsers (Uniswap#3995)
Browse files Browse the repository at this point in the history
* feat: show injected options in wallet browsers

* initial testing

* more mocking

* mock more

* mobile tests

* updates

* add data test

* finally got the mock to work

* WORKING

* uncomment

* rm console.log

* fix

* check length

* fix tests to use useWeb3React

* rm

* rename tests
  • Loading branch information
vm authored Jun 30, 2022
1 parent 0e148bb commit 8548b33
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 23 deletions.
11 changes: 6 additions & 5 deletions src/components/SearchModal/CurrencyList/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,21 @@ jest.mock(
`CurrencyLogo currency=${currency.symbol}`
)

jest.mock('hooks/useActiveWeb3React', () => {
jest.mock('@web3-react/core', () => {
const web3React = jest.requireActual('@web3-react/core')
return {
__esModule: true,
default: () => ({
useWeb3React: () => ({
account: '123',
active: true,
isActive: true,
}),
...web3React,
}
})

jest.mock('../../../state/wallet/hooks', () => {
return {
useCurrencyBalance: (currency: Currency) => {
return mockCurrencyAmt[(currency as mockToken).address]
return mockCurrencyAmt[(currency as mockToken)?.address]
},
}
})
Expand Down
4 changes: 2 additions & 2 deletions src/components/SearchModal/CurrencyList/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Trans } from '@lingui/macro'
import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/core'
import { LightGreyCard } from 'components/Card'
import QuestionHelper from 'components/QuestionHelper'
import useActiveWeb3React from 'hooks/useActiveWeb3React'
import useTheme from 'hooks/useTheme'
import { CSSProperties, MutableRefObject, useCallback, useMemo } from 'react'
import { FixedSizeList } from 'react-window'
Expand Down Expand Up @@ -114,7 +114,7 @@ function CurrencyRow({
style: CSSProperties
showCurrencyAmount?: boolean
}) {
const { account } = useActiveWeb3React()
const { account } = useWeb3React()
const key = currencyKey(currency)
const selectedTokenList = useCombinedActiveList()
const isOnSelectedList = isTokenOnList(selectedTokenList, currency.isToken ? currency : undefined)
Expand Down
8 changes: 7 additions & 1 deletion src/components/WalletModal/Option.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,13 @@ export default function Option({
id: string
}) {
const content = (
<OptionCardClickable id={id} onClick={onClick} clickable={clickable && !active} active={active}>
<OptionCardClickable
id={id}
onClick={onClick}
clickable={clickable && !active}
active={active}
data-testid="wallet-modal-option"
>
<OptionCardLeft>
<HeaderText color={color}>
{active ? (
Expand Down
87 changes: 87 additions & 0 deletions src/components/WalletModal/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { ApplicationModal } from 'state/application/reducer'

import { render, screen } from '../../test-utils'
import WalletModal from './index'

beforeEach(() => {
delete global.window.ethereum
})

afterAll(() => {
delete global.window.ethereum
})

const UserAgentMock = jest.requireMock('utils/userAgent')
jest.mock('utils/userAgent', () => ({
isMobile: false,
}))

jest.mock('.../../state/application/hooks', () => {
return {
useModalOpen: (_modal: ApplicationModal) => true,
useWalletModalToggle: () => {
return
},
}
})

jest.mock('@web3-react/core', () => {
const web3React = jest.requireActual('@web3-react/core')
return {
useWeb3React: () => ({
account: undefined,
isActive: false,
isActivating: false,
connector: undefined,
}),
...web3React,
}
})

it('loads Wallet Modal on desktop', async () => {
render(<WalletModal pendingTransactions={[]} confirmedTransactions={[]} />)
expect(screen.getByText('Install MetaMask')).toBeInTheDocument()
expect(screen.getByText('Coinbase Wallet')).toBeInTheDocument()
expect(screen.getByText('WalletConnect')).toBeInTheDocument()
expect(screen.getByText('Fortmatic')).toBeInTheDocument()
expect(screen.getAllByTestId('wallet-modal-option')).toHaveLength(4)
})

it('loads Wallet Modal on desktop with MetaMask installed', async () => {
global.window.ethereum = { isMetaMask: true }

render(<WalletModal pendingTransactions={[]} confirmedTransactions={[]} />)
expect(screen.getByText('MetaMask')).toBeInTheDocument()
expect(screen.getByText('Coinbase Wallet')).toBeInTheDocument()
expect(screen.getByText('WalletConnect')).toBeInTheDocument()
expect(screen.getByText('Fortmatic')).toBeInTheDocument()
expect(screen.getAllByTestId('wallet-modal-option')).toHaveLength(4)
})

it('loads Wallet Modal on mobile', async () => {
UserAgentMock.isMobile = true

render(<WalletModal pendingTransactions={[]} confirmedTransactions={[]} />)
expect(screen.getByText('Open in Coinbase Wallet')).toBeInTheDocument()
expect(screen.getByText('WalletConnect')).toBeInTheDocument()
expect(screen.getByText('Fortmatic')).toBeInTheDocument()
expect(screen.getAllByTestId('wallet-modal-option')).toHaveLength(3)
})

it('loads Wallet Modal on MetaMask browser', async () => {
UserAgentMock.isMobile = true
global.window.ethereum = { isMetaMask: true }

render(<WalletModal pendingTransactions={[]} confirmedTransactions={[]} />)
expect(screen.getByText('MetaMask')).toBeInTheDocument()
expect(screen.getAllByTestId('wallet-modal-option')).toHaveLength(1)
})

it('loads Wallet Modal on Coinbase Wallet browser', async () => {
UserAgentMock.isMobile = true
global.window.ethereum = { isCoinbaseWallet: true }

render(<WalletModal pendingTransactions={[]} confirmedTransactions={[]} />)
expect(screen.getByText('Coinbase Wallet')).toBeInTheDocument()
expect(screen.getAllByTestId('wallet-modal-option')).toHaveLength(1)
})
15 changes: 10 additions & 5 deletions src/components/WalletModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,9 @@ export default function WalletModal({

// get wallets user can switch too, depending on device/browser
function getOptions() {
const isMetamask = !!window.ethereum?.isMetaMask
const isMetaMask = !!window.ethereum?.isMetaMask
const isTally = !!window.ethereum?.isTally
const isCoinbaseWallet = !!window.ethereum?.isCoinbaseWallet
return Object.keys(SUPPORTED_WALLETS).map((key) => {
const option = SUPPORTED_WALLETS[key]
const isActive = option.connector === connector
Expand All @@ -202,7 +203,11 @@ export default function WalletModal({

// check for mobile options
if (isMobile) {
if (!window.web3 && !window.ethereum && option.mobile) {
if (
(!window.web3 && !window.ethereum && option.mobile) ||
(isMetaMask && option.name === 'MetaMask') ||
(isCoinbaseWallet && option.name === 'Coinbase Wallet')
) {
return (
<Option
{...optionProps}
Expand All @@ -228,7 +233,7 @@ export default function WalletModal({
id={`connect-${key}`}
key={key}
color={'#E8831D'}
header={<Trans>Install Metamask</Trans>}
header={<Trans>Install MetaMask</Trans>}
subheader={null}
link={'https://metamask.io/'}
icon={MetamaskIcon}
Expand All @@ -239,11 +244,11 @@ export default function WalletModal({
}
}
// don't return metamask if injected provider isn't metamask
else if (option.name === 'MetaMask' && !isMetamask) {
else if (option.name === 'MetaMask' && !isMetaMask) {
return null
}
// likewise for generic
else if (option.name === 'Injected' && isMetamask) {
else if (option.name === 'Injected' && isMetaMask) {
return null
} else if (option.name === 'Injected' && isTally) {
return (
Expand Down
37 changes: 29 additions & 8 deletions src/test-utils.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,40 @@
import { render, RenderOptions } from '@testing-library/react'
import React, { FC, ReactElement, ReactNode } from 'react'
import { i18n } from '@lingui/core'
import { I18nProvider } from '@lingui/react'
import { render } from '@testing-library/react'
import { Web3ReactProvider } from '@web3-react/core'
import { injected, injectedHooks } from 'connectors'
import { DEFAULT_LOCALE } from 'constants/locales'
import { en } from 'make-plural/plurals'
import { ReactElement, ReactNode } from 'react'
import { Provider } from 'react-redux'
import store from 'state'
import ThemeProvider from 'theme'

const WithProviders: FC = ({ children }: { children?: ReactNode }) => {
import catalog from './locales/en-US'

i18n.load({
[DEFAULT_LOCALE]: catalog.messages,
})
i18n.loadLocaleData({
[DEFAULT_LOCALE]: { plurals: en },
})
i18n.activate(DEFAULT_LOCALE)

const MockedI18nProvider = ({ children }: any) => <I18nProvider i18n={i18n}>{children}</I18nProvider>

const WithProviders = ({ children }: { children?: ReactNode }) => {
return (
<Provider store={store}>
<ThemeProvider>{children}</ThemeProvider>
</Provider>
<MockedI18nProvider>
<Provider store={store}>
<Web3ReactProvider connectors={[[injected, injectedHooks]]}>
<ThemeProvider>{children}</ThemeProvider>
</Web3ReactProvider>
</Provider>
</MockedI18nProvider>
)
}

const customRender = (ui: ReactElement, options?: Omit<RenderOptions, 'wrapper'>) =>
render(ui, { wrapper: WithProviders, ...options })
const customRender = (ui: ReactElement) => render(ui, { wrapper: WithProviders })

export * from '@testing-library/react'
export { customRender as render }
4 changes: 2 additions & 2 deletions src/theme/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ function colors(darkMode: boolean): Colors {
}
}

function theme(darkMode: boolean): DefaultTheme {
function getTheme(darkMode: boolean): DefaultTheme {
return {
...colors(darkMode),

Expand Down Expand Up @@ -144,7 +144,7 @@ function theme(darkMode: boolean): DefaultTheme {
export default function ThemeProvider({ children }: { children: React.ReactNode }) {
const darkMode = useIsDarkMode()

const themeObject = useMemo(() => theme(darkMode), [darkMode])
const themeObject = useMemo(() => getTheme(darkMode), [darkMode])

return <StyledComponentsThemeProvider theme={themeObject}>{children}</StyledComponentsThemeProvider>
}
Expand Down

0 comments on commit 8548b33

Please sign in to comment.