Skip to content
Open
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import React from 'react';
import { fireEvent } from '@testing-library/react-native';
import { fireEvent, render, waitFor } from '@testing-library/react-native';
import { AccountGroupId, AccountWalletId } from '@metamask/account-api';
import { SolAccountType, EthScope, SolScope } from '@metamask/keyring-api';
import {
IconName,
Toast,
ToastCloseButtonVariant,
ToastVariant,
} from '@metamask/design-system-react-native';

import { createMockInternalAccount } from '../../../../util/test/accountsControllerTestUtils';
import renderWithProvider from '../../../../util/test/renderWithProvider';
Expand All @@ -10,6 +16,8 @@ import { AddressList } from './AddressList';
import { MULTICHAIN_ADDRESS_ROW_QR_BUTTON_TEST_ID } from '../../../../component-library/components-temp/MultichainAccounts/MultichainAddressRow';
import { toFormattedAddress } from '../../../../util/address';
import { EVENT_NAME } from '../../../../core/Analytics/MetaMetrics.events';
import { strings } from '../../../../../locales/i18n';
import { AddressListIds } from './AddressList.testIds';

const ACCOUNT_WALLET_ID = 'entropy:wallet-id-1' as AccountWalletId;
const ACCOUNT_GROUP_ID = 'entropy:wallet-id-1/1' as AccountGroupId;
Expand Down Expand Up @@ -55,6 +63,23 @@ jest.mock('../../../../core/ClipboardManager', () => ({
setString: jest.fn(),
}));

jest.mock('@metamask/design-system-react-native', () => {
const actualDesignSystem = jest.requireActual(
'@metamask/design-system-react-native',
);

return {
...actualDesignSystem,
Toast: Object.assign(
jest.fn(() => null),
{
show: jest.fn(),
hide: jest.fn(),
},
),
};
});

const mockEthEoaAccount = {
...createMockInternalAccount(
'0x4fec2622fb662e892dd0e5060b91fa49ddcfdcb5',
Expand Down Expand Up @@ -193,6 +218,27 @@ describe('AddressList', () => {
});
});

it('calls navigation.goBack from the header back button', () => {
renderWithAddressList();

const navOptionsWithHeader = mockSetOptions.mock.calls
.map(([opts]) => opts)
.find(
(opts) =>
opts &&
opts.headerShown === true &&
typeof opts.header === 'function',
);

expect(navOptionsWithHeader).toBeDefined();

const { getByTestId, unmount } = render(navOptionsWithHeader.header());
fireEvent.press(getByTestId(AddressListIds.GO_BACK));

expect(mockGoBack).toHaveBeenCalled();
unmount();
});

it('does not set navigation options when title is not provided', () => {
const { useParams } = jest.requireMock(
'../../../../util/navigation/navUtils',
Expand Down Expand Up @@ -307,5 +353,39 @@ describe('AddressList', () => {

expect(addPropertiesCall).toHaveProperty('location', 'address-list');
});

it('shows and dismisses the design system copy toast', async () => {
const { getAllByTestId } = renderWithAddressList();

const copyButton = getAllByTestId(
'multichain-address-row-copy-button',
)[0];
fireEvent.press(copyButton);

const toastShowMock = jest.mocked(Toast.show);

await waitFor(() => {
expect(toastShowMock).toHaveBeenCalledWith({
variant: ToastVariant.Plain,
labelOptions: [
{
label: strings('notifications.address_copied_to_clipboard'),
},
],
hasNoTimeout: false,
closeButtonOptions: {
variant: ToastCloseButtonVariant.Icon,
iconName: IconName.Close,
onPress: expect.any(Function),
},
});
});

const toastOptions = toastShowMock.mock.calls[0][0];
const closeToast = toastOptions.closeButtonOptions?.onPress as () => void;
closeToast();

expect(Toast.hide).toHaveBeenCalled();
});
});
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, useContext, useLayoutEffect } from 'react';
import React, { useCallback, useLayoutEffect } from 'react';
import { View } from 'react-native';
import { useSelector } from 'react-redux';
import { useNavigation } from '@react-navigation/native';
Expand All @@ -7,7 +7,12 @@ import { FlashList } from '@shopify/flash-list';
import { useStyles } from '../../../hooks/useStyles';
import { useAnalytics } from '../../../hooks/useAnalytics/useAnalytics';
import { selectInternalAccountListSpreadByScopesByGroupId } from '../../../../selectors/multichainAccounts/accounts';
import { IconName } from '@metamask/design-system-react-native';
import {
IconName,
Toast,
ToastCloseButtonVariant,
ToastVariant,
} from '@metamask/design-system-react-native';
import MultichainAddressRow, {
MULTICHAIN_ADDRESS_ROW_QR_BUTTON_TEST_ID,
} from '../../../../component-library/components-temp/MultichainAccounts/MultichainAddressRow';
Expand All @@ -22,7 +27,6 @@ import styleSheet from './styles';
import type { AddressListProps, AddressItem } from './types';
import ClipboardManager from '../../../../core/ClipboardManager';
import getHeaderCompactStandardNavbarOptions from '../../../../component-library/components-temp/HeaderCompactStandard/getHeaderCompactStandardNavbarOptions';
import { ToastContext } from '../../../../component-library/components/Toast';
import { strings } from '../../../../../locales/i18n';
import { EVENT_NAME } from '../../../../core/Analytics/MetaMetrics.events';

