import { render } from '@testing-library/react-native' import BigNumber from 'bignumber.js' import React from 'react' import { View } from 'react-native' import { Provider } from 'react-redux' import { LocalCurrencySymbol } from 'src/localCurrency/consts' import { type Recipient } from 'src/recipients/recipient' import { typeScale } from 'src/styles/fonts' import { TokenBalance } from 'src/tokens/slice' import Logger from 'src/utils/Logger' import { createMockStore } from 'test/utils' import { mockCeloTokenId, mockCusdTokenId, mockTokenBalances } from 'test/values' import { ReviewContent, ReviewDetailsItem, ReviewSummaryItem, ReviewSummaryItemContact, ReviewTotalValue, ReviewTransaction, } from './ReviewTransaction' jest.mock('src/utils/Logger') describe('ReviewTransaction', () => { it('uses the custom headerAction if provided', async () => { const tree = render( Custom Left Button} > <> ) expect(tree.getByTestId('Review')).toHaveTextContent('Custom Left Button') }) }) describe('ReviewSummaryItem', () => { it('renders the title and optional subtitle', () => { const tree = render( Item Icon} /> ) expect(tree.getByTestId('MyItem/Label')).toHaveTextContent('Item Label') expect(tree.getByTestId('MyItem/PrimaryValue')).toHaveTextContent('Item Primary Value') expect(tree.getByTestId('MyItem/SecondaryValue')).toHaveTextContent('Item Secondary Value') expect(tree.getByTestId('MyItem')).toHaveTextContent('Item Icon') }) it('does not render subtitle if not provided', () => { const tree = render( } /> ) expect(tree.queryByTestId('NoSubtitleItem/SecondaryValue')).toBeNull() }) }) describe('ReviewSummaryItemContact', () => { it('displays name + phone if recipient has a name and phone number', () => { const recipient = { name: 'John Doe', displayNumber: '+111111111', e164PhoneNumber: '+222222222', } as Recipient const tree = render() expect(tree.getByTestId('ContactItem/PrimaryValue')).toHaveTextContent('John Doe') expect(tree.getByTestId('ContactItem/SecondaryValue')).toHaveTextContent('+111111111') }) it.each([ { phoneNumberType: 'displayNumber', displayNumber: '+111111111', e164PhoneNumber: '+222222222', expectedDisplayedValue: '+111111111', }, { phoneNumberType: 'e164PhoneNumber', displayNumber: undefined, e164PhoneNumber: '+222222222', expectedDisplayedValue: '+222222222', }, ])( 'displays only $phoneNumberType phone if name is not available', ({ displayNumber, e164PhoneNumber, expectedDisplayedValue }) => { const recipient = { displayNumber, e164PhoneNumber } as Recipient const tree = render() expect(tree.getByTestId('ContactItem/PrimaryValue')).toHaveTextContent(expectedDisplayedValue) expect(tree.queryByTestId('ContactItem/SecondaryValue')).toBeNull() } ) it('displays address if name/phone not available', () => { const recipient = { address: '0x123456789', } as Recipient const tree = render() expect(tree.getByTestId('ContactItem/PrimaryValue')).toHaveTextContent('0x123456789') }) it('logs an error if no name/phone/address exist', () => { const recipient = {} as Recipient const tree = render() expect(Logger.error).toHaveBeenCalledTimes(1) expect(tree.toJSON()).toBeNull() }) }) describe('ReviewDetailsItem', () => { it('renders loading skeleton if isLoading is true', () => { const tree = render( ) expect(tree.getByTestId('LoadingItem/Loader')).toBeTruthy() expect(tree.queryByText('Should not show')).toBeNull() }) it('renders value text if isLoading is false', () => { const tree = render() expect(tree.queryByTestId('DetailsItem/Loader')).toBeNull() expect(tree.getByTestId('DetailsItem/Value')).toHaveTextContent('Value') }) it('applies bold variant if specified', () => { const tree = render( ) expect(tree.getByTestId('BoldItem/Label')).toHaveStyle(typeScale.labelSemiBoldMedium) }) }) describe('ReviewTotalValue', () => { const celoToken = mockTokenBalances[mockCeloTokenId] as unknown as TokenBalance const cUSDToken = mockTokenBalances[mockCusdTokenId] as unknown as TokenBalance it.each([ { tokenInfo: { ...celoToken, priceUsd: new BigNumber(1) }, tokenAmount: new BigNumber(10), localAmount: new BigNumber(10), feeTokenInfo: undefined, feeTokenAmount: undefined, feeLocalAmount: null, title: 'returns the token and fiat amount when fee info is missing and local price is available', result: 'tokenAndLocalAmountApprox, {"tokenAmount":"10.00","localAmount":"10.00","tokenSymbol":"CELO","localCurrencySymbol":"₱"}', }, { tokenInfo: { ...celoToken, priceUsd: null }, tokenAmount: new BigNumber(10), localAmount: null, feeTokenInfo: undefined, feeTokenAmount: undefined, feeLocalAmount: null, title: 'returns only the token amount when fee info is missing and no local price is available', result: 'tokenAmountApprox, {"tokenAmount":"10.00","tokenSymbol":"CELO"}', }, { tokenInfo: { ...celoToken, priceUsd: new BigNumber(1) }, tokenAmount: new BigNumber(10), localAmount: new BigNumber(10), feeTokenInfo: { ...celoToken, priceUsd: new BigNumber(1) }, feeTokenAmount: new BigNumber(0.5), feeLocalAmount: new BigNumber(0.5), title: 'returns the token and local amount when the token and fee token are the same and local price is available', result: 'tokenAndLocalAmountApprox, {"tokenAmount":"10.50","localAmount":"10.50","tokenSymbol":"CELO","localCurrencySymbol":"₱"}', }, { tokenInfo: { ...celoToken, priceUsd: null }, tokenAmount: new BigNumber(10), localAmount: null, feeTokenInfo: { ...celoToken, priceUsd: null }, feeTokenAmount: new BigNumber(0.5), feeLocalAmount: null, title: "returns only the token amount when token and fee token are the same but they don't have local price", result: 'tokenAmountApprox, {"tokenAmount":"10.50","tokenSymbol":"CELO"}', }, { tokenInfo: { ...cUSDToken, priceUsd: new BigNumber(1) }, tokenAmount: new BigNumber(10), localAmount: new BigNumber(10), feeTokenInfo: { ...celoToken, priceUsd: new BigNumber(1) }, feeTokenAmount: new BigNumber(0.5), feeLocalAmount: new BigNumber(0.5), title: 'returns only the local amount when token and fee token are different but local prices are available for both', result: 'localAmountApprox, {"localAmount":"10.50","localCurrencySymbol":"₱"}', }, { tokenInfo: { ...cUSDToken, priceUsd: null }, tokenAmount: new BigNumber(10), localAmount: null, feeTokenInfo: { ...celoToken, priceUsd: null }, feeTokenAmount: new BigNumber(0.5), feeLocalAmount: null, title: 'returns multiple token amounts when token and fee token are different and no local prices available', result: 'reviewTransaction.multipleTokensWithPlusSign, {"amount1":"10.00","symbol1":"cUSD","amount2":"0.50","symbol2":"CELO"}', }, ])( '$title', ({ tokenInfo, tokenAmount, localAmount, feeTokenInfo, feeTokenAmount, feeLocalAmount, result, }) => { const tree = render( ) expect(tree.getByTestId('Total')).toHaveTextContent(result) } ) })