Skip to content
Open
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ import MoneyActivityView from './MoneyActivityView';
import { MoneyActivityViewTestIds } from './MoneyActivityView.testIds';

const mockGoBack = jest.fn();
const mockNavigate = jest.fn();

jest.mock('@react-navigation/native', () => {
const actualReactNavigation = jest.requireActual('@react-navigation/native');
return {
...actualReactNavigation,
useNavigation: () => ({
goBack: mockGoBack,
navigate: jest.fn(),
navigate: mockNavigate,
}),
};
});
Expand All @@ -32,13 +33,26 @@ jest.mock('../../hooks/useMoneyAccountTransactions', () => ({
}));

jest.mock('../../components/MoneyActivityItem/MoneyActivityItem', () => {
const { View, Text } = jest.requireActual('react-native');
const {
View,
Text,
Pressable: RNPressable,
} = jest.requireActual('react-native');
return {
__esModule: true,
default: ({ tx }: { tx: { id: string } }) => (
<View testID={`activity-mock-tx-${tx.id}`}>
default: ({
tx,
onPress,
}: {
tx: { id: string };
onPress?: (id: string) => void;
}) => (
<RNPressable
testID={`activity-mock-tx-${tx.id}`}
onPress={() => onPress?.(tx.id)}
>
<Text>{tx.id}</Text>
</View>
</RNPressable>
),
};
});
Expand Down Expand Up @@ -74,6 +88,7 @@ describe('MoneyActivityView', () => {
transfers: MOCK_TRANSFERS,
submittedTransactions: [],
moneyAddress: '0x0000000000000000000000000000000000000001',
mockDataEnabled: false,
});
});

Expand Down Expand Up @@ -144,6 +159,7 @@ describe('MoneyActivityView', () => {
transfers: [],
submittedTransactions: [],
moneyAddress: '0x0000000000000000000000000000000000000001',
mockDataEnabled: false,
});

const { getByTestId } = renderWithProvider(<MoneyActivityView />);
Expand All @@ -153,4 +169,12 @@ describe('MoneyActivityView', () => {
getByTestId(MoneyActivityViewTestIds.EMPTY_LIST_MESSAGE),
).toBeOnTheScreen();
});

it('pressing a row navigates to the transaction details sheet when mockDataEnabled is false', () => {
const { getByTestId } = renderWithProvider(<MoneyActivityView />);

fireEvent.press(getByTestId('activity-mock-tx-money-tx-1'));

expect(mockNavigate).toHaveBeenCalledTimes(1);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import MoneyActivityItem from '../../components/MoneyActivityItem';
import { useMoneyAccountTransactions } from '../../hooks/useMoneyAccountTransactions';
import { getMoneyActivityDateKeyUtc } from '../../constants/moneyActivityFilters';
import { MoneyActivityFilter } from '../../constants/mockActivityData';
import { showMoneyActivityUnderConstructionAlert } from '../../constants/showMoneyActivityUnderConstructionAlert';
import Routes from '../../../../../constants/navigation/Routes';
import { MoneyActivityViewTestIds } from './MoneyActivityView.testIds';

const styles = StyleSheet.create({
Expand Down Expand Up @@ -67,16 +67,27 @@ const MoneyActivityView = () => {
const { colors } = useTheme();
const [filter, setFilter] = useState(MoneyActivityFilter.All);

const { allTransactions, deposits, transfers, moneyAddress } =
useMoneyAccountTransactions();
const {
allTransactions,
deposits,
transfers,
moneyAddress,
mockDataEnabled,
} = useMoneyAccountTransactions();

const handleBackPress = useCallback(() => {
navigation.goBack();
}, [navigation]);

const handleItemPress = useCallback(() => {
showMoneyActivityUnderConstructionAlert();
}, []);
const handleItemPress = useCallback(
(transactionId: string) => {
navigation.navigate(Routes.MONEY.MODALS.ROOT, {
screen: Routes.MONEY.MODALS.TRANSACTION_DETAILS_SHEET,
params: { transactionId },
});
},
[navigation],
);

const filtered = useMemo(() => {
if (filter === MoneyActivityFilter.All) {
Expand Down Expand Up @@ -110,7 +121,7 @@ const MoneyActivityView = () => {
<MoneyActivityItem
tx={item}
moneyAddress={moneyAddress}
onPress={handleItemPress}
onPress={mockDataEnabled ? undefined : handleItemPress}
/>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ describe('MoneyHomeView', () => {
transfers: [],
submittedTransactions: [],
moneyAddress: '0x0000000000000000000000000000000000000001',
mockDataEnabled: false,
});
});

Expand Down Expand Up @@ -432,6 +433,7 @@ describe('MoneyHomeView', () => {
transfers: [],
submittedTransactions: [],
moneyAddress: '0x0000000000000000000000000000000000000001',
mockDataEnabled: false,
});

const { getByTestId } = renderWithProvider(<MoneyHomeView />);
Expand Down Expand Up @@ -530,6 +532,7 @@ describe('MoneyHomeView', () => {
transfers: [],
submittedTransactions: [],
moneyAddress: '0x0000000000000000000000000000000000000001',
mockDataEnabled: false,
});
});

Expand Down Expand Up @@ -591,6 +594,7 @@ describe('MoneyHomeView', () => {
transfers: [],
submittedTransactions: [],
moneyAddress: '0x0000000000000000000000000000000000000001',
mockDataEnabled: false,
});
mockSelectIsCardholder.mockReturnValue(true);
// Non-US so MetaMask card renders in link mode (manage mode is US-only).
Expand Down Expand Up @@ -774,6 +778,7 @@ describe('MoneyHomeView', () => {
transfers: [],
submittedTransactions: [],
moneyAddress: '0x0000000000000000000000000000000000000001',
mockDataEnabled: false,
});
});

Expand Down Expand Up @@ -910,14 +915,6 @@ describe('MoneyHomeView', () => {
}),
);
});

