From 0ec9cb933f6188a5f1403bb31f58af58c6cd7429 Mon Sep 17 00:00:00 2001 From: Satish Ravi Date: Tue, 24 Oct 2023 15:43:26 -0700 Subject: [PATCH] fix(token-details): update withdraw to navigate to WithdrawSpend screen (#4377) ### Description Per feedback from Nitya, update withdraw to navigate to the WithdrawSpend screen to allow either using Spend or Withdraw. ### Test plan Unit tests & manual https://github.com/valora-inc/wallet/assets/5062591/03bb80b9-e9d8-4b08-8e34-cdc152ef3162 ### Related issues N/A ### Backwards compatibility Yes --- src/tokens/TokenDetails.test.tsx | 51 +++++++++++++++++++- src/tokens/TokenDetails.tsx | 28 +++++------ src/tokens/TokenDetailsMoreActions.test.tsx | 52 ++++----------------- src/tokens/TokenDetailsMoreActions.tsx | 1 + 4 files changed, 73 insertions(+), 59 deletions(-) diff --git a/src/tokens/TokenDetails.test.tsx b/src/tokens/TokenDetails.test.tsx index ecd399b2987..bc622e9130a 100644 --- a/src/tokens/TokenDetails.test.tsx +++ b/src/tokens/TokenDetails.test.tsx @@ -1,9 +1,13 @@ -import { fireEvent, render } from '@testing-library/react-native' +import { fireEvent, render, waitFor } from '@testing-library/react-native' import React from 'react' import { Provider } from 'react-redux' +import ValoraAnalytics from 'src/analytics/ValoraAnalytics' +import { CICOFlow } from 'src/fiatExchanges/utils' import { navigate } from 'src/navigator/NavigationService' import { Screens } from 'src/navigator/Screens' import TokenDetailsScreen from 'src/tokens/TokenDetails' +import { Network } from 'src/transactions/types' +import { CiCoCurrency } from 'src/utils/currencies' import { ONE_DAY_IN_MILLIS } from 'src/utils/time' import MockedNavigator from 'test/MockedNavigator' import { createMockStore } from 'test/utils' @@ -25,6 +29,9 @@ jest.mock('src/statsig', () => ({ })) describe('TokenDetails', () => { + beforeEach(() => { + jest.clearAllMocks() + }) it('renders title, balance and token balance item', () => { const store = createMockStore({ tokens: { @@ -323,4 +330,46 @@ describe('TokenDetails', () => { expect(getByTestId('TokenDetails/Action/More')).toBeTruthy() expect(queryByTestId('TokenDetails/Action/Withdraw')).toBeFalsy() }) + + it('actions navigate to appropriate screens', async () => { + const store = createMockStore({ + tokens: { + tokenBalances: { + [mockCeloTokenId]: { + ...mockTokenBalances[mockCeloTokenId], + balance: '10', + isSwappable: true, + }, + }, + }, + app: { + showSwapMenuInDrawerMenu: true, + }, + }) + + const { getByTestId } = render( + + + + ) + + fireEvent.press(getByTestId('TokenDetails/Action/Send')) + expect(navigate).toHaveBeenCalledWith(Screens.Send, { defaultTokenIdOverride: mockCeloTokenId }) + fireEvent.press(getByTestId('TokenDetails/Action/Swap')) + expect(navigate).toHaveBeenCalledWith(Screens.SwapScreenWithBack, { + fromTokenId: mockCeloTokenId, + }) + fireEvent.press(getByTestId('TokenDetails/Action/More')) + await waitFor(() => expect(getByTestId('TokenDetailsMoreActions')).toBeTruthy()) + fireEvent.press(getByTestId('TokenDetailsMoreActions/Add')) + expect(navigate).toHaveBeenCalledWith(Screens.FiatExchangeAmount, { + currency: CiCoCurrency.CELO, + tokenId: mockCeloTokenId, + flow: CICOFlow.CashIn, + network: Network.Celo, + }) + fireEvent.press(getByTestId('TokenDetailsMoreActions/Withdraw')) + expect(navigate).toHaveBeenCalledWith(Screens.WithdrawSpend) + expect(ValoraAnalytics.track).toHaveBeenCalledTimes(5) // 4 actions + 1 more action + }) }) diff --git a/src/tokens/TokenDetails.tsx b/src/tokens/TokenDetails.tsx index b2b382c67ef..990fa30d8ee 100644 --- a/src/tokens/TokenDetails.tsx +++ b/src/tokens/TokenDetails.tsx @@ -150,20 +150,6 @@ function PriceInfo({ token }: { token: TokenBalance }) { ) } -export const onPressCicoAction = (token: TokenBalance, flow: CICOFlow) => { - const tokenSymbol = token.symbol - // this should always be true given that we only show Add / Withdraw if a - // token is CiCoCurrency, but adding it here to ensure type safety - if (isCicoToken(tokenSymbol)) { - navigate(Screens.FiatExchangeAmount, { - currency: tokenSymbol, - tokenId: token.tokenId, - flow, - network: Network.Celo, // TODO (ACT-954): use networkId from token - }) - } -} - export const useActions = (token: TokenBalance) => { const { t } = useTranslation() const sendableTokens = useTokensForSend() @@ -203,7 +189,17 @@ export const useActions = (token: TokenBalance) => { details: t('tokenDetails.actionDescriptions.add'), iconComponent: QuickActionsAdd, onPress: () => { - onPressCicoAction(token, CICOFlow.CashIn) + const tokenSymbol = token.symbol + // this should always be true given that we only show Add / Withdraw if a + // token is CiCoCurrency, but adding it here to ensure type safety + if (isCicoToken(tokenSymbol)) { + navigate(Screens.FiatExchangeAmount, { + currency: tokenSymbol, + tokenId: token.tokenId, + flow: CICOFlow.CashIn, + network: Network.Celo, // TODO (ACT-954): use networkId from token + }) + } }, visible: !!cashInTokens.find((tokenInfo) => tokenInfo.tokenId === token.tokenId), }, @@ -213,7 +209,7 @@ export const useActions = (token: TokenBalance) => { details: t('tokenDetails.actionDescriptions.withdraw'), iconComponent: QuickActionsWithdraw, onPress: () => { - onPressCicoAction(token, CICOFlow.CashOut) + navigate(Screens.WithdrawSpend) }, visible: showWithdraw, }, diff --git a/src/tokens/TokenDetailsMoreActions.test.tsx b/src/tokens/TokenDetailsMoreActions.test.tsx index 0db5bc49d46..9e45b39bf67 100644 --- a/src/tokens/TokenDetailsMoreActions.test.tsx +++ b/src/tokens/TokenDetailsMoreActions.test.tsx @@ -3,17 +3,13 @@ import BigNumber from 'bignumber.js' import React from 'react' import { AssetsEvents } from 'src/analytics/Events' import ValoraAnalytics from 'src/analytics/ValoraAnalytics' -import { CICOFlow } from 'src/fiatExchanges/utils' import QuickActionsAdd from 'src/icons/quick-actions/Add' import QuickActionsSend from 'src/icons/quick-actions/Send' import QuickActionsSwap from 'src/icons/quick-actions/Swap' -import { navigate } from 'src/navigator/NavigationService' -import { Screens } from 'src/navigator/Screens' -import { onPressCicoAction } from 'src/tokens/TokenDetails' import TokenDetailsMoreActions from 'src/tokens/TokenDetailsMoreActions' import { StoredTokenBalance, TokenBalance } from 'src/tokens/slice' import { TokenDetailsAction, TokenDetailsActionName } from 'src/tokens/types' -import { Network, NetworkId } from 'src/transactions/types' +import { NetworkId } from 'src/transactions/types' import { mockCeloAddress, mockCeloTokenId } from 'test/values' const mockStoredCeloTokenBalance: StoredTokenBalance = { @@ -48,9 +44,7 @@ const mockActions: TokenDetailsAction[] = [ title: 'tokenDetails.actions.send', details: 'tokenDetails.actions.sendDetails', iconComponent: QuickActionsSend, - onPress: () => { - navigate(Screens.Send, { defaultTokenIdOverride: mockCeloTokenId }) - }, + onPress: jest.fn(), visible: true, }, { @@ -58,9 +52,7 @@ const mockActions: TokenDetailsAction[] = [ title: 'tokenDetails.actions.swap', details: 'tokenDetails.actions.swapDetails', iconComponent: QuickActionsSwap, - onPress: () => { - navigate(Screens.SwapScreenWithBack, { fromTokenId: mockCeloTokenId }) - }, + onPress: jest.fn(), visible: true, }, { @@ -68,9 +60,7 @@ const mockActions: TokenDetailsAction[] = [ title: 'tokenDetails.actions.add', details: 'tokenDetails.actions.addDetails', iconComponent: QuickActionsAdd, - onPress: () => { - onPressCicoAction(mockCeloBalance, CICOFlow.CashIn) - }, + onPress: jest.fn(), visible: true, }, { @@ -78,9 +68,7 @@ const mockActions: TokenDetailsAction[] = [ title: 'tokenDetails.actions.withdraw', details: 'tokenDetails.actions.withdrawDetails', iconComponent: QuickActionsSend, - onPress: () => { - onPressCicoAction(mockCeloBalance, CICOFlow.CashOut) - }, + onPress: jest.fn(), visible: true, }, ] @@ -101,29 +89,9 @@ describe('TokenDetailsMoreActions', () => { expect(getByText('tokenDetails.actions.withdraw')).toBeTruthy() }) - const mockAddParams = { - currency: mockCeloBalance.symbol, - tokenId: mockCeloTokenId, - flow: CICOFlow.CashIn, - network: Network.Celo, - } - - const mockWithdrawParams = { - currency: mockCeloBalance.symbol, - tokenId: mockCeloTokenId, - flow: CICOFlow.CashOut, - network: Network.Celo, - } - - it.each` - action | buttonText | navigatedScreen | navigationParams - ${TokenDetailsActionName.Send} | ${'tokenDetails.actions.send'} | ${Screens.Send} | ${{ defaultTokenIdOverride: mockCeloTokenId }} - ${TokenDetailsActionName.Swap} | ${'tokenDetails.actions.swap'} | ${Screens.SwapScreenWithBack} | ${{ fromTokenId: mockCeloTokenId }} - ${TokenDetailsActionName.Add} | ${'tokenDetails.actions.add'} | ${Screens.FiatExchangeAmount} | ${mockAddParams} - ${TokenDetailsActionName.Withdraw} | ${'tokenDetails.actions.withdraw'} | ${Screens.FiatExchangeAmount} | ${mockWithdrawParams} - `( + it.each(mockActions)( 'triggers the correct analytics and navigation for $buttonText', - async ({ action, buttonText, navigatedScreen, navigationParams }) => { + async ({ name, title, onPress }) => { const { getByText } = render( { /> ) - fireEvent.press(getByText(buttonText)) + fireEvent.press(getByText(title)) expect(ValoraAnalytics.track).toHaveBeenCalledWith( AssetsEvents.tap_token_details_bottom_sheet_action, { - action, + action: name, address: mockCeloAddress, balanceUsd: 5.8, networkId: mockCeloBalance.networkId, @@ -145,7 +113,7 @@ describe('TokenDetailsMoreActions', () => { } ) - expect(navigate).toHaveBeenCalledWith(navigatedScreen, navigationParams) + expect(onPress).toHaveBeenCalled() } ) }) diff --git a/src/tokens/TokenDetailsMoreActions.tsx b/src/tokens/TokenDetailsMoreActions.tsx index 55769dc5b50..ebeaad98272 100644 --- a/src/tokens/TokenDetailsMoreActions.tsx +++ b/src/tokens/TokenDetailsMoreActions.tsx @@ -43,6 +43,7 @@ export default function TokenDetailsMoreActions({ }) action.onPress() }} + testID={`TokenDetailsMoreActions/${action.name}`} > <>