import { render, waitFor } from '@testing-library/react-native'
import { FetchMock } from 'jest-fetch-mock/types'
import * as React from 'react'
import { Provider } from 'react-redux'
import TabHome from 'src/home/TabHome'
import { RootState } from 'src/redux/reducers'
import { getFeatureGate } from 'src/statsig'
import { StatsigFeatureGates } from 'src/statsig/types'
import { NetworkId } from 'src/transactions/types'
import MockedNavigator from 'test/MockedNavigator'
import { RecursivePartial, createMockStore } from 'test/utils'
import {
mockCeurAddress,
mockCeurTokenId,
mockCusdAddress,
mockCusdTokenId,
mockStoreCelebrationReady,
mockStoreReminderDisplayed,
mockStoreReminderReady,
mockStoreRewardDisplayed,
mockStoreRewardReady,
mockStoreRewardReayWithDifferentNft,
} from 'test/values'
// Mocking the TransactionFeedV2 component, as it has comprehensive unit tests
// already. For the purposes of the TabHome test, we only need to verify that
// the component is rendered at the expected time.
jest.mock('src/transactions/feed/TransactionFeedV2', () => {
const React = require('react')
const { Text } = require('react-native')
return jest.fn(() => Transaction feed v2)
})
jest.mock('src/web3/networkConfig', () => {
const originalModule = jest.requireActual('src/web3/networkConfig')
return {
...originalModule,
__esModule: true,
default: {
...originalModule.default,
defaultNetworkId: 'celo-alfajores',
},
}
})
const mockBalances = {
tokens: {
tokenBalances: {
[mockCusdTokenId]: {
address: mockCusdAddress,
tokenId: mockCusdTokenId,
networkId: NetworkId['celo-alfajores'],
symbol: 'cUSD',
decimals: 18,
balance: '1',
isFeeCurrency: true,
priceUsd: '1',
priceFetchedAt: Date.now(),
},
[mockCeurTokenId]: {
address: mockCeurAddress,
tokenId: mockCeurTokenId,
networkId: NetworkId['celo-alfajores'],
symbol: 'cEUR',
decimals: 18,
balance: '0',
priceUsd: '1',
isFeeCurrency: true,
priceFetchedAt: Date.now(),
},
},
},
}
jest.mock('src/statsig', () => ({
getFeatureGate: jest.fn().mockReturnValue(false),
getMultichainFeatures: jest.fn(() => ({
showBalances: ['celo-alfajores'],
showTransfers: ['celo-alfajores'],
})),
}))
jest.mock('src/fiatExchanges/utils', () => ({
...(jest.requireActual('src/fiatExchanges/utils') as any),
fetchProviders: jest.fn(),
}))
describe('TabHome', () => {
const mockFetch = fetch as FetchMock
beforeEach(() => {
jest.clearAllMocks()
jest.mocked(getFeatureGate).mockReturnValue(false)
mockFetch.mockResponse(
JSON.stringify({
data: {
tokenTransactionsV2: {
transactions: [],
},
},
})
)
})
function renderScreen(storeOverrides: RecursivePartial = {}, screenParams = {}) {
const store = createMockStore({
...mockBalances,
...storeOverrides,
})
const tree = render(
)
return {
store,
tree,
...tree,
}
}
it('renders home tab correctly and fires initial actions', async () => {
const { store, tree } = renderScreen({
app: {
phoneNumberVerified: true,
},
recipients: {
phoneRecipientCache: {},
},
})
// Multiple elements use this text with the scroll aware header
expect(tree.getByTestId('HomeActionsCarousel')).toBeTruthy()
expect(tree.queryByText('notificationCenterSpotlight.message')).toBeFalsy()
expect(tree.queryByTestId('HomeTokenBalance')).toBeFalsy()
expect(tree.queryByTestId('cashInBtn')).toBeFalsy()
await waitFor(() =>
expect(store.getActions().map((action) => action.type)).toEqual(
expect.arrayContaining([
'HOME/VISIT_HOME',
'HOME/REFRESH_BALANCES',
'IDENTITY/IMPORT_CONTACTS',
])
)
)
})
it("doesn't import contacts if number isn't verified", async () => {
const { store } = renderScreen({
app: {
phoneNumberVerified: false,
},
recipients: {
phoneRecipientCache: {},
},
})
await waitFor(() =>
expect(store.getActions().map((action) => action.type)).toEqual(
expect.arrayContaining(['HOME/VISIT_HOME', 'HOME/REFRESH_BALANCES'])
)
)
})
it('renders the v2 transaction feed when the feature gate is enabled', async () => {
jest.mocked(getFeatureGate).mockImplementation((featureGate) => {
if (featureGate === StatsigFeatureGates.SHOW_ZERION_TRANSACTION_FEED) {
return true
}
return false
})
const { tree } = renderScreen()
await waitFor(() => expect(tree.getByText('Transaction feed v2')).toBeTruthy())
})
describe('nft reward bottom sheet', () => {
beforeEach(() => {
jest.mocked(getFeatureGate).mockImplementation((featureGate) => {
if (featureGate === StatsigFeatureGates.SHOW_NFT_REWARD) {
return true
}
return false
})
})
afterEach(() => {
jest.clearAllMocks()
jest.useFakeTimers({ doNotFake: ['Date'] })
})
it('renders correctly when status is "reward ready"', async () => {
const { getByText } = renderScreen({
...mockStoreRewardReady,
app: {
showNotificationSpotlight: false,
},
})
await waitFor(() => expect(getByText('nftCelebration.rewardBottomSheet.title')).toBeTruthy())
expect(
getByText('nftCelebration.rewardBottomSheet.description, {"nftName":"John Doe.fizzBuzz"}')
).toBeTruthy()
expect(getByText('nftCelebration.rewardBottomSheet.cta')).toBeTruthy()
})
it('renders correctly when status is "reminder ready"', async () => {
const { getByText } = renderScreen({
...mockStoreReminderReady,
app: {
showNotificationSpotlight: false,
},
})
await waitFor(() =>
expect(getByText('nftCelebration.rewardReminderBottomSheet.title')).toBeTruthy()
)
expect(
getByText(
'nftCelebration.rewardReminderBottomSheet.description, {"nftName":"John Doe.fizzBuzz"}'
)
).toBeTruthy()
expect(getByText('nftCelebration.rewardReminderBottomSheet.cta')).toBeTruthy()
})
it('does not render when status is other than "reward ready" or "reminder ready"', async () => {
const { queryByText } = renderScreen({
...mockStoreCelebrationReady,
app: {
showNotificationSpotlight: false,
},
})
await waitFor(() => expect(queryByText('nftCelebration.rewardBottomSheet.title')).toBeNull())
expect(queryByText('nftCelebration.rewardBottomSheet.description')).toBeNull()
expect(queryByText('nftCelebration.rewardBottomSheet.cta')).toBeNull()
})
it('does not render when celebrated contract does not match with user nft', async () => {
const { queryByText } = renderScreen({
...mockStoreRewardReayWithDifferentNft,
app: {
showNotificationSpotlight: false,
},
})
await waitFor(() => expect(queryByText('nftCelebration.rewardBottomSheet.title')).toBeNull())
expect(queryByText('nftCelebration.rewardBottomSheet.description')).toBeNull()
expect(queryByText('nftCelebration.rewardBottomSheet.cta')).toBeNull()
})
it('does not render when feature gate is closed', async () => {
jest.mocked(getFeatureGate).mockReturnValue(false)
const { queryByText } = renderScreen({
...mockStoreRewardReady,
app: {
showNotificationSpotlight: false,
},
})
await waitFor(() => expect(queryByText('nftCelebration.rewardBottomSheet.title')).toBeNull())
expect(queryByText('nftCelebration.rewardBottomSheet.description')).toBeNull()
expect(queryByText('nftCelebration.rewardBottomSheet.cta')).toBeNull()
})
it('does not render if reward is already displayed', async () => {
const { queryByText } = renderScreen({
...mockStoreRewardDisplayed,
app: {
showNotificationSpotlight: false,
},
})
await waitFor(() => expect(queryByText('nftCelebration.rewardBottomSheet.title')).toBeNull())
expect(queryByText('nftCelebration.rewardBottomSheet.description')).toBeNull()
expect(queryByText('nftCelebration.rewardBottomSheet.cta')).toBeNull()
})
it('does not render if reminder is already displayed', async () => {
const { queryByText } = renderScreen({
...mockStoreReminderDisplayed,
app: {
showNotificationSpotlight: false,
},
})
await waitFor(() => expect(queryByText('nftCelebration.rewardBottomSheet.title')).toBeNull())
expect(queryByText('nftCelebration.rewardBottomSheet.description')).toBeNull()
expect(queryByText('nftCelebration.rewardBottomSheet.cta')).toBeNull()
})
it('does not render if expired', async () => {
jest.useFakeTimers({ now: new Date('3001-01-01T00:00:00.000Z') })
const { queryByText } = renderScreen({
...mockStoreRewardReady,
app: {
showNotificationSpotlight: false,
},
})
await waitFor(() => expect(queryByText('nftCelebration.rewardBottomSheet.title')).toBeNull())
expect(queryByText('nftCelebration.rewardBottomSheet.description')).toBeNull()
expect(queryByText('nftCelebration.rewardBottomSheet.cta')).toBeNull()
})
})
})