@@ -25,9 +25,11 @@ import useMoneyAccountBalance from '../../hooks/useMoneyAccountBalance';
2525import { selectIsCardholder } from '../../../../../selectors/cardController' ;
2626import { getDetectedGeolocation } from '../../../../../reducers/fiatOrders' ;
2727import { moneyFormatFiat } from '../../utils/moneyFormatFiat' ;
28+ import { useMusdConversion } from '../../../Earn/hooks/useMusdConversion' ;
2829
2930const mockGoBack = jest . fn ( ) ;
3031const mockNavigate = jest . fn ( ) ;
32+ const mockInitiateCustomConversion = jest . fn ( ) ;
3133const mockMoneyFormatFiat = moneyFormatFiat as jest . MockedFunction <
3234 typeof moneyFormatFiat
3335> ;
@@ -72,9 +74,16 @@ jest.mock('../../hooks/useMoneyAccountBalance', () => ({
7274} ) ) ;
7375
7476jest . mock ( '../../../Earn/hooks/useMusdConversion' , ( ) => ( {
75- useMusdConversion : ( ) => ( {
76- initiateCustomConversion : jest . fn ( ) ,
77- } ) ,
77+ useMusdConversion : jest . fn ( ) ,
78+ } ) ) ;
79+
80+ jest . mock ( '../../../../../core/NavigationService' , ( ) => ( {
81+ __esModule : true ,
82+ default : {
83+ navigation : {
84+ navigate : jest . fn ( ) ,
85+ } ,
86+ } ,
7887} ) ) ;
7988
8089jest . mock ( '../../utils/moneyFormatFiat' , ( ) => ( {
@@ -98,6 +107,8 @@ const mockUseMoneyAccountTransactions = jest.mocked(
98107 useMoneyAccountTransactions ,
99108) ;
100109
110+ const mockUseMusdConversion = jest . mocked ( useMusdConversion ) ;
111+
101112const mockUseMoneyAccountBalance = jest . mocked ( useMoneyAccountBalance ) ;
102113
103114jest . mock (
@@ -119,13 +130,22 @@ jest.mock('../../../../../component-library/components/Badges/Badge', () => ({
119130} ) ) ;
120131
121132jest . mock ( '../../components/MoneyActivityItem/MoneyActivityItem' , ( ) => {
122- const { View , Text } = jest . requireActual ( 'react-native' ) ;
133+ const { TouchableOpacity , Text } = jest . requireActual ( 'react-native' ) ;
123134 return {
124135 __esModule : true ,
125- default : ( { tx } : { tx : { id : string } } ) => (
126- < View testID = { `money-activity-item-${ tx . id } ` } >
136+ default : ( {
137+ tx,
138+ onPress,
139+ } : {
140+ tx : { id : string } ;
141+ onPress ?: ( ) => void ;
142+ } ) => (
143+ < TouchableOpacity
144+ testID = { `money-activity-item-${ tx . id } ` }
145+ onPress = { onPress }
146+ >
127147 < Text > { tx . id } </ Text >
128- </ View >
148+ </ TouchableOpacity >
129149 ) ,
130150 } ;
131151} ) ;
@@ -134,12 +154,21 @@ jest.mock('@react-native-masked-view/masked-view', () => 'MaskedView');
134154jest . mock ( '../../../../UI/AssetOverview/Balance/Balance' , ( ) => ( {
135155 NetworkBadgeSource : jest . fn ( ( ) => null ) ,
136156} ) ) ;
157+ jest . mock ( '../../../../../util/Logger' , ( ) => ( {
158+ __esModule : true ,
159+ default : { error : jest . fn ( ) } ,
160+ } ) ) ;
137161
138162describe ( 'MoneyHomeView' , ( ) => {
139163 beforeEach ( ( ) => {
140164 jest . clearAllMocks ( ) ;
141165 global . alert = jest . fn ( ) ;
142166
167+ mockInitiateCustomConversion . mockResolvedValue ( undefined ) ;
168+ mockUseMusdConversion . mockReturnValue ( {
169+ initiateCustomConversion : mockInitiateCustomConversion ,
170+ } as unknown as ReturnType < typeof useMusdConversion > ) ;
171+
143172 mockSelectIsCardholder . mockReturnValue ( false ) ;
144173 mockGetDetectedGeolocation . mockReturnValue ( 'US' ) ;
145174
@@ -339,22 +368,31 @@ describe('MoneyHomeView', () => {
339368
340369 expect ( mockNavigate ) . toHaveBeenCalledWith ( Routes . MONEY . MODALS . ROOT , {
341370 screen : Routes . MONEY . MODALS . EARNINGS_INFO_SHEET ,
342- params : { apy : 5 } ,
343371 } ) ;
344372 } ) ;
345373
346- describe ( 'projected earnings' , ( ) => {
347- it ( 'passes the formatted projected earnings to MoneyEarnings' , ( ) => {
374+ describe ( 'monthly and yearly earnings' , ( ) => {
375+ it ( 'passes the formatted monthly earnings to MoneyEarnings' , ( ) => {
348376 mockMoneyFormatFiat . mockReturnValue ( '$0.12' ) ;
349377
350378 const { getByTestId } = renderWithProvider ( < MoneyHomeView /> ) ;
351379
352- expect (
353- getByTestId ( MoneyEarningsTestIds . PROJECTED_VALUE ) ,
354- ) . toHaveTextContent ( '$0.12' ) ;
380+ expect ( getByTestId ( MoneyEarningsTestIds . MONTHLY_VALUE ) ) . toHaveTextContent (
381+ '$0.12' ,
382+ ) ;
383+ } ) ;
384+
385+ it ( 'passes the formatted yearly earnings to MoneyEarnings' , ( ) => {
386+ mockMoneyFormatFiat . mockReturnValue ( '$0.12' ) ;
387+
388+ const { getByTestId } = renderWithProvider ( < MoneyHomeView /> ) ;
389+
390+ expect ( getByTestId ( MoneyEarningsTestIds . YEARLY_VALUE ) ) . toHaveTextContent (
391+ '$0.12' ,
392+ ) ;
355393 } ) ;
356394
357- it ( 'displays the zero-formatted value for projected earnings when totalFiatRaw is absent' , ( ) => {
395+ it ( 'displays the zero-formatted value for monthly earnings when totalFiatRaw is absent' , ( ) => {
358396 mockMoneyFormatFiat . mockReturnValue ( '$0.00' ) ;
359397 mockUseMoneyAccountBalance . mockReturnValue ( {
360398 totalFiatFormatted : undefined ,
@@ -373,9 +411,9 @@ describe('MoneyHomeView', () => {
373411
374412 const { getByTestId } = renderWithProvider ( < MoneyHomeView /> ) ;
375413
376- expect (
377- getByTestId ( MoneyEarningsTestIds . PROJECTED_VALUE ) ,
378- ) . toHaveTextContent ( '$0.00' ) ;
414+ expect ( getByTestId ( MoneyEarningsTestIds . MONTHLY_VALUE ) ) . toHaveTextContent (
415+ '$0.00' ,
416+ ) ;
379417 } ) ;
380418 } ) ;
381419
@@ -599,6 +637,107 @@ describe('MoneyHomeView', () => {
599637 screen : Routes . MONEY . MODALS . ADD_MONEY_SHEET ,
600638 } ) ;
601639 } ) ;
640+
641+ it ( 'navigates to Asset details when the mUSD token row is pressed' , ( ) => {
642+ const NavigationService = jest . requireMock (
643+ '../../../../../core/NavigationService' ,
644+ ) . default ;
645+
646+ const { getByTestId } = renderWithProvider ( < MoneyHomeView /> ) ;
647+
648+ fireEvent . press ( getByTestId ( MoneyMusdTokenRowTestIds . CONTAINER ) ) ;
649+
650+ expect ( NavigationService . navigation . navigate ) . toHaveBeenCalledWith (
651+ 'Asset' ,
652+ expect . objectContaining ( { source : expect . any ( String ) } ) ,
653+ ) ;
654+ } ) ;
655+
656+ it ( 'navigates to HowItWorks when its section header is pressed' , ( ) => {
657+ const { getByText } = renderWithProvider ( < MoneyHomeView /> ) ;
658+
659+ fireEvent . press ( getByText ( strings ( 'money.how_it_works.title' ) ) ) ;
660+
661+ expect ( mockNavigate ) . toHaveBeenCalledWith ( Routes . MONEY . HOW_IT_WORKS ) ;
662+ } ) ;
663+
664+ it ( 'opens the Learn more URL when Learn more is pressed' , ( ) => {
665+ const { Linking } = jest . requireMock ( 'react-native' ) ;
666+ const { getByTestId } = renderWithProvider ( < MoneyHomeView /> ) ;
667+
668+ fireEvent . press ( getByTestId ( MoneyWhatYouGetTestIds . LEARN_MORE_BUTTON ) ) ;
669+
670+ expect ( Linking . openURL ) . toHaveBeenCalledWith (
671+ expect . stringContaining ( 'http' ) ,
672+ ) ;
673+ } ) ;
674+ } ) ;
675+
676+ describe ( 'filled state navigation handlers' , ( ) => {
677+ it ( 'navigates to Potential Earnings when View all is pressed on potential earnings section' , ( ) => {
678+ const { getByTestId } = renderWithProvider ( < MoneyHomeView /> ) ;
679+
680+ fireEvent . press (
681+ getByTestId ( MoneyPotentialEarningsTestIds . VIEW_ALL_BUTTON ) ,
682+ ) ;
683+
684+ expect ( mockNavigate ) . toHaveBeenCalledWith (
685+ Routes . MONEY . POTENTIAL_EARNINGS ,
686+ ) ;
687+ } ) ;
688+
689+ it ( 'initiates a custom conversion when a token Convert button is pressed' , async ( ) => {
690+ const { getByText } = renderWithProvider ( < MoneyHomeView /> ) ;
691+
692+ fireEvent . press ( getByText ( strings ( 'money.potential_earnings.convert' ) ) ) ;
693+
694+ expect ( mockInitiateCustomConversion ) . toHaveBeenCalledWith (
695+ expect . objectContaining ( {
696+ preferredPaymentToken : expect . objectContaining ( {
697+ address : mockConversionTokens [ 0 ] . address ,
698+ } ) ,
699+ navigationStack : Routes . MONEY . ROOT ,
700+ } ) ,
701+ ) ;
702+ } ) ;
703+
704+ it ( 'logs an error when initiateCustomConversion rejects' , async ( ) => {
705+ mockInitiateCustomConversion . mockRejectedValueOnce (
706+ new Error ( 'network failure' ) ,
707+ ) ;
708+ const Logger = jest . requireMock ( '../../../../../util/Logger' ) ;
709+
710+ const { getByText } = renderWithProvider ( < MoneyHomeView /> ) ;
711+
712+ fireEvent . press ( getByText ( strings ( 'money.potential_earnings.convert' ) ) ) ;
713+
714+ await Promise . resolve ( ) ;
715+
716+ expect ( Logger . default . error ) . toHaveBeenCalledWith (
717+ expect . any ( Error ) ,
718+ expect . objectContaining ( {
719+ message : expect . stringContaining ( 'MoneyHomeView' ) ,
720+ } ) ,
721+ ) ;
722+ } ) ;
723+
724+ it ( 'triggers the under-construction alert when an activity item is pressed' , ( ) => {
725+ const { getByTestId } = renderWithProvider ( < MoneyHomeView /> ) ;
726+
727+ fireEvent . press ( getByTestId ( 'money-activity-item-padded-0' ) ) ;
728+
729+ expect ( global . alert ) . toHaveBeenCalled ( ) ;
730+ } ) ;
731+ } ) ;
732+
733+ describe ( 'card upsell mode — Get Now handler' , ( ) => {
734+ it ( 'navigates to Card root when the Get Now card row is pressed' , ( ) => {
735+ const { getByTestId } = renderWithProvider ( < MoneyHomeView /> ) ;
736+
737+ fireEvent . press ( getByTestId ( MoneyMetaMaskCardTestIds . VIRTUAL_CARD_ROW ) ) ;
738+
739+ expect ( mockNavigate ) . toHaveBeenCalledWith ( Routes . CARD . ROOT ) ;
740+ } ) ;
602741 } ) ;
603742
604743 describe ( 'Metal card geolocation gating' , ( ) => {
0 commit comments