Skip to content

Commit

Permalink
Merge branch 'main' into fix/asset-receive-network
Browse files Browse the repository at this point in the history
  • Loading branch information
tommasini authored Mar 3, 2025
2 parents 2856d7a + 1ae7b55 commit 9621604
Show file tree
Hide file tree
Showing 10 changed files with 534 additions and 9 deletions.
20 changes: 19 additions & 1 deletion app/components/Nav/Main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import { useMinimumVersions } from '../../hooks/MinimumVersions';
import navigateTermsOfUse from '../../../util/termsOfUse/termsOfUse';
import {
selectChainId,
selectIsAllNetworks,
selectNetworkClientId,
selectNetworkConfigurations,
selectProviderConfig,
Expand All @@ -67,7 +68,10 @@ import {
selectNetworkName,
selectNetworkImageSource,
} from '../../../selectors/networkInfos';
import { selectShowIncomingTransactionNetworks } from '../../../selectors/preferencesController';
import {
selectShowIncomingTransactionNetworks,
selectTokenNetworkFilter,
} from '../../../selectors/preferencesController';

import useNotificationHandler from '../../../util/notifications/hooks';
import {
Expand All @@ -86,6 +90,7 @@ import { useConnectionHandler } from '../../../util/navigation/useConnectionHand
import { AssetPollingProvider } from '../../hooks/AssetPolling/AssetPollingProvider';
import { getGlobalEthQuery } from '../../../util/networks/global-network';
import { selectIsEvmNetworkSelected } from '../../../selectors/multichainNetworkController';
import { isPortfolioViewEnabled } from '../../../util/networks';

const Stack = createStackNavigator();

Expand Down Expand Up @@ -232,6 +237,9 @@ const Main = (props) => {
const { toastRef } = useContext(ToastContext);
const networkImage = useSelector(selectNetworkImageSource);

const isAllNetworks = useSelector(selectIsAllNetworks);
const tokenNetworkFilter = useSelector(selectTokenNetworkFilter);

const hasNetworkChanged = useCallback(
(chainId, previousConfig, isEvmSelected) => {
if (!previousConfig) return false;
Expand All @@ -249,6 +257,14 @@ const Main = (props) => {
if (
hasNetworkChanged(chainId, previousProviderConfig.current, isEvmSelected)
) {
//set here token network filter if portfolio view is enabled
if (isPortfolioViewEnabled()) {
const { PreferencesController } = Engine.context;
PreferencesController.setTokenNetworkFilter({
...(isAllNetworks ? tokenNetworkFilter : {}),
[chainId]: true,
});
}
toastRef?.current?.showToast({
variant: ToastVariants.Network,
labelOptions: [
Expand All @@ -272,6 +288,8 @@ const Main = (props) => {
chainId,
isEvmSelected,
hasNetworkChanged,
isAllNetworks,
tokenNetworkFilter,
]);

// Show add network confirmation.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`DrawerView should render correctly 1`] = `
exports[`DrawerView - Extended Coverage renders correctly (snapshot) 1`] = `
<View
style={
{
Expand Down
6 changes: 5 additions & 1 deletion app/components/UI/DrawerView/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ import { createAccountSelectorNavDetails } from '../../Views/AccountSelector';
import NetworkInfo from '../NetworkInfo';
import { withMetricsAwareness } from '../../../components/hooks/useMetrics';
import { toChecksumHexAddress } from '@metamask/controller-utils';
import safePromiseHandler from './utils';

const createStyles = (colors) =>
StyleSheet.create({
Expand Down Expand Up @@ -981,9 +982,12 @@ class DrawerView extends PureComponent {
networkSwitched,
toggleInfoNetworkModal,
} = this.props;

onboardNetworkAction(chainId);
networkSwitched({ networkUrl: '', networkStatus: false });
toggleInfoNetworkModal();

// Wrap the toggle call in a setTimeout to avoid awaiting a non-promise function.
safePromiseHandler(toggleInfoNetworkModal(), 100);
};

renderProtectModal = () => {
Expand Down
98 changes: 96 additions & 2 deletions app/components/UI/DrawerView/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ import DrawerView from './';
import { backgroundState } from '../../../util/test/initial-root-state';
import { MOCK_ACCOUNTS_CONTROLLER_STATE } from '../../../util/test/accountsControllerTestUtils';

import { fireEvent } from '@testing-library/react-native';

jest.mock('react-native-share', () => ({
open: jest.fn(() => Promise.resolve()),
}));

jest.mock('../../../core/ClipboardManager', () => ({
setString: jest.fn(() => Promise.resolve()),
}));

const mockInitialState = {
engine: {
backgroundState: {
Expand Down Expand Up @@ -33,8 +43,62 @@ jest.mock('../../../core/Engine', () => {
};
});

describe('DrawerView', () => {
it('should render correctly', () => {
describe('DrawerView - Extended Coverage', () => {
const navigationMock = {
navigate: jest.fn(),
goBack: jest.fn(),
replace: jest.fn(),
dangerouslyGetState: jest.fn(() => ({ routes: [{ name: 'Home' }] })),
};
const metricsMock = {
trackEvent: jest.fn(),
createEventBuilder: jest.fn(() => ({
addProperties: jest.fn(() => ({
build: jest.fn(() => ({})),
})),
build: jest.fn(() => ({})),
})),
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const props = {
navigation: navigationMock,
providerConfig: {
type: 'mainnet',
ticker: 'ETH',
rpcUrl: 'https://rpc.example.com',
},
accounts: {},
selectedInternalAccount: {
address: '0x123',
metadata: { name: 'Account 1' },
},
currentCurrency: 'USD',
keyrings: [],
toggleNetworkModal: jest.fn(),
showAlert: jest.fn(),
networkModalVisible: false,
newAssetTransaction: jest.fn(),
passwordSet: true,
wizard: {},
ticker: 'ETH',
networkConfigurations: {},
tokens: [],
tokenBalances: {},
collectibles: [],
seedphraseBackedUp: true,
currentRoute: 'Home',
switchedNetwork: {},
protectWalletModalVisible: jest.fn(),
onboardNetworkAction: jest.fn(),
networkSwitched: jest.fn(),
infoNetworkModalVisible: false,
toggleInfoNetworkModal: jest.fn(),
onCloseDrawer: jest.fn(),
metrics: metricsMock,
chainId: '1',
};

it('renders correctly (snapshot)', () => {
const { toJSON } = renderWithProvider(
<DrawerView navigation={{ goBack: () => null }} />,
{
Expand All @@ -43,4 +107,34 @@ describe('DrawerView', () => {
);
expect(toJSON()).toMatchSnapshot();
});

it('handles onSend correctly', async () => {
const { getByTestId } = renderWithProvider(<DrawerView {...props} />, {
state: mockInitialState,
});
const sendButton = getByTestId('drawer-send-button');
fireEvent.press(sendButton);
expect(navigationMock.navigate).toHaveBeenCalledWith('SendFlowView');
});

it('calls openAccountSelector and tracks the event', () => {
const { getByTestId } = renderWithProvider(<DrawerView {...props} />, {
state: mockInitialState,
});
const identicon = getByTestId('navbar-account-identicon');
fireEvent.press(identicon);
expect(navigationMock.navigate).toHaveBeenCalled();
});

it('handles onReceive correctly', () => {
const { getByTestId } = renderWithProvider(<DrawerView {...props} />, {
state: mockInitialState,
});
const receiveButton = getByTestId('drawer-receive-button');
fireEvent.press(receiveButton);
expect(navigationMock.navigate).toHaveBeenCalledWith('QRTabSwitcher', {
disableTabber: true,
initialScreen: 1,
});
});
});
53 changes: 53 additions & 0 deletions app/components/UI/DrawerView/util.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import safePromiseHandler from './utils';

describe('safePromiseHandler', () => {
beforeEach(() => {
jest.useFakeTimers();
});

afterEach(() => {
jest.runOnlyPendingTimers();
jest.useRealTimers();
jest.clearAllMocks();
});

it('should return a function', () => {
const toggleFunction = jest.fn();
const handler = safePromiseHandler(toggleFunction);
expect(typeof handler).toBe('function');
});

it('should call toggleFunction after the default delay (100ms)', () => {
const toggleFunction = jest.fn();
const handler = safePromiseHandler(toggleFunction);
handler();
// Initially, the toggleFunction should not have been called.
expect(toggleFunction).not.toHaveBeenCalled();
// Advance time by 100ms
jest.advanceTimersByTime(100);
expect(toggleFunction).toHaveBeenCalledTimes(1);
});

it('should call toggleFunction after a custom delay', () => {
const customDelay = 250;
const toggleFunction = jest.fn();
const handler = safePromiseHandler(toggleFunction, customDelay);
handler();
// Advance time by less than customDelay; function should not have been called yet.
jest.advanceTimersByTime(customDelay - 1);
expect(toggleFunction).not.toHaveBeenCalled();
// Advance by the remaining time.
jest.advanceTimersByTime(1);
expect(toggleFunction).toHaveBeenCalledTimes(1);
});

it('should call toggleFunction for each invocation of the handler', () => {
const toggleFunction = jest.fn();
const handler = safePromiseHandler(toggleFunction);
// Call the returned function twice.
handler();
handler();
jest.advanceTimersByTime(100);
expect(toggleFunction).toHaveBeenCalledTimes(2);
});
});
13 changes: 13 additions & 0 deletions app/components/UI/DrawerView/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* Delays the execution of a function by a specified amount of time.
*
* @param toggleFunction - The function to execute after the delay.
* @param delay - The delay in milliseconds (default: 100ms).
* @returns A function that, when called, will execute the provided function after the delay.
*/
const safePromiseHandler =
(toggleFunction: () => void, delay: number = 100): (() => void) =>
() =>
setTimeout(toggleFunction, delay);

export default safePromiseHandler;
Original file line number Diff line number Diff line change
@@ -1,21 +1,52 @@
import React from 'react';

import renderWithProvider from '../../../../../../../util/test/renderWithProvider';
import { personalSignatureConfirmationState } from '../../../../../../../util/test/confirm-data-helpers';
import AccountNetworkInfoExpanded from './AccountNetworkInfoExpanded';
import { isPortfolioViewEnabled } from '../../../../../../../util/networks';

jest.mock('../../../../../../../util/networks', () => ({
...jest.requireActual('../../../../../../../util/networks'),
isPortfolioViewEnabled: jest.fn(),
}));

jest.mock('../../../../../../../core/Engine', () => ({
getTotalFiatAccountBalance: () => ({ tokenFiat: 10 }),
}));

describe('AccountNetworkInfoExpanded', () => {
it('should render correctly', async () => {
const mockIsPortfolioViewEnabled = jest.mocked(isPortfolioViewEnabled);

beforeEach(() => {
jest.clearAllMocks();
mockIsPortfolioViewEnabled.mockReturnValue(false);
});

it('should match snapshot when isPortfolioVieEnabled is true', () => {
mockIsPortfolioViewEnabled.mockReturnValue(true);
const { toJSON, getByText } = renderWithProvider(
<AccountNetworkInfoExpanded />,
{
state: personalSignatureConfirmationState,
},
);

expect(toJSON()).toMatchSnapshot();
expect(getByText('Account')).toBeDefined();
expect(getByText('Balance')).toBeDefined();
expect(getByText('Balance')).toBeDefined();
expect(getByText('$0')).toBeDefined();
expect(getByText('Network')).toBeDefined();
expect(getByText('Ethereum Mainnet')).toBeDefined();
});

it('should render correctly when isPortfolioVieEnabled is false', async () => {
const { getByText } = renderWithProvider(<AccountNetworkInfoExpanded />, {
state: personalSignatureConfirmationState,
});

expect(getByText('$10')).toBeDefined();
expect(getByText('Account')).toBeDefined();
expect(getByText('Balance')).toBeDefined();
expect(getByText('$10')).toBeDefined();
expect(getByText('Network')).toBeDefined();
expect(getByText('Ethereum Mainnet')).toBeDefined();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,18 @@ import Network from '../../../UI/InfoRow/InfoValue/Network';
import { useSignatureRequest } from '../../../../hooks/useSignatureRequest';
import { Hex } from '@metamask/utils';
import { renderShortAddress } from '../../../../../../../util/address';
import { useMultichainBalances } from '../../../../../../hooks/useMultichainBalances';

const AccountNetworkInfoExpanded = () => {
const signatureRequest = useSignatureRequest();
const chainId = signatureRequest?.chainId as Hex;

const fromAddress = signatureRequest?.messageParams?.from as string;
const { accountAddress, accountFiatBalance } = useAccountInfo(fromAddress);
const { multichainBalances } = useMultichainBalances();
const balanceToDisplay = multichainBalances.isPortfolioVieEnabled
? multichainBalances.displayBalance
: accountFiatBalance;

return (
<View>
Expand All @@ -24,7 +29,7 @@ const AccountNetworkInfoExpanded = () => {
{renderShortAddress(accountAddress, 5)}
</InfoRow>
<InfoRow label={strings('confirm.label.balance')}>
{accountFiatBalance}
{balanceToDisplay}
</InfoRow>
</InfoSection>
<InfoSection>
Expand Down
Loading

0 comments on commit 9621604

Please sign in to comment.