Expand All @@ -39,7 +43,6 @@ export const createAddressListNavigationDetails =
export const AddressList = () => {
const navigation = useNavigation();
const { styles } = useStyles(styleSheet, {});
const { toastRef } = useContext(ToastContext);
const { trackEvent, createEventBuilder } = useAnalytics();

const { groupId, title, onLoad } = useParams<AddressListProps>();
Expand Down Expand Up @@ -71,8 +74,23 @@ export const AddressList = () => {
address={item.account.address}
copyParams={{
toastMessage: strings('notifications.address_copied_to_clipboard'),
callback: copyAddressToClipboard,
toastRef,
callback: async () => {
await copyAddressToClipboard();
Toast.show({
variant: ToastVariant.Plain,
labelOptions: [
{
label: strings('notifications.address_copied_to_clipboard'),
},
],
hasNoTimeout: false,
closeButtonOptions: {
variant: ToastCloseButtonVariant.Icon,
iconName: IconName.Close,
onPress: () => Toast.hide(),
},
});
},
}}
icons={[
{
Expand All @@ -98,7 +116,7 @@ export const AddressList = () => {
/>
);
},
[navigation, groupId, toastRef, trackEvent, createEventBuilder],
[navigation, groupId, trackEvent, createEventBuilder],
);

useLayoutEffect(() => {
Expand All @@ -123,6 +141,7 @@ export const AddressList = () => {
renderItem={renderAddressItem}
onLoad={onLoad}
/>
<Toast />
</View>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -15,31 +15,28 @@ const mockDispatch = jest.fn();
// Mock the BottomSheet component
const mockOnCloseBottomSheet = jest.fn();
// eslint-disable-next-line import-x/no-commonjs
jest.mock(
'../../../../component-library/components/BottomSheets/BottomSheet',
() => {
// eslint-disable-next-line @typescript-eslint/no-require-imports, import-x/no-commonjs, @typescript-eslint/no-var-requires
const ReactMock = require('react');
return {
__esModule: true,
default: ReactMock.forwardRef(
(
{ children }: { children: React.ReactNode },
ref: React.Ref<{ onCloseBottomSheet: () => void }>,
) => {
ReactMock.useImperativeHandle(ref, () => ({
onCloseBottomSheet: mockOnCloseBottomSheet,
}));
return ReactMock.createElement(
'View',
{ testID: 'bottom-sheet' },
children,
);
},
),
};
},
);
jest.mock('@metamask/design-system-react-native', () => {
const actualDesignSystem = jest.requireActual(
'@metamask/design-system-react-native',
);
// eslint-disable-next-line @typescript-eslint/no-require-imports, import-x/no-commonjs, @typescript-eslint/no-var-requires
const ReactMock = require('react');

return {
...actualDesignSystem,
BottomSheet: ReactMock.forwardRef(
(
{ children, testID }: { children: React.ReactNode; testID?: string },
ref: React.Ref<{ onCloseBottomSheet: () => void }>,
) => {
ReactMock.useImperativeHandle(ref, () => ({
onCloseBottomSheet: mockOnCloseBottomSheet,
}));
return ReactMock.createElement('View', { testID }, children);
},
),
};
});

// Mock React Navigation
jest.mock('@react-navigation/native', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@ import {
Button,
ButtonVariant,
ButtonBaseSize,
BottomSheet,
type BottomSheetRef,
} from '@metamask/design-system-react-native';
import BottomSheet, {
BottomSheetRef,
} from '../../../../component-library/components/BottomSheets/BottomSheet';
import { useNavigation, useTheme } from '@react-navigation/native';
import { strings } from '../../../../../locales/i18n';
import { useStyles } from '../../../../component-library/hooks';
Expand Down Expand Up @@ -63,7 +62,11 @@ const LearnMoreBottomSheet: React.FC<LearnMoreBottomSheetProps> = ({
}, [isCheckboxChecked, navigation, isBasicFunctionalityEnabled, dispatch]);

return (
<BottomSheet ref={sheetRef} onClose={onClose}>
<BottomSheet
ref={sheetRef}
onClose={onClose}
testID={LEARN_MORE_BOTTOM_SHEET_TEST_IDS.BOTTOM_SHEET}
>
<View style={styles.container}>
<View style={styles.header}>
<ButtonIcon
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import { Provider } from 'react-redux';
import { configureStore } from '@reduxjs/toolkit';
import { AccountGroupType, AccountGroupId } from '@metamask/account-api';
import { Box } from '@metamask/design-system-react-native';
import { Box, Toast } from '@metamask/design-system-react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import {
Expand All @@ -14,7 +14,6 @@ import {
import MultichainAccountConnect from './MultichainAccountConnect';
import { AccountGroupWithInternalAccounts } from '../../../../selectors/multichainAccounts/accounts.type';
import { AccountConnectProps } from '../../AccountConnect/AccountConnect.types';
import { ToastContextWrapper } from '../../../../component-library/components/Toast';
import { createMockInternalAccount } from '../../../../util/test/accountsControllerTestUtils';

const Stack = createStackNavigator();
Expand Down Expand Up @@ -209,13 +208,12 @@ const MultichainAccountConnectMeta = {
}: { args: { accountGroups?: AccountGroupWithInternalAccounts[] } },
) => (
<Provider store={createMockStore(args.accountGroups)}>
<ToastContextWrapper>
<MockNavigationWrapper>
<Box twClassName="flex-1 bg-default">
<Story />
</Box>
</MockNavigationWrapper>
</ToastContextWrapper>
<MockNavigationWrapper>
<Box twClassName="flex-1 bg-default">
<Story />
<Toast />
Comment thread
cursor[bot] marked this conversation as resolved.
Outdated
</Box>
</MockNavigationWrapper>
</Provider>
),
],
Expand Down
Loading
Loading