it('triggers the under-construction alert when an activity item is pressed', () => {
const { getByTestId } = renderWithProvider(<MoneyHomeView />);

fireEvent.press(getByTestId('money-activity-item-padded-0'));

expect(global.alert).toHaveBeenCalled();
});
});

describe('card upsell mode — Get Now handler', () => {
Expand Down Expand Up @@ -996,6 +993,7 @@ describe('MoneyHomeView', () => {
transfers: [],
submittedTransactions: [],
moneyAddress: '0x0000000000000000000000000000000000000001',
mockDataEnabled: false,
});
});

Expand Down
20 changes: 14 additions & 6 deletions app/components/UI/Money/Views/MoneyHomeView/MoneyHomeView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import styleSheet from './MoneyHomeView.styles';
import { useMusdConversionTokens } from '../../../Earn/hooks/useMusdConversionTokens';
import { useMusdConversion } from '../../../Earn/hooks/useMusdConversion';
import { useMoneyAccountTransactions } from '../../hooks/useMoneyAccountTransactions';
import { showMoneyActivityUnderConstructionAlert } from '../../constants/showMoneyActivityUnderConstructionAlert';
import useMoneyAccountBalance from '../../hooks/useMoneyAccountBalance';
import { selectCurrentCurrency } from '../../../../../selectors/currencyRateController';
import { moneyFormatFiat } from '../../utils/moneyFormatFiat';
Expand Down Expand Up @@ -68,7 +67,8 @@ const MoneyHomeView = () => {

const { tokens: conversionTokens } = useMusdConversionTokens();
const { initiateCustomConversion } = useMusdConversion();
const { allTransactions, moneyAddress } = useMoneyAccountTransactions();
const { allTransactions, moneyAddress, mockDataEnabled } =
useMoneyAccountTransactions();

const isCardholder = useSelector(selectIsCardholder);
const { canLink, openLinkCardSheet } = useMoneyAccountCardLinkage();
Expand Down Expand Up @@ -206,9 +206,15 @@ const MoneyHomeView = () => {
}, [navigation]);
const handleActivityHeaderPress = handleViewAllActivityPress;

const handleActivityItemPress = useCallback(() => {
showMoneyActivityUnderConstructionAlert();
Comment thread
shane-t marked this conversation as resolved.
}, []);
const handleActivityItemPress = useCallback(
(transactionId: string) => {
navigation.navigate(Routes.MONEY.MODALS.ROOT, {
screen: Routes.MONEY.MODALS.TRANSACTION_DETAILS_SHEET,
params: { transactionId },
});
},
[navigation],
);

