import { fireEvent, render } from '@testing-library/react-native' import * as React from 'react' import { Provider } from 'react-redux' import { AssetsEvents } from 'src/analytics/Events' import AppAnalytics from 'src/analytics/AppAnalytics' import { navigate } from 'src/navigator/NavigationService' import { Screens } from 'src/navigator/Screens' import { fetchNfts } from 'src/nfts/slice' import { getFeatureGate } from 'src/statsig' import { StatsigFeatureGates } from 'src/statsig/types' import AssetList from 'src/tokens/AssetList' import { AssetTabType } from 'src/tokens/types' import { NetworkId } from 'src/transactions/types' import { createMockStore } from 'test/utils' import { mockEthTokenId, mockNftAllFields, mockNftMinimumFields, mockNftNullMetadata, mockPoofTokenId, mockPositions, mockTokenBalances, } from 'test/values' jest.mock('src/statsig', () => { return { getFeatureGate: jest.fn(), getMultichainFeatures: jest.fn(() => ({ showBalances: ['celo-alfajores', 'ethereum-sepolia'], })), } }) const storeWithAssets = { tokens: { tokenBalances: { ...mockTokenBalances, [mockEthTokenId]: { tokenId: mockEthTokenId, balance: '0', priceUsd: '5', networkId: NetworkId['ethereum-sepolia'], showZeroBalance: true, isNative: true, symbol: 'ETH', }, ['token1']: { tokenId: 'token1', networkId: NetworkId['celo-alfajores'], balance: '10', symbol: 'TK1', }, ['token2']: { tokenId: 'token2', networkId: NetworkId['celo-alfajores'], balance: '0', symbol: 'TK2', }, ['token3']: { tokenId: 'token3', networkId: NetworkId['ethereum-sepolia'], balance: '20', symbol: 'TK3', }, }, }, positions: { positions: mockPositions, }, nfts: { nfts: [ { ...mockNftAllFields, networkId: NetworkId['celo-alfajores'] }, { ...mockNftMinimumFields, networkId: NetworkId['ethereum-sepolia'] }, { ...mockNftNullMetadata, networkId: NetworkId['celo-alfajores'] }, ], nftsLoading: false, nftsError: null, }, } describe('AssetList', () => { beforeEach(() => { jest.clearAllMocks() jest.mocked(getFeatureGate).mockReturnValue(true) }) it('renders tokens in the expected order', () => { const store = createMockStore(storeWithAssets) const { getAllByTestId, queryAllByTestId } = render( ) expect(getAllByTestId('TokenBalanceItem')).toHaveLength(6) expect(queryAllByTestId('PositionItem')).toHaveLength(0) expect(queryAllByTestId('NftItem')).toHaveLength(0) ;['POOF', 'TK3', 'TK1', 'CELO', 'ETH', 'cUSD'].map((symbol, index) => { expect(getAllByTestId('TokenBalanceItem')[index]).toHaveTextContent(symbol) }) }) it('renders collectibles', () => { const store = createMockStore(storeWithAssets) const { queryAllByTestId } = render( ) expect(queryAllByTestId('TokenBalanceItem')).toHaveLength(0) expect(queryAllByTestId('PositionItem')).toHaveLength(0) expect(queryAllByTestId('NftItem')).toHaveLength(2) }) it('renders collectibles error', () => { const store = createMockStore({ nfts: { nftsLoading: false, nfts: [], nftsError: 'Error fetching nfts', }, }) const { getByTestId } = render( ) expect(getByTestId('Assets/NftsLoadError')).toBeTruthy() }) it('renders no collectables text', () => { const store = createMockStore({ nfts: { nftsLoading: false, nfts: [], nftsError: null, }, }) const { getByText } = render( ) expect(getByText('nftGallery.noNfts')).toBeTruthy() }) it('renders dapp positions', () => { const store = createMockStore(storeWithAssets) const { getAllByTestId, queryAllByTestId } = render( ) expect(getAllByTestId('PositionItem')).toHaveLength(3) expect(queryAllByTestId('TokenBalanceItem')).toHaveLength(0) expect(queryAllByTestId('NftItem')).toHaveLength(0) }) it('clicking a token navigates to the token details screen and fires analytics event', () => { const store = createMockStore(storeWithAssets) const { getAllByTestId } = render( ) expect(getAllByTestId('TokenBalanceItem')).toHaveLength(6) fireEvent.press(getAllByTestId('TokenBalanceItem')[0]) expect(navigate).toHaveBeenCalledTimes(1) expect(navigate).toHaveBeenCalledWith(Screens.TokenDetails, { tokenId: mockPoofTokenId }) expect(AppAnalytics.track).toHaveBeenCalledTimes(1) }) it('clicking an NFT navigates to the nfts info screen', async () => { const store = createMockStore(storeWithAssets) const { getAllByTestId } = render( ) expect(getAllByTestId('NftItem')).toHaveLength(2) fireEvent.press(getAllByTestId('NftGallery/NftImage')[0]) fireEvent.press(getAllByTestId('NftGallery/NftImage')[1]) expect(navigate).toHaveBeenCalledTimes(2) expect(navigate).toHaveBeenCalledWith(Screens.NftsInfoCarousel, { nfts: [{ ...mockNftAllFields, networkId: NetworkId['celo-alfajores'] }], networkId: NetworkId['celo-alfajores'], }) expect(navigate).toHaveBeenCalledWith(Screens.NftsInfoCarousel, { nfts: [{ ...mockNftMinimumFields, networkId: NetworkId['ethereum-sepolia'] }], networkId: NetworkId['ethereum-sepolia'], }) }) it('dispatches action to fetch nfts on load', () => { const store = createMockStore(storeWithAssets) render( ) expect(store.getActions()).toEqual([fetchNfts()]) }) it('shows import token on tokens tab on wallet tab screen', () => { const store = createMockStore(storeWithAssets) const { getByTestId } = render( ) expect(getByTestId('AssetList/ImportTokens')).toBeTruthy() fireEvent.press(getByTestId('AssetList/ImportTokens')) expect(navigate).toHaveBeenCalledTimes(1) expect(navigate).toHaveBeenCalledWith(Screens.TokenImport) expect(AppAnalytics.track).toHaveBeenCalledTimes(1) expect(AppAnalytics.track).toHaveBeenCalledWith(AssetsEvents.import_token_screen_open) }) it.each([ { name: 'tokens tab when import gate is off', tab: AssetTabType.Tokens, gate: false }, { name: 'collections tab', tab: AssetTabType.Collectibles, gate: true }, { name: 'positions tab', tab: AssetTabType.Positions, gate: true }, ])('does not show import token on $name', ({ tab, gate }) => { jest .mocked(getFeatureGate) .mockImplementation( (featureGate) => featureGate === StatsigFeatureGates.SHOW_IMPORT_TOKENS_FLOW && gate ) const store = createMockStore(storeWithAssets) const { queryByTestId } = render( ) expect(queryByTestId('AssetList/ImportTokens')).toBeFalsy() }) })