import { fireEvent, render } from '@testing-library/react-native' import * as React from 'react' import { Provider } from 'react-redux' import { navigate } from 'src/navigator/NavigationService' import { Screens } from 'src/navigator/Screens' import { getFeatureGate, getMultichainFeatures } from 'src/statsig' import { StatsigFeatureGates } from 'src/statsig/types' import TabWallet from 'src/tokens/TabWallet' import { NetworkId } from 'src/transactions/types' import MockedNavigator from 'test/MockedNavigator' import { createMockStore } from 'test/utils' import { mockCeurAddress, mockCeurTokenId, mockCusdAddress, mockCusdTokenId, mockNftAllFields, mockNftMinimumFields, mockNftNullMetadata, mockPositions, mockShortcuts, } from 'test/values' jest.mock('src/statsig') const storeWithTokenBalances = { tokens: { tokenBalances: { [mockCeurTokenId]: { tokenId: mockCeurTokenId, priceUsd: '1.16', address: mockCeurAddress, symbol: 'cEUR', imageUrl: 'https://raw.githubusercontent.com/ubeswap/default-token-list/master/assets/asset_cEUR.png', name: 'Celo Euro', decimals: 18, balance: '5', isFeeCurrency: true, canTransferWithComment: true, priceFetchedAt: Date.now(), networkId: NetworkId['celo-alfajores'], }, [mockCusdTokenId]: { tokenId: mockCusdTokenId, priceUsd: '1.001', address: mockCusdAddress, symbol: 'cUSD', imageUrl: 'https://raw.githubusercontent.com/ubeswap/default-token-list/master/assets/asset_cUSD.png', name: 'Celo Dollar', decimals: 18, balance: '10', isFeeCurrency: true, canTransferWithComment: true, priceFetchedAt: Date.now(), networkId: NetworkId['celo-alfajores'], }, }, }, positions: { positions: [], }, } const storeWithPositions = { ...storeWithTokenBalances, positions: { positions: mockPositions, // Total value of positions is ~$7.91 or ~₱10.52 shortcuts: [], }, } const storeWithPositionsAndClaimableRewards = { ...storeWithTokenBalances, positions: { positions: mockPositions, shortcuts: mockShortcuts, }, } const storeWithNfts = { ...storeWithTokenBalances, nfts: { nfts: [ { ...mockNftAllFields, networkId: NetworkId['celo-alfajores'] }, { ...mockNftMinimumFields, networkId: NetworkId['ethereum-sepolia'] }, { ...mockNftNullMetadata, networkId: NetworkId['celo-alfajores'] }, ], nftsLoading: false, nftsError: null, }, } describe('TabWallet', () => { beforeEach(() => { jest.clearAllMocks() jest.mocked(getFeatureGate).mockRestore() jest.mocked(getMultichainFeatures).mockReturnValue({ showBalances: [NetworkId['celo-alfajores']], }) }) it('renders tokens and collectibles tabs when positions is disabled', () => { jest.mocked(getFeatureGate).mockReturnValue(false) const store = createMockStore(storeWithPositions) const { getByTestId, getAllByTestId, queryAllByTestId, getByText, queryByText, queryByTestId } = render( ) expect(getByTestId('AssetsTokenBalance')).toBeTruthy() expect(queryByTestId('AssetsTokenBalance/Info')).toBeFalsy() expect(getByTestId('AssetsTokenBalance')).toHaveTextContent('₱21.03') expect(getByTestId('Assets/TabBar')).toBeTruthy() expect(getAllByTestId('Assets/TabBarItem')).toHaveLength(2) expect(getByText('assets.tabBar.tokens')).toBeTruthy() expect(getByText('assets.tabBar.collectibles')).toBeTruthy() expect(queryByText('assets.tabBar.dappPositions')).toBeFalsy() expect(getAllByTestId('TokenBalanceItem')).toHaveLength(2) expect(queryAllByTestId('PositionItem')).toHaveLength(0) }) it('renders tokens, collectibles and dapp positions tabs when positions is enabled', () => { jest.mocked(getFeatureGate).mockReturnValue(true) const store = createMockStore(storeWithPositions) const { getByTestId, getAllByTestId, queryAllByTestId, getByText, queryByText } = render( ) expect(getByTestId('AssetsTokenBalance')).toBeTruthy() expect(getByTestId('AssetsTokenBalance/Info')).toBeTruthy() expect(getByTestId('AssetsTokenBalance')).toHaveTextContent('₱31.55') expect(getByTestId('Assets/TabBar')).toBeTruthy() expect(getAllByTestId('Assets/TabBarItem')).toHaveLength(3) expect(getByText('assets.tabBar.tokens')).toBeTruthy() expect(getByText('assets.tabBar.collectibles')).toBeTruthy() expect(queryByText('assets.tabBar.dappPositions')).toBeTruthy() expect(getAllByTestId('TokenBalanceItem')).toHaveLength(2) expect(queryAllByTestId('PositionItem')).toHaveLength(0) }) it('hides dapp positions if feature gate is enabled but there are no positions', () => { jest.mocked(getFeatureGate).mockReturnValue(true) const store = createMockStore(storeWithTokenBalances) const { getByTestId, getAllByTestId, queryAllByTestId, getByText, queryByTestId, queryByText } = render( ) expect(getByTestId('AssetsTokenBalance')).toBeTruthy() expect(queryByTestId('AssetsTokenBalance/Info')).toBeFalsy() expect(getByTestId('AssetsTokenBalance')).toHaveTextContent('₱21.03') expect(getByTestId('Assets/TabBar')).toBeTruthy() expect(getAllByTestId('Assets/TabBarItem')).toHaveLength(2) expect(getByText('assets.tabBar.tokens')).toBeTruthy() expect(getByText('assets.tabBar.collectibles')).toBeTruthy() expect(queryByText('assets.tabBar.dappPositions')).toBeFalsy() expect(getAllByTestId('TokenBalanceItem')).toHaveLength(2) expect(queryAllByTestId('PositionItem')).toHaveLength(0) }) it('renders collectibles on selecting the collectibles tab', () => { const store = createMockStore(storeWithNfts) const { getAllByTestId, queryAllByTestId, getByText } = render( ) expect(getAllByTestId('TokenBalanceItem')).toHaveLength(2) expect(queryAllByTestId('PositionItem')).toHaveLength(0) expect(queryAllByTestId('NftItem')).toHaveLength(0) fireEvent.press(getByText('assets.tabBar.collectibles')) expect(queryAllByTestId('TokenBalanceItem')).toHaveLength(0) expect(queryAllByTestId('PositionItem')).toHaveLength(0) expect(queryAllByTestId('NftItem')).toHaveLength(2) }) it('renders dapp positions on selecting the tab', () => { jest.mocked(getFeatureGate).mockReturnValue(true) const store = createMockStore(storeWithPositions) const { getAllByTestId, queryAllByTestId, getByText } = render( ) expect(getAllByTestId('TokenBalanceItem')).toHaveLength(2) expect(queryAllByTestId('PositionItem')).toHaveLength(0) fireEvent.press(getByText('assets.tabBar.dappPositions')) expect(getAllByTestId('PositionItem')).toHaveLength(3) expect(queryAllByTestId('TokenBalanceItem')).toHaveLength(0) fireEvent.press(getByText('assets.tabBar.tokens')) expect(getAllByTestId('TokenBalanceItem')).toHaveLength(2) expect(queryAllByTestId('PositionItem')).toHaveLength(0) }) it('hides claim rewards if feature gate is false', () => { jest .mocked(getFeatureGate) .mockImplementation((gate) => gate === StatsigFeatureGates.SHOW_POSITIONS) const store = createMockStore(storeWithPositionsAndClaimableRewards) const { queryByText } = render( ) expect(queryByText('assets.claimRewards')).toBeFalsy() }) it('hides claim rewards if feature gate is true and positions do not include claimable rewards', () => { jest.mocked(getFeatureGate).mockReturnValue(true) const store = createMockStore(storeWithPositions) const { queryByText } = render( ) expect(queryByText('assets.claimRewards')).toBeFalsy() }) it('shows claim rewards if feature gate is true and positions include claimable rewards', () => { jest.mocked(getFeatureGate).mockReturnValue(true) const store = createMockStore(storeWithPositionsAndClaimableRewards) const { getByText, queryByText } = render( ) expect(getByText('assets.claimRewards')).toBeTruthy() fireEvent.press(getByText('assets.tabBar.dappPositions')) expect(getByText('assets.claimRewards')).toBeTruthy() fireEvent.press(getByText('assets.tabBar.collectibles')) expect(queryByText('assets.claimRewards')).toBeFalsy() fireEvent.press(getByText('assets.tabBar.tokens')) expect(getByText('assets.claimRewards')).toBeTruthy() }) it('clicking claim rewards navigates to rewards screen', () => { jest.mocked(getFeatureGate).mockReturnValue(true) const store = createMockStore(storeWithPositionsAndClaimableRewards) const { getByText } = render( ) fireEvent.press(getByText('assets.claimRewards')) expect(navigate).toHaveBeenCalledWith(Screens.DappShortcutsRewards) }) })