const handleOnboardingCtaPress = useCallback(() => {
if (isCardholderWithMilestone) {
Expand Down Expand Up @@ -305,7 +311,9 @@ const MoneyHomeView = () => {
: handleViewAllActivityPress
}
onHeaderPress={handleActivityHeaderPress}
onItemPress={handleActivityItemPress}
onItemPress={
mockDataEnabled ? undefined : handleActivityItemPress
}
/>
<Divider />
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import React from 'react';
import { fireEvent } from '@testing-library/react-native';
import {
type TransactionMeta,
TransactionStatus,
TransactionType,
} from '@metamask/transaction-controller';
import { IconName } from '@metamask/design-system-react-native';
import type { Hex } from '@metamask/utils';
import renderWithProvider from '../../../../../util/test/renderWithProvider';
import { useMoneyTransactionDisplayInfo } from '../../hooks/useMoneyTransactionDisplayInfo';
import { MUSD_TOKEN_ADDRESS } from '../../../Earn/constants/musd';
import MoneyActivityItem from './MoneyActivityItem';
import { MoneyActivityItemTestIds } from './MoneyActivityItem.testIds';

Expand All @@ -17,12 +18,6 @@ const baseTx = {
id: 'tx-row-1',
chainId: MOCK_CHAIN,
type: TransactionType.incoming,
transferInformation: {
amount: '1000000000',
symbol: 'mUSD',
decimals: 6,
contractAddress: MUSD_TOKEN_ADDRESS,
},
} as unknown as TransactionMeta;

jest.mock('../../hooks/useMoneyTransactionDisplayInfo');
Expand All @@ -31,13 +26,16 @@ jest.mock('../../../../../util/networks', () => ({
getNetworkImageSource: jest.fn(() => ({ uri: 'network' })),
}));

jest.mock(
'../../../../../component-library/components/Avatars/Avatar/variants/AvatarToken',
() => {
const { View } = jest.requireActual('react-native');
return () => <View testID="mock-avatar-token" />;
},
);
jest.mock('@metamask/design-system-react-native', () => {
const actual = jest.requireActual('@metamask/design-system-react-native');
const { View } = jest.requireActual('react-native');
return {
...actual,
AvatarIcon: ({ testID }: { testID?: string }) => (
<View testID={testID ?? 'mock-avatar-icon'} />
),
};
});

jest.mock(
'../../../../../component-library/components/Badges/BadgeWrapper',
Expand Down Expand Up @@ -83,6 +81,7 @@ describe('MoneyActivityItem', () => {
primaryAmount: '+$0.00',
fiatAmount: '$0.00',
isIncoming: true,
icon: IconName.Arrow2Down,
});
});

Expand All @@ -100,13 +99,22 @@ describe('MoneyActivityItem', () => {
).toBeOnTheScreen();
});

it('renders the avatar icon', () => {
const { getByTestId } = renderWithProvider(
<MoneyActivityItem tx={baseTx} moneyAddress="0x1" />,
);

expect(getByTestId(MoneyActivityItemTestIds.ICON)).toBeOnTheScreen();
});

it('omits description when hook returns undefined description', () => {
mockUseMoneyTransactionDisplayInfo.mockReturnValue({
label: 'Label',
description: undefined,
primaryAmount: '+$0.00',
fiatAmount: '$0.00',
isIncoming: false,
icon: IconName.Arrow2Down,
});

const { queryByText } = renderWithProvider(
Expand All @@ -116,7 +124,7 @@ describe('MoneyActivityItem', () => {
expect(queryByText('Description')).toBeNull();
});

it('invokes onPress when the row is pressed', () => {
it('invokes onPress with transaction id when the row is pressed', () => {
const onPress = jest.fn();
const { getByTestId } = renderWithProvider(
<MoneyActivityItem tx={baseTx} moneyAddress="0x1" onPress={onPress} />,
Expand All @@ -125,6 +133,22 @@ describe('MoneyActivityItem', () => {
fireEvent.press(getByTestId(`${MoneyActivityItemTestIds.ROW}-tx-row-1`));

expect(onPress).toHaveBeenCalledTimes(1);
expect(onPress).toHaveBeenCalledWith('tx-row-1');
});

it('shows "Failed" in the description slot for a failed transaction', () => {
const failedTx = {
...baseTx,
status: TransactionStatus.failed,
} as unknown as TransactionMeta;

const { getByText, queryByText } = renderWithProvider(
<MoneyActivityItem tx={failedTx} moneyAddress="0x1" />,
);

expect(getByText('Failed')).toBeOnTheScreen();
// Normal description should not appear for failed rows
expect(queryByText('Description')).toBeNull();
});

it('renders network badge subtree when showNetworkBadge is true', () => {
Expand All @@ -134,5 +158,6 @@ describe('MoneyActivityItem', () => {

expect(getByTestId('mock-badge-wrapper')).toBeOnTheScreen();
expect(getByTestId('mock-network-badge')).toBeOnTheScreen();
expect(getByTestId(MoneyActivityItemTestIds.ICON)).toBeOnTheScreen();
});
});
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export const MoneyActivityItemTestIds = {
ROW: 'money-activity-item-row',
ICON: 'money-activity-item-icon',
};
Loading
Loading