diff --git a/app/components/UI/Predict/components/PredictPosition/PredictPosition.tsx b/app/components/UI/Predict/components/PredictPosition/PredictPosition.tsx index 8cb663d5d7a9..0a4fbd8cd7e5 100644 --- a/app/components/UI/Predict/components/PredictPosition/PredictPosition.tsx +++ b/app/components/UI/Predict/components/PredictPosition/PredictPosition.tsx @@ -8,7 +8,7 @@ import { useStyles } from '../../../../../component-library/hooks'; import { PredictPosition as PredictPositionType } from '../../types'; import { formatPercentage, formatPrice } from '../../utils/format'; import styleSheet from './PredictPosition.styles'; -import { getPredictPositionSelector } from '../../../../../../e2e/selectors/Predict/Predict.selectors'; +import { PredictPositionSelectorsIDs } from '../../../../../../e2e/selectors/Predict/Predict.selectors'; interface PredictPositionProps { position: PredictPositionType; @@ -32,7 +32,7 @@ const PredictPosition: React.FC = ({ return ( onPress?.(position)} > diff --git a/app/components/UI/Predict/components/PredictPositionResolved/PredictPositionResolved.tsx b/app/components/UI/Predict/components/PredictPositionResolved/PredictPositionResolved.tsx index fcccf7b03dbb..d1d8cbac9779 100644 --- a/app/components/UI/Predict/components/PredictPositionResolved/PredictPositionResolved.tsx +++ b/app/components/UI/Predict/components/PredictPositionResolved/PredictPositionResolved.tsx @@ -10,7 +10,7 @@ import { useStyles } from '../../../../../component-library/hooks'; import { PredictPosition as PredictPositionType } from '../../types'; import { formatPrice } from '../../utils/format'; import styleSheet from './PredictPositionResolved.styles'; -import { getPredictPositionSelector } from '../../../../../../e2e/selectors/Predict/Predict.selectors'; +import { PredictPositionSelectorsIDs } from '../../../../../../e2e/selectors/Predict/Predict.selectors'; dayjs.extend(relativeTime); @@ -46,7 +46,7 @@ const PredictPositionResolved: React.FC = ({ return ( onPress?.(position)} > diff --git a/app/components/UI/Tokens/util/sortAssetsWithPriority.test.ts b/app/components/UI/Tokens/util/sortAssetsWithPriority.test.ts new file mode 100644 index 000000000000..59b501b9a61b --- /dev/null +++ b/app/components/UI/Tokens/util/sortAssetsWithPriority.test.ts @@ -0,0 +1,190 @@ +import type { Asset } from '@metamask/assets-controllers'; +import { CHAIN_IDS } from '@metamask/transaction-controller'; +import type { CaipChainId, Hex } from '@metamask/utils'; +import { + compareFiatBalanceWithPriority, + sortAssetsWithPriority, +} from './sortAssetsWithPriority'; + +function createMockAsset({ + name, + fiatBalance, + isNative = true, + chainId = CHAIN_IDS.MAINNET, +}: { + name: string; + fiatBalance?: number; + isNative?: boolean; + chainId?: Hex | CaipChainId; +}): Asset { + return { + name, + fiat: fiatBalance === undefined ? undefined : { balance: fiatBalance }, + isNative, + chainId, + } as unknown as Asset; +} + +describe('sortAssetsWithPriority', () => { + function extractAssetNames(assets: Asset[]): string[] { + return assets.map((asset) => asset.name); + } + + it('sorts by name when key is "name"', () => { + const assets = [ + createMockAsset({ name: 'Asset B', fiatBalance: 400 }), + createMockAsset({ name: 'Asset A', fiatBalance: 600 }), + createMockAsset({ name: 'Asset Z', fiatBalance: 500 }), + ]; + + const sortedAssets = sortAssetsWithPriority(assets, { + key: 'name', + order: 'asc', + sortCallback: 'alphaNumeric', + }); + + expect(extractAssetNames(sortedAssets)).toStrictEqual([ + 'Asset A', + 'Asset B', + 'Asset Z', + ]); + }); + + it('sorts by fiat balance when key is "tokenFiatAmount"', () => { + const assets = [ + createMockAsset({ name: 'Asset B', fiatBalance: 400 }), + createMockAsset({ name: 'Asset A', fiatBalance: 600 }), + createMockAsset({ name: 'Asset Z', fiatBalance: 500 }), + ]; + + const sortedAssets = sortAssetsWithPriority(assets, { + key: 'tokenFiatAmount', + order: 'dsc', + sortCallback: 'stringNumeric', + }); + + expect(extractAssetNames(sortedAssets)).toStrictEqual([ + 'Asset A', + 'Asset Z', + 'Asset B', + ]); + }); +}); + +describe('compareFiatBalanceWithPriority', () => { + describe('fiat balance comparison', () => { + it('compares second value above first if the second asset has a fiat balance and the first asset does not', () => { + const assetA = createMockAsset({ + name: 'Asset A', + fiatBalance: undefined, + }); + const assetB = createMockAsset({ name: 'Asset B', fiatBalance: 400 }); + + const result = compareFiatBalanceWithPriority(assetA, assetB); + + expect(result).toBeGreaterThan(0); + }); + + it('compares second value above the first value if both assets have fiat balances and the second value is greater', () => { + const assetA = createMockAsset({ name: 'Asset A', fiatBalance: 300 }); + const assetB = createMockAsset({ name: 'Asset B', fiatBalance: 400 }); + + const result = compareFiatBalanceWithPriority(assetA, assetB); + + expect(result).toBeGreaterThan(0); + }); + }); + + describe('non-native asset comparison', () => { + it('returns -1 if the first asset is native and the second asset is not', () => { + const assetA = createMockAsset({ name: 'Asset A', isNative: true }); + const assetB = createMockAsset({ name: 'Asset B', isNative: false }); + + const result = compareFiatBalanceWithPriority(assetA, assetB); + + expect(result).toBeLessThan(0); + }); + + it('returns 1 if the second asset is native and the first asset is not', () => { + const assetA = createMockAsset({ name: 'Asset A', isNative: false }); + const assetB = createMockAsset({ name: 'Asset B', isNative: true }); + + const result = compareFiatBalanceWithPriority(assetA, assetB); + + expect(result).toBeGreaterThan(0); + }); + + it('compares name values if neither asset is native', () => { + const assetA = createMockAsset({ name: 'Asset A', isNative: false }); + const assetB = createMockAsset({ name: 'Asset B', isNative: false }); + + const result = compareFiatBalanceWithPriority(assetA, assetB); + + expect(result).toBeLessThan(0); + }); + }); + + describe('native asset comparison', () => { + it('compares name values if neither asset is in the defaultNativeAssetOrder', () => { + const assetA = createMockAsset({ + name: 'Asset A', + chainId: '0xeeeeeeeeeeeee1', + }); + const assetB = createMockAsset({ + name: 'Asset B', + chainId: '0xeeeeeeeeeeeee2', + }); + + const result = compareFiatBalanceWithPriority(assetA, assetB); + + expect(result).toBeLessThan(0); + }); + + it('compares second value above first if the second asset is in the defaultNativeAssetOrder and the first asset is not', () => { + const assetA = createMockAsset({ + name: 'Asset A', + chainId: '0xeeeeeeeeeeeee1', + }); + const assetB = createMockAsset({ + name: 'Asset B', + chainId: CHAIN_IDS.BASE, + }); + + const result = compareFiatBalanceWithPriority(assetA, assetB); + + expect(result).toBeGreaterThan(0); + }); + + it('compares second value above first if both assets are in the defaultNativeAssetOrder and the second value has higher priority', () => { + const assetA = createMockAsset({ + name: 'Asset A', + chainId: CHAIN_IDS.ARBITRUM, + }); + const assetB = createMockAsset({ + name: 'Asset B', + chainId: CHAIN_IDS.LINEA_MAINNET, + }); + + const result = compareFiatBalanceWithPriority(assetA, assetB); + + expect(result).toBeGreaterThan(0); + }); + + it('compares second value above first if both assets are in the defaultNativeAssetOrder and the second value has higher priority (both values have balances of zero)', () => { + const assetA = createMockAsset({ + name: 'Asset A', + chainId: CHAIN_IDS.ARBITRUM, + fiatBalance: 0, + }); + const assetB = createMockAsset({ + name: 'Asset B', + chainId: CHAIN_IDS.LINEA_MAINNET, + fiatBalance: 0, + }); + + const result = compareFiatBalanceWithPriority(assetA, assetB); + + expect(result).toBeGreaterThan(0); + }); + }); +}); diff --git a/app/components/UI/Tokens/util/sortAssetsWithPriority.ts b/app/components/UI/Tokens/util/sortAssetsWithPriority.ts new file mode 100644 index 000000000000..3fa463e82e73 --- /dev/null +++ b/app/components/UI/Tokens/util/sortAssetsWithPriority.ts @@ -0,0 +1,82 @@ +import type { Asset } from '@metamask/assets-controllers'; +import { CHAIN_IDS } from '@metamask/transaction-controller'; +import type { CaipChainId, Hex } from '@metamask/utils'; +import { BtcScope, SolScope, TrxScope } from '@metamask/keyring-api'; +import { sortAssets, type SortCriteria } from './sortAssets'; + +// These are the only two options for sorting assets +// {"key": "name", "order": "asc", "sortCallback": "alphaNumeric"} +// {"key": "tokenFiatAmount", "order": "dsc", "sortCallback": "stringNumeric"} +export function sortAssetsWithPriority( + array: Asset[], + criteria: SortCriteria, +): Asset[] { + if (criteria.key === 'name') { + return sortAssets(array, { + key: 'name', + order: 'asc', + sortCallback: 'alphaNumeric', + }); + } + + return [...array].sort(compareFiatBalanceWithPriority); +} + +// Higher priority assets are last in the array to facilitate sorting +const defaultNativeAssetOrder: (Hex | CaipChainId)[] = [ + CHAIN_IDS.POLYGON, + CHAIN_IDS.OPTIMISM, + CHAIN_IDS.BSC, + CHAIN_IDS.ARBITRUM, + CHAIN_IDS.BASE, + TrxScope.Mainnet, + BtcScope.Mainnet, + SolScope.Mainnet, + CHAIN_IDS.LINEA_MAINNET, + CHAIN_IDS.MAINNET, +]; + +/** + * Compares assets by fiat balance with priority sorting. + * + * @param a - The first asset to compare. + * @param b - The second asset to compare. + * @returns A negative number if the first asset should appear before the second, a positive number if the first asset should appear after the second, or 0 if they are equal. + */ +export function compareFiatBalanceWithPriority(a: Asset, b: Asset) { + // If one of the fiat balances is greater than the other, return the comparison + const fiatBalanceComparison = (b.fiat?.balance ?? 0) - (a.fiat?.balance ?? 0); + + // Only return comparison if it is not zero + if (fiatBalanceComparison) { + return fiatBalanceComparison; + } + + // With equal fiat balances + // Always return native assets before token assets + // Apply the priority defined in defaultNativeAssetOrder if both are native assets + // If both assets are tokens or none is in the defaultNativeAssetOrder, compare by name + if (a.isNative && !b.isNative) { + return -1; + } + + if (b.isNative && !a.isNative) { + return 1; + } + + if (!a.isNative && !b.isNative) { + return a.name.localeCompare(b.name); + } + + const nativeAssetOrderA = defaultNativeAssetOrder.indexOf(a.chainId); + const nativeAssetOrderB = defaultNativeAssetOrder.indexOf(b.chainId); + + const nativeAssetOrderComparison = nativeAssetOrderB - nativeAssetOrderA; + + if (nativeAssetOrderComparison) { + return nativeAssetOrderComparison; + } + + // If neither asset is in the defaultNativeAssetOrder, compare by name + return a.name.localeCompare(b.name); +} diff --git a/app/components/Views/Login/index.tsx b/app/components/Views/Login/index.tsx index 344d8677aafa..f1b61065660a 100644 --- a/app/components/Views/Login/index.tsx +++ b/app/components/Views/Login/index.tsx @@ -364,6 +364,11 @@ const Login: React.FC = ({ saveOnboardingEvent }) => { }; const handleUseOtherMethod = () => { + if (isComingFromOauthOnboarding) { + track(MetaMetricsEvents.USE_DIFFERENT_LOGIN_METHOD_CLICKED, { + account_type: 'social', + }); + } navigation.goBack(); OAuthService.resetOauthState(); }; diff --git a/app/components/Views/confirmations/components/info/contract-interaction/contract-interaction.test.tsx b/app/components/Views/confirmations/components/info/contract-interaction/contract-interaction.test.tsx index cac8aa899188..86e5ee442106 100644 --- a/app/components/Views/confirmations/components/info/contract-interaction/contract-interaction.test.tsx +++ b/app/components/Views/confirmations/components/info/contract-interaction/contract-interaction.test.tsx @@ -10,6 +10,7 @@ import { upgradeAccountConfirmation, } from '../../../../../../util/test/confirm-data-helpers'; import renderWithProvider from '../../../../../../util/test/renderWithProvider'; +import useBalanceChanges from '../../../../../UI/SimulationDetails/useBalanceChanges'; // eslint-disable-next-line import/no-namespace import * as EditNonceHook from '../../../../../../components/hooks/useEditNonce'; import { useConfirmActions } from '../../../hooks/useConfirmActions'; @@ -36,6 +37,7 @@ jest.mock('../../../hooks/useAutomaticGasFeeTokenSelect'); jest.mock('../../../hooks/alerts/useInsufficientBalanceAlert', () => ({ useInsufficientBalanceAlert: jest.fn().mockReturnValue([]), })); +jest.mock('../../../../../UI/SimulationDetails/useBalanceChanges'); jest.mock('../../../hooks/7702/use7702TransactionType', () => ({ use7702TransactionType: jest @@ -111,6 +113,7 @@ describe('ContractInteraction', () => { const mockUseConfirmationMetricEvents = jest.mocked( useConfirmationMetricEvents, ); + const mockUseBalanceChanges = jest.mocked(useBalanceChanges); beforeEach(() => { jest.clearAllMocks(); @@ -122,6 +125,10 @@ describe('ContractInteraction', () => { mockUseConfirmationMetricEvents.mockReturnValue({ trackPageViewedEvent: mockTrackPageViewedEvent, } as unknown as ReturnType); + mockUseBalanceChanges.mockReturnValue({ + pending: false, + value: [], + }); const mockTxId = '7e62bcb1-a4e9-11ef-9b51-ddf21c91a998'; jest diff --git a/app/components/Views/confirmations/components/predict-confirmations/predict-claim-amount/predict-claim-amount.tsx b/app/components/Views/confirmations/components/predict-confirmations/predict-claim-amount/predict-claim-amount.tsx index 3dafd866f626..5cb31b4eb4a4 100644 --- a/app/components/Views/confirmations/components/predict-confirmations/predict-claim-amount/predict-claim-amount.tsx +++ b/app/components/Views/confirmations/components/predict-confirmations/predict-claim-amount/predict-claim-amount.tsx @@ -15,6 +15,7 @@ import { formatPercentage, formatPrice, } from '../../../../../UI/Predict/utils/format'; +import { PredictClaimConfirmationSelectorsIDs } from '../../../../../../../e2e/selectors/Predict/Predict.selectors'; import styleSheet from './predict-claim-amount.styles'; export function PredictClaimAmount() { @@ -35,7 +36,10 @@ export function PredictClaimAmount() { })} (${formatPercentage((winningsPnl / winningsFiat) * 100)})`; return ( - + {strings('confirm.predict_claim.summary')} diff --git a/app/components/Views/confirmations/components/predict-confirmations/predict-claim-footer/predict-claim-footer.tsx b/app/components/Views/confirmations/components/predict-confirmations/predict-claim-footer/predict-claim-footer.tsx index 02269f36900d..8332d340906b 100644 --- a/app/components/Views/confirmations/components/predict-confirmations/predict-claim-footer/predict-claim-footer.tsx +++ b/app/components/Views/confirmations/components/predict-confirmations/predict-claim-footer/predict-claim-footer.tsx @@ -15,6 +15,7 @@ import Text, { } from '../../../../../../component-library/components/Texts/Text'; import { useStyles } from '../../../../../../component-library/hooks'; import { Box } from '../../../../../UI/Box/Box'; +import { PredictClaimConfirmationSelectorsIDs } from '../../../../../../../e2e/selectors/Predict/Predict.selectors'; import styleSheet from './predict-claim-footer.styles'; import { selectPredictWonPositions } from '../../../../../UI/Predict/selectors/predictController'; @@ -52,6 +53,7 @@ export function PredictClaimFooter({ onPress }: PredictClaimFooterProps) { label={strings('confirm.predict_claim.button_label')} onPress={onPress} isInverse + testID={PredictClaimConfirmationSelectorsIDs.CLAIM_CONFIRM_BUTTON} /> ({ GasSpeed: () => null, @@ -34,6 +36,7 @@ jest.mock('../../../../hooks/gas/useIsGaslessSupported'); jest.mock('../../../../hooks/alerts/useInsufficientBalanceAlert'); jest.mock('../../../../../../hooks/useHideFiatForTestnet'); jest.mock('../../../../hooks/tokens/useTokenWithBalance'); +jest.mock('../../../../../../UI/SimulationDetails/useBalanceChanges'); const GAS_FEE_TOKEN_MOCK: ReturnType = { amount: toHex(10000), @@ -56,6 +59,31 @@ const GAS_FEE_TOKEN_MOCK: ReturnType = { transferTransaction: {}, }; +const SIMULATION_DATA_MOCK: SimulationData = { + nativeBalanceChange: { + previousBalance: '0x0', + newBalance: '0x0', + difference: '0x0', + isDecrease: false, + }, + tokenBalanceChanges: [], +}; + +const createStateWithSimulationData = ( + baseState = stakingDepositConfirmationState, +) => { + const stateWithSimulation = cloneDeep(baseState); + const transactions = + stateWithSimulation.engine.backgroundState.TransactionController + .transactions; + + if (transactions?.[0]) { + transactions[0].simulationData = cloneDeep(SIMULATION_DATA_MOCK); + } + + return stateWithSimulation; +}; + describe('GasFeesDetailsRow', () => { const useConfirmationMetricEventsMock = jest.mocked( useConfirmationMetricEvents, @@ -67,6 +95,7 @@ describe('GasFeesDetailsRow', () => { useInsufficientBalanceAlert, ); const mockUseHideFiatForTestnet = jest.mocked(useHideFiatForTestnet); + const mockUseBalanceChanges = jest.mocked(useBalanceChanges); beforeEach(() => { useConfirmationMetricEventsMock.mockReturnValue({ @@ -79,11 +108,15 @@ describe('GasFeesDetailsRow', () => { }); mockUseInsufficientBalanceAlert.mockReturnValue([]); mockUseHideFiatForTestnet.mockReturnValue(false); + mockUseBalanceChanges.mockReturnValue({ + pending: false, + value: [], + }); }); it('contains required text', async () => { const { getByText } = renderWithProvider(, { - state: stakingDepositConfirmationState, + state: createStateWithSimulationData(), }); expect(getByText('Network Fee')).toBeDefined(); expect(getByText('$0.34')).toBeDefined(); @@ -91,9 +124,8 @@ describe('GasFeesDetailsRow', () => { }); it('shows fiat if showFiatOnTestnets is true', async () => { - const clonedStakingDepositConfirmationState = cloneDeep( - stakingDepositConfirmationState, - ); + const clonedStakingDepositConfirmationState = + createStateWithSimulationData(); clonedStakingDepositConfirmationState.engine.backgroundState.TransactionController.transactions[0].chainId = NETWORKS_CHAIN_ID.SEPOLIA; @@ -104,9 +136,8 @@ describe('GasFeesDetailsRow', () => { }); it('hides fiat if showFiatOnTestnets is false', async () => { - const clonedStakingDepositConfirmationState = cloneDeep( - stakingDepositConfirmationState, - ); + const clonedStakingDepositConfirmationState = + createStateWithSimulationData(); clonedStakingDepositConfirmationState.engine.backgroundState.TransactionController.transactions[0].chainId = NETWORKS_CHAIN_ID.SEPOLIA; clonedStakingDepositConfirmationState.settings.showFiatOnTestnets = false; @@ -118,9 +149,8 @@ describe('GasFeesDetailsRow', () => { }); it('hides fiat if nativeConversionRate is undefined', async () => { - const clonedStakingDepositConfirmationState = cloneDeep( - stakingDepositConfirmationState, - ); + const clonedStakingDepositConfirmationState = + createStateWithSimulationData(); // No type is exported for CurrencyRate, so we need to cast it to the correct type clonedStakingDepositConfirmationState.engine.backgroundState.CurrencyRateController.currencyRates.ETH = @@ -138,7 +168,7 @@ describe('GasFeesDetailsRow', () => { it('tracks tooltip clicked event', async () => { const { getByTestId } = renderWithProvider(, { - state: stakingDepositConfirmationState, + state: createStateWithSimulationData(), }); fireEvent.press(getByTestId('info-row-tooltip-open-btn')); @@ -153,7 +183,7 @@ describe('GasFeesDetailsRow', () => { it('shows gas speed row', async () => { const { getByText } = renderWithProvider(, { - state: stakingDepositConfirmationState, + state: createStateWithSimulationData(), }); expect(getByText('Speed')).toBeDefined(); }); @@ -162,7 +192,7 @@ describe('GasFeesDetailsRow', () => { const { queryByText } = renderWithProvider( , { - state: stakingDepositConfirmationState, + state: createStateWithSimulationData(), }, ); @@ -173,7 +203,7 @@ describe('GasFeesDetailsRow', () => { const { getByText, queryByText } = renderWithProvider( , { - state: stakingDepositConfirmationState, + state: createStateWithSimulationData(), }, ); @@ -188,7 +218,7 @@ describe('GasFeesDetailsRow', () => { >, ); const { getByText } = renderWithProvider(, { - state: stakingDepositConfirmationState, + state: createStateWithSimulationData(), }); expect(getByText('USDC')).toBeDefined(); @@ -197,9 +227,8 @@ describe('GasFeesDetailsRow', () => { it('shows native amount when is a testnet', async () => { mockUseHideFiatForTestnet.mockReturnValue(true); - const clonedStakingDepositConfirmationState = cloneDeep( - stakingDepositConfirmationState, - ); + const clonedStakingDepositConfirmationState = + createStateWithSimulationData(); clonedStakingDepositConfirmationState.engine.backgroundState.TransactionController.transactions[0].chainId = NETWORKS_CHAIN_ID.SEPOLIA; @@ -212,9 +241,8 @@ describe('GasFeesDetailsRow', () => { }); it(`shows 'Paid by MetaMask' when gas is sponsored`, async () => { - const clonedStakingDepositConfirmationState = cloneDeep( - stakingDepositConfirmationState, - ); + const clonedStakingDepositConfirmationState = + createStateWithSimulationData(); clonedStakingDepositConfirmationState.engine.backgroundState.TransactionController.transactions[0].isGasFeeSponsored = true; const { getByText, queryByText } = renderWithProvider( , @@ -239,7 +267,7 @@ describe('GasFeesDetailsRow', () => { ); const { queryByText } = renderWithProvider(, { - state: stakingDepositConfirmationState, + state: createStateWithSimulationData(), }); expect(queryByText('MetaMask fee: $0.12')).toBeNull(); @@ -259,7 +287,7 @@ describe('GasFeesDetailsRow', () => { const { getByTestId, getByText } = renderWithProvider( , { - state: stakingDepositConfirmationState, + state: createStateWithSimulationData(), }, ); diff --git a/app/components/Views/confirmations/components/rows/transactions/gas-fee-details-row/gas-fee-details-row.tsx b/app/components/Views/confirmations/components/rows/transactions/gas-fee-details-row/gas-fee-details-row.tsx index 0ba7f7df5bf4..183d2bd7cb0d 100644 --- a/app/components/Views/confirmations/components/rows/transactions/gas-fee-details-row/gas-fee-details-row.tsx +++ b/app/components/Views/confirmations/components/rows/transactions/gas-fee-details-row/gas-fee-details-row.tsx @@ -4,41 +4,55 @@ import { } from '@metamask/transaction-controller'; import React, { useState } from 'react'; import { TouchableOpacity, View } from 'react-native'; +import SkeletonPlaceholder from 'react-native-skeleton-placeholder'; import { ConfirmationRowComponentIDs } from '../../../../../../../../e2e/selectors/Confirmation/ConfirmationView.selectors'; import { strings } from '../../../../../../../../locales/i18n'; import Icon, { IconName, IconSize, } from '../../../../../../../component-library/components/Icons/Icon'; +import { + TextColor, + TextVariant, +} from '../../../../../../../component-library/components/Texts/Text'; import Text from '../../../../../../../component-library/components/Texts/Text/Text'; import { useStyles } from '../../../../../../../component-library/hooks'; import { TOOLTIP_TYPES } from '../../../../../../../core/Analytics/events/confirmations'; import useHideFiatForTestnet from '../../../../../../hooks/useHideFiatForTestnet'; +import useBalanceChanges from '../../../../../../UI/SimulationDetails/useBalanceChanges'; import { useFeeCalculations } from '../../../../hooks/gas/useFeeCalculations'; import { useFeeCalculationsTransactionBatch } from '../../../../hooks/gas/useFeeCalculationsTransactionBatch'; +import { useSelectedGasFeeToken } from '../../../../hooks/gas/useGasFeeToken'; import { useConfirmationMetricEvents } from '../../../../hooks/metrics/useConfirmationMetricEvents'; import { useTransactionBatchesMetadata } from '../../../../hooks/transactions/useTransactionBatchesMetadata'; import { useTransactionMetadataRequest } from '../../../../hooks/transactions/useTransactionMetadataRequest'; +import { useAutomaticGasFeeTokenSelect } from '../../../../hooks/useAutomaticGasFeeTokenSelect'; +import { GasFeeTokenToast } from '../../../gas/gas-fee-token-toast'; import { GasSpeed } from '../../../gas/gas-speed'; +import { SelectedGasFeeToken } from '../../../gas/selected-gas-fee-token'; import { GasFeeModal } from '../../../modals/gas-fee-modal'; import AlertRow from '../../../UI/info-row/alert-row'; import { RowAlertKey } from '../../../UI/info-row/alert-row/constants'; import InfoSection from '../../../UI/info-row/info-section'; import styleSheet from './gas-fee-details-row.styles'; -import { SelectedGasFeeToken } from '../../../gas/selected-gas-fee-token'; -import { useSelectedGasFeeToken } from '../../../../hooks/gas/useGasFeeToken'; -import { - TextColor, - TextVariant, -} from '../../../../../../../component-library/components/Texts/Text'; -import { GasFeeTokenToast } from '../../../gas/gas-fee-token-toast'; -import { useAutomaticGasFeeTokenSelect } from '../../../../hooks/useAutomaticGasFeeTokenSelect'; const PaidByMetaMask = () => ( {strings('transactions.paid_by_metamask')} ); + +const SkeletonEstimationInfo = () => ( + + + +); + const EstimationInfo = ({ hideFiatForTestnet, feeCalculations, @@ -64,11 +78,22 @@ const EstimationInfo = ({ hideFiatForTestnet || !fiatValue ? styles.primaryValue : styles.secondaryValue; + const transactionMetadata = useTransactionMetadataRequest(); + const { chainId, simulationData, networkClientId } = + (transactionMetadata as TransactionMeta) ?? {}; + const balanceChangesResult = useBalanceChanges({ + chainId, + simulationData, + networkClientId, + }); + const isSimulationLoading = !simulationData || balanceChangesResult.pending; return ( {isGasFeeSponsored ? ( + ) : isSimulationLoading ? ( + ) : ( <> {displayValue && {displayValue}} @@ -228,6 +253,15 @@ const GasFeesDetailsRow = ({ : strings('transactions.network_fee_tooltip'); const Container = noSection ? View : InfoSection; + + const { chainId, simulationData, networkClientId } = + (transactionMetadata as TransactionMeta) ?? {}; + const balanceChangesResult = useBalanceChanges({ + chainId, + simulationData, + networkClientId, + }); + const isSimulationLoading = !simulationData || balanceChangesResult.pending; return ( <> @@ -238,7 +272,10 @@ const GasFeesDetailsRow = ({ onTooltipPress={handleNetworkFeeTooltipClickedEvent} > - {disableUpdate || gasFeeToken || isGasFeeSponsored ? ( + {disableUpdate || + gasFeeToken || + isGasFeeSponsored || + isSimulationLoading ? ( { key: AlertKeys.BurnAddress, field: RowAlertKey.BurnAddress, severity: Severity.Danger, - isBlocking: false, + isBlocking: true, }); expect(result.current[0].title).toBeDefined(); expect(result.current[0].message).toBeDefined(); @@ -72,7 +72,7 @@ describe('useBurnAddressAlert', () => { key: AlertKeys.BurnAddress, field: RowAlertKey.BurnAddress, severity: Severity.Danger, - isBlocking: false, + isBlocking: true, }); }); @@ -100,7 +100,7 @@ describe('useBurnAddressAlert', () => { key: AlertKeys.BurnAddress, field: RowAlertKey.BurnAddress, severity: Severity.Danger, - isBlocking: false, + isBlocking: true, }); }); diff --git a/app/components/Views/confirmations/hooks/alerts/useBurnAddressAlert.ts b/app/components/Views/confirmations/hooks/alerts/useBurnAddressAlert.ts index c243d018fd7a..94b3f40583d6 100644 --- a/app/components/Views/confirmations/hooks/alerts/useBurnAddressAlert.ts +++ b/app/components/Views/confirmations/hooks/alerts/useBurnAddressAlert.ts @@ -41,7 +41,7 @@ export function useBurnAddressAlert(): Alert[] { message: strings('alert_system.burn_address.message'), title: strings('alert_system.burn_address.title'), severity: Severity.Danger, - isBlocking: false, + isBlocking: true, }, ]; }, [hasBurnAddressRecipient]); diff --git a/app/core/Analytics/MetaMetrics.events.ts b/app/core/Analytics/MetaMetrics.events.ts index 2e58ea3e48af..8a07dd008551 100644 --- a/app/core/Analytics/MetaMetrics.events.ts +++ b/app/core/Analytics/MetaMetrics.events.ts @@ -145,6 +145,7 @@ enum EVENT_NAME { REHYDRATION_PASSWORD_FAILED = 'Rehydration Password Failed', PASSWORD_CHANGED = 'Password Changed', FORGOT_PASSWORD_CLICKED = 'Forgot Password Clicked', + USE_DIFFERENT_LOGIN_METHOD_CLICKED = 'Use Different Login Method Clicked', RESET_WALLET = 'Reset Wallet', // Account @@ -767,6 +768,9 @@ const events = { ), PASSWORD_CHANGED: generateOpt(EVENT_NAME.PASSWORD_CHANGED), FORGOT_PASSWORD_CLICKED: generateOpt(EVENT_NAME.FORGOT_PASSWORD_CLICKED), + USE_DIFFERENT_LOGIN_METHOD_CLICKED: generateOpt( + EVENT_NAME.USE_DIFFERENT_LOGIN_METHOD_CLICKED, + ), RESET_WALLET: generateOpt(EVENT_NAME.RESET_WALLET), SWITCHED_ACCOUNT: generateOpt(EVENT_NAME.SWITCHED_ACCOUNT), BROWSER_OPENED: generateOpt(EVENT_NAME.BROWSER_OPENED), diff --git a/app/selectors/assets/assets-list.ts b/app/selectors/assets/assets-list.ts index f69fa90dfc8d..dc5add731454 100644 --- a/app/selectors/assets/assets-list.ts +++ b/app/selectors/assets/assets-list.ts @@ -10,7 +10,6 @@ import { createSelector } from 'reselect'; import I18n from '../../../locales/i18n'; import { TokenI } from '../../components/UI/Tokens/types'; -import { sortAssets } from '../../components/UI/Tokens/util'; import { RootState } from '../../reducers'; import { formatWithThreshold } from '../../util/assets'; import { selectEvmNetworkConfigurationsByChainId } from '../networkController'; @@ -27,6 +26,7 @@ import { TRON_RESOURCE_SYMBOLS_SET, TronResourceSymbol, } from '../../core/Multichain/constants'; +import { sortAssetsWithPriority } from '../../components/UI/Tokens/util/sortAssetsWithPriority'; export const selectAssetsBySelectedAccountGroup = createDeepEqualSelector( (state: RootState) => { @@ -234,7 +234,7 @@ export const selectSortedAssetsBySelectedAccountGroup = createDeepEqualSelector( // Current sorting options // {"key": "name", "order": "asc", "sortCallback": "alphaNumeric"} // {"key": "tokenFiatAmount", "order": "dsc", "sortCallback": "stringNumeric"} - const tokensSorted = sortAssets( + const tokensSorted = sortAssetsWithPriority( assets.map((asset) => ({ ...asset, tokenFiatAmount: asset.fiat?.balance.toString(), diff --git a/app/selectors/featureFlagController/card/index.test.ts b/app/selectors/featureFlagController/card/index.test.ts index 7735cb67628e..2c301f4ae0c3 100644 --- a/app/selectors/featureFlagController/card/index.test.ts +++ b/app/selectors/featureFlagController/card/index.test.ts @@ -20,6 +20,13 @@ jest.mock('../../../util/remoteFeatureFlag', () => ({ validatedVersionGatedFeatureFlag: jest.fn(), })); +jest.mock( + '../../../core/Engine/controllers/remote-feature-flag-controller', + () => ({ + isRemoteFeatureFlagOverrideActivated: false, + }), +); + const originalEnv = process.env; beforeEach(() => { @@ -493,25 +500,43 @@ describe('selectDisplayCardButtonFeatureFlag', () => { }); describe('selectCardExperimentalSwitch', () => { + const mockedValidatedVersionGatedFeatureFlag = + validatedVersionGatedFeatureFlag as jest.MockedFunction< + typeof validatedVersionGatedFeatureFlag + >; + + beforeEach(() => { + jest.clearAllMocks(); + }); + it('returns false when feature flag state is empty', () => { + mockedValidatedVersionGatedFeatureFlag.mockReturnValue(undefined); + const result = selectCardExperimentalSwitch(mockedEmptyFlagsState); expect(result).toBe(false); }); it('returns false when RemoteFeatureFlagController state is undefined', () => { + mockedValidatedVersionGatedFeatureFlag.mockReturnValue(undefined); + const result = selectCardExperimentalSwitch(mockedUndefinedFlagsState); expect(result).toBe(false); }); - it('returns true when cardExperimentalSwitch is enabled', () => { + it('returns true when feature flag is enabled and version requirement is met', () => { + mockedValidatedVersionGatedFeatureFlag.mockReturnValue(true); + const stateWithExperimentalSwitch = { engine: { backgroundState: { RemoteFeatureFlagController: { remoteFeatureFlags: { - cardExperimentalSwitch: true, + cardExperimentalSwitch2: { + enabled: true, + minimumVersion: '7.0.0', + }, }, cacheTimestamp: 0, }, @@ -523,15 +548,24 @@ describe('selectCardExperimentalSwitch', () => { const result = selectCardExperimentalSwitch(stateWithExperimentalSwitch); expect(result).toBe(true); + expect(mockedValidatedVersionGatedFeatureFlag).toHaveBeenCalledWith({ + enabled: true, + minimumVersion: '7.0.0', + }); }); - it('returns false when cardExperimentalSwitch is disabled', () => { + it('returns false when feature flag is disabled', () => { + mockedValidatedVersionGatedFeatureFlag.mockReturnValue(false); + const stateWithDisabledSwitch = { engine: { backgroundState: { RemoteFeatureFlagController: { remoteFeatureFlags: { - cardExperimentalSwitch: false, + cardExperimentalSwitch2: { + enabled: false, + minimumVersion: '7.0.0', + }, }, cacheTimestamp: 0, }, @@ -545,13 +579,18 @@ describe('selectCardExperimentalSwitch', () => { expect(result).toBe(false); }); - it('returns false when cardExperimentalSwitch is null', () => { - const stateWithNullSwitch = { + it('returns false when version requirement is not met', () => { + mockedValidatedVersionGatedFeatureFlag.mockReturnValue(false); + + const stateWithVersionGate = { engine: { backgroundState: { RemoteFeatureFlagController: { remoteFeatureFlags: { - cardExperimentalSwitch: null, + cardExperimentalSwitch2: { + enabled: true, + minimumVersion: '99.0.0', + }, }, cacheTimestamp: 0, }, @@ -560,18 +599,22 @@ describe('selectCardExperimentalSwitch', () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any; - const result = selectCardExperimentalSwitch(stateWithNullSwitch); + const result = selectCardExperimentalSwitch(stateWithVersionGate); expect(result).toBe(false); }); - it('returns false when cardExperimentalSwitch is undefined', () => { - const stateWithUndefinedSwitch = { + it('returns false when validatedVersionGatedFeatureFlag returns undefined', () => { + mockedValidatedVersionGatedFeatureFlag.mockReturnValue(undefined); + + const stateWithMalformedFlag = { engine: { backgroundState: { RemoteFeatureFlagController: { remoteFeatureFlags: { - cardExperimentalSwitch: undefined, + cardExperimentalSwitch2: { + enabled: 'true', // Invalid type + }, }, cacheTimestamp: 0, }, @@ -580,7 +623,7 @@ describe('selectCardExperimentalSwitch', () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any; - const result = selectCardExperimentalSwitch(stateWithUndefinedSwitch); + const result = selectCardExperimentalSwitch(stateWithMalformedFlag); expect(result).toBe(false); }); diff --git a/app/selectors/featureFlagController/card/index.ts b/app/selectors/featureFlagController/card/index.ts index 377069a014a3..bb7e3572b2c0 100644 --- a/app/selectors/featureFlagController/card/index.ts +++ b/app/selectors/featureFlagController/card/index.ts @@ -149,7 +149,7 @@ const defaultCardSupportedCountries: CardSupportedCountries = { export type CardSupportedCountries = Record; -export interface DisplayCardButtonFeatureFlag { +export interface GateVersionedFeatureFlag { enabled: boolean; minimumVersion: string; } @@ -188,7 +188,7 @@ export const selectDisplayCardButtonFeatureFlag = createSelector( selectRemoteFeatureFlags, (remoteFeatureFlags) => { const remoteFlag = - remoteFeatureFlags?.displayCardButton as unknown as DisplayCardButtonFeatureFlag; + remoteFeatureFlags?.displayCardButton as unknown as GateVersionedFeatureFlag; return validatedVersionGatedFeatureFlag(remoteFlag) ?? false; }, @@ -196,7 +196,12 @@ export const selectDisplayCardButtonFeatureFlag = createSelector( export const selectCardExperimentalSwitch = createSelector( selectRemoteFeatureFlags, - (remoteFeatureFlags) => remoteFeatureFlags?.cardExperimentalSwitch ?? false, + (remoteFeatureFlags) => { + const remoteFlag = + remoteFeatureFlags?.cardExperimentalSwitch2 as unknown as GateVersionedFeatureFlag; + + return validatedVersionGatedFeatureFlag(remoteFlag) ?? false; + }, ); export const selectCardFeatureFlag = createSelector( diff --git a/appwright/tests/performance/login/send-flows.spec.js b/appwright/tests/performance/login/send-flows.spec.js index f87f800e8c30..ba2f2681c916 100644 --- a/appwright/tests/performance/login/send-flows.spec.js +++ b/appwright/tests/performance/login/send-flows.spec.js @@ -128,7 +128,7 @@ test('Send flow - Solana, SRP 1 + SRP 2 + SRP 3', async ({ await SendScreen.typeAddressInSendAddressField(solanaAddress); await SendScreen.clickOnReviewButton(); timer4.start(); - await ConfirmationScreen.isVisible(); + await ConfirmationScreen.isVisible('Solana', 180000); timer4.stop(); performanceTracker.addTimer(timer1); diff --git a/e2e/api-mocking/mock-responses/defaults/gas-api.ts b/e2e/api-mocking/mock-responses/defaults/gas-api.ts index 7af49955229c..c6a52b5c0a80 100644 --- a/e2e/api-mocking/mock-responses/defaults/gas-api.ts +++ b/e2e/api-mocking/mock-responses/defaults/gas-api.ts @@ -1,6 +1,6 @@ import { MockEventsObject } from '../../../framework'; -// Gas fees response for offramp transactions +// Gas fees response for Ethereum networks export const GAS_FEES_RESPONSE = { low: { suggestedMaxPriorityFeePerGas: '1.5', @@ -28,6 +28,37 @@ export const GAS_FEES_RESPONSE = { priorityFeeTrend: 'down', baseFeeTrend: 'stable', }; + +// Polygon gas fees response for network 137 +export const POLYGON_GAS_FEES_RESPONSE = { + low: { + suggestedMaxPriorityFeePerGas: '30', + suggestedMaxFeePerGas: '45.297546547', + minWaitTimeEstimate: 2000, + maxWaitTimeEstimate: 8000, + }, + medium: { + suggestedMaxPriorityFeePerGas: '30', + suggestedMaxFeePerGas: '50.651687839', + minWaitTimeEstimate: 2000, + maxWaitTimeEstimate: 6000, + }, + high: { + suggestedMaxPriorityFeePerGas: '30', + suggestedMaxFeePerGas: '56.00582913', + minWaitTimeEstimate: 2000, + maxWaitTimeEstimate: 4000, + }, + estimatedBaseFee: '15.297546547', + networkCongestion: 0.9067, + latestPriorityFeeRange: ['27.971358858', '54.974422567'], + historicalPriorityFeeRange: ['25.007335215', '130'], + historicalBaseFeeRange: ['14.621185538', '15.355486504'], + priorityFeeTrend: 'down', + baseFeeTrend: 'down', + version: '0.0.1', +}; + /** * Mock data for gas API endpoints used in E2E testing. * Returns stable gas fee data to ensure consistent transaction fees. @@ -35,6 +66,12 @@ export const GAS_FEES_RESPONSE = { */ export const DEFAULT_GAS_API_MOCKS: MockEventsObject = { GET: [ + { + urlEndpoint: + /^https:\/\/gas\.api\.cx\.metamask\.io\/networks\/137\/suggestedGasFees$/, + response: POLYGON_GAS_FEES_RESPONSE, + responseCode: 200, + }, { urlEndpoint: /^https:\/\/gas\.api\.cx\.metamask\.io\/networks\/\d+\/suggestedGasFees$/, diff --git a/e2e/api-mocking/mock-responses/polymarket/polymarket-activity-response.ts b/e2e/api-mocking/mock-responses/polymarket/polymarket-activity-response.ts index bf85818fcc29..eff7b8fc4896 100644 --- a/e2e/api-mocking/mock-responses/polymarket/polymarket-activity-response.ts +++ b/e2e/api-mocking/mock-responses/polymarket/polymarket-activity-response.ts @@ -8,24 +8,24 @@ import { PROXY_WALLET_ADDRESS } from './polymarket-constants'; export const POLYMARKET_ACTIVITY_RESPONSE = [ { proxyWallet: PROXY_WALLET_ADDRESS, - timestamp: 1760559935, + timestamp: 1760387981, conditionId: - '0x39d45b454dcf932767962ad9cbd858c5a6ec21d4d48318a484775b2e83264467', + '0xb4bba8acb4a85c9f4ccd0eec6393e746c0176d271c2d0e52792968a05dd64b0c', type: 'TRADE', - size: 8.333332, - usdcSize: 0.999999, + size: 6, + usdcSize: 4.2, transactionHash: - '0x31c80f8e6c9e6dfdaf77ec6cb5022451211b23c258b5ad2f853f12925f9e4540', - price: 0.11999989919998387, + '0xfff800f2ce58a03dc269917ad581fd394f81ed91d492a6b0bad35fac10a693d9', + price: 0.7, asset: - '19740329944962592380580142050369523795065853055987745520766432334608119837023', + '74764475795121623056006185669021820483304079465092865059622185495692711341808', side: 'BUY', - outcomeIndex: 0, - title: 'Will the Buffalo Bills win Super Bowl 2026?', - slug: 'will-the-buffalo-bills-win-super-bowl-2026', - icon: 'https://polymarket-upload.s3.us-east-2.amazonaws.com/NFL+Team+Logos/BUF.png', - eventSlug: 'super-bowl-champion-2026-731', - outcome: 'Yes', + outcomeIndex: 1, + title: 'Bears vs. Commanders', + slug: 'nfl-chi-was-2025-10-13', + icon: 'https://polymarket-upload.s3.us-east-2.amazonaws.com/nfl.png', + eventSlug: 'nfl-chi-was-2025-10-13', + outcome: 'Commanders', name: 'cropMaster', pseudonym: 'Nonstop-Suitcase', bio: '', @@ -34,24 +34,24 @@ export const POLYMARKET_ACTIVITY_RESPONSE = [ }, { proxyWallet: PROXY_WALLET_ADDRESS, - timestamp: 1760548631, + timestamp: 1760387955, conditionId: - '0x1d395b8dea9dd429fbce85f8b8cbd5aa85ec8a2e8980755756be3eec03da5b9a', + '0x626a49d9b82acaa9e86760c0cddad6a71aceefbef72f4f1c154ff8e358ae88c1', type: 'TRADE', - size: 7.692306, - usdcSize: 0.999999, + size: 8, + usdcSize: 5.28, transactionHash: - '0xb9a9ebbf1bda55d76c9c7138159aa58ab074890a41d3237b2a853319059be45b', - price: 0.12999989859997768, + '0xbd48fb580de2619d8b957e6302bb035d17e0dfbe6217ea846a1e8e03b7819818', + price: 0.66, asset: - '11584273833068499329017832956188664326032555278943683999231427554688326830185', + '41363179555803964193865225014057621561864035628882209196629573070642914610300', side: 'BUY', outcomeIndex: 0, - title: 'Will the Kansas City Chiefs win Super Bowl 2026?', - slug: 'will-the-kansas-city-chiefs-win-super-bowl-2026', - icon: 'https://polymarket-upload.s3.us-east-2.amazonaws.com/NFL+Team+Logos/KC.png', - eventSlug: 'super-bowl-champion-2026-731', - outcome: 'Yes', + title: 'Bills vs. Falcons', + slug: 'nfl-buf-atl-2025-10-13', + icon: 'https://polymarket-upload.s3.us-east-2.amazonaws.com/nfl.png', + eventSlug: 'nfl-buf-atl-2025-10-13', + outcome: 'Bills', name: 'cropMaster', pseudonym: 'Nonstop-Suitcase', bio: '', @@ -60,24 +60,24 @@ export const POLYMARKET_ACTIVITY_RESPONSE = [ }, { proxyWallet: PROXY_WALLET_ADDRESS, - timestamp: 1760547989, + timestamp: 1760303247, conditionId: - '0xc40cbb2d7f5d2c43c624bd5b1d0b18cd3d0682b3937363ec7c1ad1d13bee107e', + '0xd55353d086e0d5d62383e0ff538c721eab4969a426d6404e2134f59a374894f4', type: 'TRADE', - size: 13.513512, - usdcSize: 1.499999, + size: 5, + usdcSize: 1.55, transactionHash: - '0xca1022f7d70055b8a82e9a96f53c99d52fb84a822e96f87b848c2ea916d75b6d', - price: 0.1109999384319931, + '0x685fa112399ca6503ef056095a805cda08c40c8b5a460890aada03af0930897c', + price: 0.31, asset: - '72685162394098505217895638060393901041260225434938300730127268362092284806692', + '46624220931236200146764216211260664534880387976574799044898986678450384828259', side: 'BUY', outcomeIndex: 0, - title: 'Will Andrew Cuomo win the 2025 NYC mayoral election?', - slug: 'will-andrew-cuomo-win-the-2025-nyc-mayoral-election', - icon: 'https://polymarket-upload.s3.us-east-2.amazonaws.com/will-andrew-cuomo-win-the-2025-nyc-mayoral-election-CFbNR1wG_T2X.jpg', - eventSlug: 'new-york-city-mayoral-election', - outcome: 'Yes', + title: '49ers vs. Buccaneers', + slug: 'nfl-sf-tb-2025-10-12', + icon: 'https://polymarket-upload.s3.us-east-2.amazonaws.com/nfl.png', + eventSlug: 'nfl-sf-tb-2025-10-12', + outcome: '49ers', name: 'cropMaster', pseudonym: 'Nonstop-Suitcase', bio: '', @@ -86,24 +86,24 @@ export const POLYMARKET_ACTIVITY_RESPONSE = [ }, { proxyWallet: PROXY_WALLET_ADDRESS, - timestamp: 1760547765, + timestamp: 1760277941, conditionId: - '0x1d395b8dea9dd429fbce85f8b8cbd5aa85ec8a2e8980755756be3eec03da5b9a', + '0x102c98f54c6d5be80d8380ce55a93ae10bc4fd285729b3aa33a6712484c9375a', type: 'TRADE', - size: 7.692306, - usdcSize: 0.999999, + size: 6, + usdcSize: 3, transactionHash: - '0x0b002df06d4657889b82367dc2c5a05847e9dec4299e628d7a93f5b1ce304f7d', - price: 0.12999989859997768, + '0x425e57719231b99264b4593ab7ff152f4479726deec604a2a84099e1a29446d7', + price: 0.5, asset: - '11584273833068499329017832956188664326032555278943683999231427554688326830185', + '109087901716216053417250825808952696497260040360991897081910571476476628813141', side: 'BUY', - outcomeIndex: 0, - title: 'Will the Kansas City Chiefs win Super Bowl 2026?', - slug: 'will-the-kansas-city-chiefs-win-super-bowl-2026', - icon: 'https://polymarket-upload.s3.us-east-2.amazonaws.com/NFL+Team+Logos/KC.png', - eventSlug: 'super-bowl-champion-2026-731', - outcome: 'Yes', + outcomeIndex: 1, + title: 'Seahawks vs. Jaguars', + slug: 'nfl-sea-jax-2025-10-12', + icon: 'https://polymarket-upload.s3.us-east-2.amazonaws.com/nfl.png', + eventSlug: 'nfl-sea-jax-2025-10-12', + outcome: 'Jaguars', name: 'cropMaster', pseudonym: 'Nonstop-Suitcase', bio: '', @@ -112,24 +112,24 @@ export const POLYMARKET_ACTIVITY_RESPONSE = [ }, { proxyWallet: PROXY_WALLET_ADDRESS, - timestamp: 1760387981, + timestamp: 1760559935, conditionId: - '0xb4bba8acb4a85c9f4ccd0eec6393e746c0176d271c2d0e52792968a05dd64b0c', + '0x39d45b454dcf932767962ad9cbd858c5a6ec21d4d48318a484775b2e83264467', type: 'TRADE', - size: 6, - usdcSize: 4.2, + size: 8.333332, + usdcSize: 0.999999, transactionHash: - '0xfff800f2ce58a03dc269917ad581fd394f81ed91d492a6b0bad35fac10a693d9', - price: 0.7, + '0x31c80f8e6c9e6dfdaf77ec6cb5022451211b23c258b5ad2f853f12925f9e4540', + price: 0.11999989919998387, asset: - '74764475795121623056006185669021820483304079465092865059622185495692711341808', + '19740329944962592380580142050369523795065853055987745520766432334608119837023', side: 'BUY', - outcomeIndex: 1, - title: 'Bears vs. Commanders', - slug: 'nfl-chi-was-2025-10-13', - icon: 'https://polymarket-upload.s3.us-east-2.amazonaws.com/nfl.png', - eventSlug: 'nfl-chi-was-2025-10-13', - outcome: 'Commanders', + outcomeIndex: 0, + title: 'Will the Buffalo Bills win Super Bowl 2026?', + slug: 'will-the-buffalo-bills-win-super-bowl-2026', + icon: 'https://polymarket-upload.s3.us-east-2.amazonaws.com/NFL+Team+Logos/BUF.png', + eventSlug: 'super-bowl-champion-2026-731', + outcome: 'Yes', name: 'cropMaster', pseudonym: 'Nonstop-Suitcase', bio: '', @@ -138,24 +138,24 @@ export const POLYMARKET_ACTIVITY_RESPONSE = [ }, { proxyWallet: PROXY_WALLET_ADDRESS, - timestamp: 1760387955, + timestamp: 1760548631, conditionId: - '0x626a49d9b82acaa9e86760c0cddad6a71aceefbef72f4f1c154ff8e358ae88c1', + '0x1d395b8dea9dd429fbce85f8b8cbd5aa85ec8a2e8980755756be3eec03da5b9a', type: 'TRADE', - size: 8, - usdcSize: 5.28, + size: 7.692306, + usdcSize: 0.999999, transactionHash: - '0xbd48fb580de2619d8b957e6302bb035d17e0dfbe6217ea846a1e8e03b7819818', - price: 0.66, + '0xb9a9ebbf1bda55d76c9c7138159aa58ab074890a41d3237b2a853319059be45b', + price: 0.12999989859997768, asset: - '41363179555803964193865225014057621561864035628882209196629573070642914610300', + '11584273833068499329017832956188664326032555278943683999231427554688326830185', side: 'BUY', outcomeIndex: 0, - title: 'Bills vs. Falcons', - slug: 'nfl-buf-atl-2025-10-13', - icon: 'https://polymarket-upload.s3.us-east-2.amazonaws.com/nfl.png', - eventSlug: 'nfl-buf-atl-2025-10-13', - outcome: 'Bills', + title: 'Will the Kansas City Chiefs win Super Bowl 2026?', + slug: 'will-the-kansas-city-chiefs-win-super-bowl-2026', + icon: 'https://polymarket-upload.s3.us-east-2.amazonaws.com/NFL+Team+Logos/KC.png', + eventSlug: 'super-bowl-champion-2026-731', + outcome: 'Yes', name: 'cropMaster', pseudonym: 'Nonstop-Suitcase', bio: '', @@ -164,24 +164,24 @@ export const POLYMARKET_ACTIVITY_RESPONSE = [ }, { proxyWallet: PROXY_WALLET_ADDRESS, - timestamp: 1760303247, + timestamp: 1760547989, conditionId: - '0xd55353d086e0d5d62383e0ff538c721eab4969a426d6404e2134f59a374894f4', + '0xc40cbb2d7f5d2c43c624bd5b1d0b18cd3d0682b3937363ec7c1ad1d13bee107e', type: 'TRADE', - size: 5, - usdcSize: 1.55, + size: 13.513512, + usdcSize: 1.499999, transactionHash: - '0x685fa112399ca6503ef056095a805cda08c40c8b5a460890aada03af0930897c', - price: 0.31, + '0xca1022f7d70055b8a82e9a96f53c99d52fb84a822e96f87b848c2ea916d75b6d', + price: 0.1109999384319931, asset: - '46624220931236200146764216211260664534880387976574799044898986678450384828259', + '72685162394098505217895638060393901041260225434938300730127268362092284806692', side: 'BUY', outcomeIndex: 0, - title: '49ers vs. Buccaneers', - slug: 'nfl-sf-tb-2025-10-12', - icon: 'https://polymarket-upload.s3.us-east-2.amazonaws.com/nfl.png', - eventSlug: 'nfl-sf-tb-2025-10-12', - outcome: '49ers', + title: 'Will Andrew Cuomo win the 2025 NYC mayoral election?', + slug: 'will-andrew-cuomo-win-the-2025-nyc-mayoral-election', + icon: 'https://polymarket-upload.s3.us-east-2.amazonaws.com/will-andrew-cuomo-win-the-2025-nyc-mayoral-election-CFbNR1wG_T2X.jpg', + eventSlug: 'new-york-city-mayoral-election', + outcome: 'Yes', name: 'cropMaster', pseudonym: 'Nonstop-Suitcase', bio: '', @@ -190,24 +190,24 @@ export const POLYMARKET_ACTIVITY_RESPONSE = [ }, { proxyWallet: PROXY_WALLET_ADDRESS, - timestamp: 1760277941, + timestamp: 1760547765, conditionId: - '0x102c98f54c6d5be80d8380ce55a93ae10bc4fd285729b3aa33a6712484c9375a', + '0x1d395b8dea9dd429fbce85f8b8cbd5aa85ec8a2e8980755756be3eec03da5b9a', type: 'TRADE', - size: 6, - usdcSize: 3, + size: 7.692306, + usdcSize: 0.999999, transactionHash: - '0x425e57719231b99264b4593ab7ff152f4479726deec604a2a84099e1a29446d7', - price: 0.5, + '0x0b002df06d4657889b82367dc2c5a05847e9dec4299e628d7a93f5b1ce304f7d', + price: 0.12999989859997768, asset: - '109087901716216053417250825808952696497260040360991897081910571476476628813141', + '11584273833068499329017832956188664326032555278943683999231427554688326830185', side: 'BUY', - outcomeIndex: 1, - title: 'Seahawks vs. Jaguars', - slug: 'nfl-sea-jax-2025-10-12', - icon: 'https://polymarket-upload.s3.us-east-2.amazonaws.com/nfl.png', - eventSlug: 'nfl-sea-jax-2025-10-12', - outcome: 'Jaguars', + outcomeIndex: 0, + title: 'Will the Kansas City Chiefs win Super Bowl 2026?', + slug: 'will-the-kansas-city-chiefs-win-super-bowl-2026', + icon: 'https://polymarket-upload.s3.us-east-2.amazonaws.com/NFL+Team+Logos/KC.png', + eventSlug: 'super-bowl-champion-2026-731', + outcome: 'Yes', name: 'cropMaster', pseudonym: 'Nonstop-Suitcase', bio: '', diff --git a/e2e/api-mocking/mock-responses/polymarket/polymarket-constants.ts b/e2e/api-mocking/mock-responses/polymarket/polymarket-constants.ts index df5f92320dd7..6543b9a6b0c4 100644 --- a/e2e/api-mocking/mock-responses/polymarket/polymarket-constants.ts +++ b/e2e/api-mocking/mock-responses/polymarket/polymarket-constants.ts @@ -8,13 +8,14 @@ export const PROXY_WALLET_ADDRESS = '0x5f7c8f3c8bedf5e7db63a34ef2f39322ca77fe72'; // Use the default fixture account address for consistency with tests export const USER_WALLET_ADDRESS = '0x76cf1cdd1fcc252442b50d6e97207228aa4aefc3'; + // Mock USDC balance (28.16 USDC = 28,160,000 = 0x1adb5e4) export const MOCK_USDC_BALANCE_WEI = '0x0000000000000000000000000000000000000000000000000000000001adb5e4'; // 28160000 in hex -// Post-claim USDC balance (48.16 USDC = 48,160,000 = 0x2de0300) +// Post-claim USDC balance (48.16 USDC = 48,160,000 = 0x2dedd00) export const POST_CLAIM_USDC_BALANCE_WEI = - '0x0000000000000000000000000000000000000000000000000000000002de0300'; + '0x0000000000000000000000000000000000000000000000000000000002dedd00'; export const POST_CASH_OUT_USDC_BALANCE_WEI = '0x00000000000000000000000000000000000000000000000000000000037f14a0'; // 58.66 USDC diff --git a/e2e/api-mocking/mock-responses/polymarket/polymarket-mocks.ts b/e2e/api-mocking/mock-responses/polymarket/polymarket-mocks.ts index 0b894e4bdc3e..e98f80bce90e 100644 --- a/e2e/api-mocking/mock-responses/polymarket/polymarket-mocks.ts +++ b/e2e/api-mocking/mock-responses/polymarket/polymarket-mocks.ts @@ -1,14 +1,13 @@ /** - * Comprehensive mock responses for all Polymarket API endpoints - * Imports response data from separate files for better organization + * File containing mock functionality for all Polymarket API endpoints */ import { Mockttp } from 'mockttp'; import { setupMockRequest } from '../../helpers/mockHelpers'; import { POLYMARKET_CURRENT_POSITIONS_RESPONSE, - POLYMARKET_RESOLVED_MARKETS_POSITIONS_RESPONSE, - createPositionsWithWinnings, + POLYMARKET_RESOLVED_LOST_POSITIONS_RESPONSE, + POLYMARKET_WINNING_POSITIONS_RESPONSE, } from './polymarket-positions-response'; import { POLYMARKET_EVENT_DETAILS_BLUE_JAYS_MARINERS_RESPONSE, @@ -49,6 +48,28 @@ import { createTransactionSentinelResponse } from './polymarket-transaction-sent * Mock for Polymarket API returning 500 error * This simulates the Polymarket API being down */ + +// Global variable to track current USDC balance +let currentUSDCBalance = MOCK_RPC_RESPONSES.USDC_BALANCE_RESULT; + +/** + * Mock Priority System + * Higher numbers = checked first (higher priority) + * + * 999 - Base mocks (catch-all for all RPC calls, set up once in POLYMARKET_COMPLETE_MOCKS) + * 1000 - API overrides (position removal, CLOB API) + * 1005 - Balance refresh mocks for /proxy calls (claim, cash-out, withdraw) + * 1006 - Balance refresh mocks for withdraw flow (separate to avoid conflicts) + * 1007 - Balance refresh mocks for direct polygon-rpc.com calls (claim, cash-out) + */ +const PRIORITY = { + BASE: 999, + API_OVERRIDE: 1000, + BALANCE_REFRESH_PROXY: 1005, + BALANCE_REFRESH_WITHDRAW: 1006, + BALANCE_REFRESH_DIRECT: 1007, +} as const; + export const POLYMARKET_API_DOWN = async (mockServer: Mockttp) => { await setupMockRequest(mockServer, { requestMethod: 'GET', @@ -173,7 +194,7 @@ export const POLYMARKET_CURRENT_POSITIONS_MOCKS = async ( ), ); }) - .asPriority(999) + .asPriority(PRIORITY.BASE) .thenCallback((request) => { const url = new URL(request.url).searchParams.get('url'); const userMatch = url?.match(/user=(0x[a-fA-F0-9]{40})/); @@ -208,11 +229,13 @@ export const POLYMARKET_CURRENT_POSITIONS_MOCKS = async ( * Mock for Polymarket positions API with controllable winning positions * Returns positions data for user with optional winning positions * This mock will trigger the CLAIM button + * Winning positions (redeemable=true) should be in resolved markets, not current positions */ export const POLYMARKET_POSITIONS_WITH_WINNINGS_MOCKS = async ( mockServer: Mockttp, includeWinnings: boolean = false, ) => { + // Mock for current positions (redeemable=false) - never include winning positions here await mockServer .forGet('/proxy') .matching((request) => { @@ -221,10 +244,11 @@ export const POLYMARKET_POSITIONS_WITH_WINNINGS_MOCKS = async ( url && /^https:\/\/data-api\.polymarket\.com\/positions\?.*user=0x[a-fA-F0-9]{40}.*$/.test( url, - ), + ) && + !url.includes('redeemable=true'), ); }) - .asPriority(999) + .asPriority(PRIORITY.BASE) .thenCallback((request) => { const url = new URL(request.url).searchParams.get('url'); const userMatch = url?.match(/user=(0x[a-fA-F0-9]{40})/); @@ -234,13 +258,10 @@ export const POLYMARKET_POSITIONS_WITH_WINNINGS_MOCKS = async ( const eventIdMatch = url?.match(/eventId=([0-9]+)/); const eventId = eventIdMatch ? eventIdMatch[1] : null; - // Use the new function to control whether to include winning positions - const positionsData = createPositionsWithWinnings(includeWinnings); - - // Filter positions by eventId if provided - let filteredPositions = positionsData; + // Current positions should never include winning positions + let filteredPositions = POLYMARKET_CURRENT_POSITIONS_RESPONSE; if (eventId) { - filteredPositions = positionsData.filter( + filteredPositions = POLYMARKET_CURRENT_POSITIONS_RESPONSE.filter( (position) => position.eventId === eventId, ); } @@ -256,6 +277,50 @@ export const POLYMARKET_POSITIONS_WITH_WINNINGS_MOCKS = async ( json: dynamicResponse, }; }); + + // Mock for resolved markets (redeemable=true) - add winning positions here if includeWinnings is true + await mockServer + .forGet('/proxy') + .matching((request) => { + const url = new URL(request.url).searchParams.get('url'); + return Boolean( + url && + /^https:\/\/data-api\.polymarket\.com\/positions\?.*user=0x[a-fA-F0-9]{40}.*$/.test( + url, + ) && + url.includes('redeemable=true'), + ); + }) + .asPriority(PRIORITY.BASE) + .thenCallback((request) => { + const url = new URL(request.url).searchParams.get('url'); + const userMatch = url?.match(/user=(0x[a-fA-F0-9]{40})/); + const userAddress = userMatch ? userMatch[1] : USER_WALLET_ADDRESS; + + // Combine lost positions with winning positions if includeWinnings is true + const resolvedMarkets = POLYMARKET_RESOLVED_LOST_POSITIONS_RESPONSE.map( + (position) => ({ + ...position, + proxyWallet: userAddress, + }), + ); + + let resolvedPositions = resolvedMarkets; + if (includeWinnings) { + const winningPositions = POLYMARKET_WINNING_POSITIONS_RESPONSE.map( + (position) => ({ + ...position, + proxyWallet: userAddress, + }), + ); + resolvedPositions = [...resolvedMarkets, ...winningPositions]; + } + + return { + statusCode: 200, + json: resolvedPositions, + }; + }); }; /** @@ -272,7 +337,7 @@ export const POLYMARKET_ORDER_BOOK_MOCKS = async (mockServer: Mockttp) => { /^https:\/\/clob\.polymarket\.com\/book\?token_id=\d+$/.test(url), ); }) - .asPriority(999) + .asPriority(PRIORITY.BASE) .thenCallback((request) => { const url = new URL(request.url).searchParams.get('url'); const tokenIdMatch = url?.match(/token_id=(\d+)/); @@ -353,17 +418,18 @@ export const POLYMARKET_RESOLVED_MARKETS_POSITIONS_MOCKS = async ( ); return matches; }) - .asPriority(999) + .asPriority(PRIORITY.BASE) .thenCallback((request) => { const url = new URL(request.url).searchParams.get('url'); const userMatch = url?.match(/user=(0x[a-fA-F0-9]{40})/); const userAddress = userMatch ? userMatch[1] : USER_WALLET_ADDRESS; - const dynamicResponse = - POLYMARKET_RESOLVED_MARKETS_POSITIONS_RESPONSE.map((position) => ({ + const dynamicResponse = POLYMARKET_RESOLVED_LOST_POSITIONS_RESPONSE.map( + (position) => ({ ...position, proxyWallet: userAddress, - })); + }), + ); return { statusCode: 200, @@ -388,7 +454,7 @@ export const POLYMARKET_ACTIVITY_MOCKS = async (mockServer: Mockttp) => { ), ); }) - .asPriority(999) + .asPriority(PRIORITY.BASE) .thenCallback((request) => { const url = new URL(request.url).searchParams.get('url'); const userMatch = url?.match(/user=(0x[a-fA-F0-9]{40})/); @@ -422,7 +488,7 @@ export const POLYMARKET_UPNL_MOCKS = async (mockServer: Mockttp) => { ), ); }) - .asPriority(999) + .asPriority(PRIORITY.BASE) .thenCallback((request) => { const url = new URL(request.url).searchParams.get('url'); const userMatch = url?.match(/user=(0x[a-fA-F0-9]{40})/); @@ -441,18 +507,6 @@ export const POLYMARKET_UPNL_MOCKS = async (mockServer: Mockttp) => { }); }; -/** - * Mock for both Polymarket positions endpoints (regular and redeemable) - * Returns both types of positions data for user 0x5f7c8f3c8bedf5e7db63a34ef2f39322ca77fe72 - */ -export const POLYMARKET_ALL_POSITIONS_MOCKS = async (mockServer: Mockttp) => { - await POLYMARKET_CURRENT_POSITIONS_MOCKS(mockServer); - await POLYMARKET_RESOLVED_MARKETS_POSITIONS_MOCKS(mockServer); -}; - -// Global variable to track current USDC balance -let currentUSDCBalance = MOCK_RPC_RESPONSES.USDC_BALANCE_RESULT; - /** * Mock for USDC balance calls on Polygon * Returns mock USDC balance for the test user @@ -509,13 +563,14 @@ export const POLYMARKET_USDC_BALANCE_MOCKS = async ( return false; }) - .asPriority(999) + .asPriority(PRIORITY.BASE) .thenCallback(async (request) => { const bodyText = await request.body.getText(); const body = bodyText ? JSON.parse(bodyText) : undefined; // Return appropriate mock response based on the call - let result = '0x'; + // Can be string (hex) or object (transaction receipt) + let result: string | object = '0x'; if (body?.method === 'eth_call') { const toAddress = body?.params?.[0]?.to; @@ -583,6 +638,11 @@ export const POLYMARKET_USDC_BALANCE_MOCKS = async ( } else if (body?.method === 'eth_estimateGas') { // Return a reasonable gas estimate result = '0xa49f3'; // ~675,683 gas + } else if (body?.method === 'eth_getTransactionReceipt') { + // Return a mock transaction receipt indicating the transaction is confirmed + // This is critical for TransactionController to mark transactions as confirmed + // TransactionController polls for receipts to determine transaction status + result = MOCK_RPC_RESPONSES.TRANSACTION_RECEIPT_RESULT; } // Note: We don't mock eth_gasPrice for Polygon - the app should use the gas API // (already mocked in DEFAULT_GAS_API_MOCKS) which provides EIP-1559 fields. @@ -617,7 +677,7 @@ export const POLYMARKET_MARKET_FEEDS_MOCKS = async (mockServer: Mockttp) => { /^https:\/\/gamma-api\.polymarket\.com\/events\/pagination/.test(url), ); }) - .asPriority(999) + .asPriority(PRIORITY.BASE) .thenCallback((request) => { const url = new URL(request.url).searchParams.get('url'); @@ -675,7 +735,7 @@ export const POLYMARKET_MARKET_FEEDS_MOCKS = async (mockServer: Mockttp) => { url && /^https:\/\/gamma-api\.polymarket\.com\/public-search/.test(url), ); }) - .asPriority(999) + .asPriority(PRIORITY.BASE) .thenCallback(() => ({ statusCode: 200, json: { @@ -685,21 +745,6 @@ export const POLYMARKET_MARKET_FEEDS_MOCKS = async (mockServer: Mockttp) => { })); }; -/** - * Mock for all Polymarket endpoints (positions, redeemable positions, activity, UpNL, and value) - * Returns data for proxy wallet: 0x5f7c8f3c8bedf5e7db63a34ef2f39322ca77fe72 - */ -export const POLYMARKET_COMPLETE_MOCKS = async (mockServer: Mockttp) => { - await POLYMARKET_ALL_POSITIONS_MOCKS(mockServer); - await POLYMARKET_ACTIVITY_MOCKS(mockServer); - await POLYMARKET_UPNL_MOCKS(mockServer); - await POLYMARKET_USDC_BALANCE_MOCKS(mockServer); // Uses default balance - await POLYMARKET_EVENT_DETAILS_MOCKS(mockServer); - await POLYMARKET_ORDER_BOOK_MOCKS(mockServer); - await POLYMARKET_MARKET_FEEDS_MOCKS(mockServer); - // Only user-specific data (positions, activity, UpNL) should be mocked -}; - /** * Mocks transaction sentinel for Polygon transactions * Mocks the infura_simulateTransactions method for transaction simulation @@ -710,8 +755,8 @@ export const POLYMARKET_TRANSACTION_SENTINEL_MOCKS = async ( mockServer: Mockttp, ) => { await mockServer - .forPost('https://tx-sentinel-polygon-mainnet.api.cx.metamask.io/') - .asPriority(999) + .forPost('https://tx-sentinel-polygon-mainnet.api.cx.metamask.io/') // + .asPriority(PRIORITY.BASE) .thenCallback(async (request) => { try { const bodyText = await request.body.getText(); @@ -751,116 +796,78 @@ export const POLYMARKET_TRANSACTION_SENTINEL_MOCKS = async ( } }); }; - -export const MOCK_BATCH_TRANSACTIONS = async (mockServer: Mockttp) => { - await POLYMARKET_USDC_BALANCE_MOCKS(mockServer, POST_CLAIM_USDC_BALANCE_WEI); - await POLYMARKET_TRANSACTION_SENTINEL_MOCKS(mockServer); - // Only user-specific data (positions, activity, UpNL) should be mocked -}; - /** - * Post-claim mock for USDC balance update - * This mock should be triggered after claim button is tapped - * Returns updated USDC balance reflecting claimed positions - * Also sets up EIP-7702 and transaction sentinel mocks specifically for claim flow + * Sets up mocks for USDC balance refresh calls after claim or cash-out operations + * This mock should be triggered after claim/cash-out transactions to update the displayed balance + * - Updates global USDC balance variable (like POLYMARKET_USDC_BALANCE_MOCKS) + * - Mocks balance refresh calls via /proxy endpoint (Polygon RPC) + * - Mocks direct polygon-rpc.com calls for USDC balance queries + * - Mocks eth_getTransactionCount calls (needed for claim flow transaction construction) + * - Returns the appropriate balance based on positionType ('claim' or 'cash-out') + * @param mockServer - The Mockttp server instance to configure mocks on + * @param positionType - The type of operation: 'claim' (returns 48.16 USDC) or 'cash-out' (returns 58.66 USDC) */ -export const POLYMARKET_POST_CLAIM_MOCKS = async (mockServer: Mockttp) => { - // Update USDC balance to claim amount using the reusable function - await POLYMARKET_USDC_BALANCE_MOCKS(mockServer, POST_CLAIM_USDC_BALANCE_WEI); +export const POLYMARKET_UPDATE_USDC_BALANCE_MOCKS = async ( + mockServer: Mockttp, + positionType: string, +) => { + // Update global balance based on position type (similar to POLYMARKET_USDC_BALANCE_MOCKS pattern) + let balance: string; + if (positionType === 'claim') { + balance = POST_CLAIM_USDC_BALANCE_WEI; // 48.16 USDC + } else if (positionType === 'cash-out') { + balance = POST_CASH_OUT_USDC_BALANCE_WEI; // 58.66 USDC + } else { + throw new Error(`Unknown positionType: ${positionType}`); + } - // Mock EIP-7702 eth_getCode for user wallet address (claim flow requires this) await mockServer .forPost('/proxy') - .matching(async (request) => { + .matching((request) => { const urlParam = new URL(request.url).searchParams.get('url'); - const isPolygonRPC = Boolean(urlParam?.includes('polygon')); - - if (isPolygonRPC) { - try { - const bodyText = await request.body.getText(); - const body = bodyText ? JSON.parse(bodyText) : undefined; - if (body?.method === 'eth_getCode') { - const address = body?.params?.[0]; - return address?.toLowerCase() === USER_WALLET_ADDRESS.toLowerCase(); - } - } catch (error) { - return false; - } - } - return false; + return Boolean( + urlParam?.includes('polygon') || urlParam?.includes('infura'), + ); }) - .asPriority(1000) // High priority for claim flow - .thenCallback(() => ({ - statusCode: 200, - json: { - id: 1, - jsonrpc: '2.0', - result: EIP7702_CODE_FORMAT(POLYGON_EIP7702_CONTRACT_ADDRESS), - }, - })); + .asPriority(PRIORITY.BALANCE_REFRESH_PROXY) // Higher priority (1005) to catch balance refresh calls before base mocks + .thenCallback(async (request) => { + const bodyText = await request.body.getText(); + const body = bodyText ? JSON.parse(bodyText) : undefined; - // Mock proxy wallet eth_call (0xaffed0e0 selector) for claim flow - await mockServer - .forPost('/proxy') - .matching(async (request) => { - const urlParam = new URL(request.url).searchParams.get('url'); - const isPolygonRPC = Boolean(urlParam?.includes('polygon')); + let result: string | object = '0x'; - if (isPolygonRPC) { - try { - const bodyText = await request.body.getText(); - const body = bodyText ? JSON.parse(bodyText) : undefined; - if (body?.method === 'eth_call') { - const toAddress = body?.params?.[0]?.to; - const callData = body?.params?.[0]?.data; - return ( - (toAddress?.toLowerCase() === - PROXY_WALLET_ADDRESS.toLowerCase() || - toAddress?.toLowerCase() === - '0x254955bE605cf7c4E683E92b157187550bd5e639'.toLowerCase()) && - callData === '0xaffed0e0' - ); - } - } catch (error) { - return false; + // Handle USDC balance calls + if (body?.method === 'eth_call') { + const toAddress = body?.params?.[0]?.to?.toLowerCase(); + if (toAddress === USDC_CONTRACT_ADDRESS.toLowerCase()) { + // USDC contract call - return updated balance + result = balance; + } else { + // For other eth_call, return empty result (let base mocks handle if needed) + result = MOCK_RPC_RESPONSES.EMPTY_RESULT; } + } else if (body?.method === 'eth_getTransactionCount') { + // Return a valid nonce (transaction count) - needed for claim flow + // This is critical for transaction construction, must be a valid hex number + result = MOCK_RPC_RESPONSES.TRANSACTION_COUNT_RESULT; + } else if (body?.method === 'eth_getTransactionReceipt') { + // Return a mock transaction receipt indicating the transaction is confirmed + // This is CRITICAL for TransactionController to mark transactions as confirmed + // TransactionController polls for receipts to determine transaction status + // Without this, transactions will remain in "pending" status + result = MOCK_RPC_RESPONSES.TRANSACTION_RECEIPT_RESULT; } - return false; - }) - .asPriority(1000) // High priority for claim flow - .thenCallback(() => ({ - statusCode: 200, - json: { - id: 1, - jsonrpc: '2.0', - result: - '0x0000000000000000000000000000000000000000000000000000000000000006', - }, - })); + // For other methods, return empty result (base mocks will handle them) - // Mock transaction sentinel for Polygon claim transactions - await POLYMARKET_TRANSACTION_SENTINEL_MOCKS(mockServer); - - // Mock updated UPNL reflecting claimed positions - await mockServer - .forGet('/proxy') - .matching((request) => { - const url = request.url; - return Boolean( - url && /^https:\/\/data-api\.polymarket\.com\/upnl/.test(url), - ); - }) - .asPriority(999) - .thenCallback(() => ({ - statusCode: 200, - json: [ - { - user: '0x5f7c8f3c8bedf5e7db63a34ef2f39322ca77fe72', - cashUpnl: 30.282462133473, // Increased by claimed amount - percentUpnl: 60.02623256406863, + return { + statusCode: 200, + json: { + id: body?.id ?? 50, + jsonrpc: '2.0', + result, }, - ], - })); + }; + }); }; /** @@ -868,7 +875,6 @@ export const POLYMARKET_POST_CLAIM_MOCKS = async (mockServer: Mockttp) => { * This mock should be triggered before tapping the cash-out button * - Mocks the CLOB API (polymarket order submission) * - Updates global USDC balance to post-cash-out amount (58.66 USDC) - * - Sets up high-priority mocks for balance refresh calls */ export const POLYMARKET_POST_CASH_OUT_MOCKS = async (mockServer: Mockttp) => { // Mock CLOB API for cash-out order submission @@ -878,7 +884,7 @@ export const POLYMARKET_POST_CASH_OUT_MOCKS = async (mockServer: Mockttp) => { const urlParam = new URL(request.url).searchParams.get('url'); return Boolean(urlParam?.includes('clob.polymarket.com')); }) - .asPriority(1000) // Higher priority to catch all clob requests + .asPriority(PRIORITY.API_OVERRIDE) // Higher priority to catch all clob requests .thenCallback(async () => { // Return success for any clob request const response = { @@ -900,93 +906,7 @@ export const POLYMARKET_POST_CASH_OUT_MOCKS = async (mockServer: Mockttp) => { return response; }); - // Update the global USDC balance to cash out amount (58.66 USDC) - // This updates currentUSDCBalance so all base RPC mocks return the updated balance - await POLYMARKET_USDC_BALANCE_MOCKS( - mockServer, - POST_CASH_OUT_USDC_BALANCE_WEI, - ); - - // High-priority mock to catch balance refresh calls after cash-out via /proxy - await mockServer - .forPost('/proxy') - .matching(async (request) => { - const urlParam = new URL(request.url).searchParams.get('url'); - const isPolygonRPC = Boolean( - urlParam?.includes('polygon') || urlParam?.includes('infura'), - ); - - if (isPolygonRPC) { - try { - const bodyText = await request.body.getText(); - const body = bodyText ? JSON.parse(bodyText) : undefined; - const isUSDCBalanceCall = - body?.method === 'eth_call' && - body?.params?.[0]?.to?.toLowerCase() === - USDC_CONTRACT_ADDRESS.toLowerCase(); - - return isUSDCBalanceCall; - } catch (error) { - return false; - } - } - return false; - }) - .asPriority(1005) // High priority to catch cash-out balance refresh calls - .thenCallback(() => ({ - statusCode: 200, - json: { - id: 50, - jsonrpc: '2.0', - result: POST_CASH_OUT_USDC_BALANCE_WEI, // 58.66 USDC - }, - })); - - // Also mock direct polygon-rpc.com calls for cash-out balance refresh - await mockServer - .forPost() - .matching((request) => request.url.includes('polygon-rpc.com')) - .asPriority(1007) - .thenCallback(async (request) => { - const bodyText = await request.body.getText(); - const body = bodyText ? JSON.parse(bodyText) : undefined; - - if ( - body?.method === 'eth_call' && - body?.params?.[0]?.to?.toLowerCase() === - USDC_CONTRACT_ADDRESS.toLowerCase() - ) { - // Return cash-out balance for USDC balance calls - return { - statusCode: 200, - body: JSON.stringify({ - id: body?.id ?? 1, - jsonrpc: '2.0', - result: POST_CASH_OUT_USDC_BALANCE_WEI, // 58.66 USDC - }), - }; - } - - // For other calls, return empty result - return { - statusCode: 200, - body: JSON.stringify({ - id: body?.id ?? 1, - jsonrpc: '2.0', - result: '0x', - }), - }; - }); -}; - -/** - * @deprecated Use POLYMARKET_POST_CASH_OUT_MOCKS instead - * This function is kept for backward compatibility but is now integrated into POLYMARKET_POST_CASH_OUT_MOCKS - */ -export const POLYMARKET_CASH_OUT_BALANCE_LOAD_MOCKS = async ( - _mockServer: Mockttp, -) => { - // No-op: Functionality moved to POLYMARKET_POST_CASH_OUT_MOCKS + await POLYMARKET_UPDATE_USDC_BALANCE_MOCKS(mockServer, 'cash-out'); }; /** @@ -1022,7 +942,7 @@ export const POLYMARKET_WITHDRAW_BALANCE_LOAD_MOCKS = async ( } return false; }) - .asPriority(1006) // High priority for withdraw balance calls (different from cash-out) + .asPriority(PRIORITY.BALANCE_REFRESH_WITHDRAW) // High priority for withdraw balance calls (different from cash-out) .thenCallback(() => ({ statusCode: 200, json: { @@ -1036,82 +956,33 @@ export const POLYMARKET_WITHDRAW_BALANCE_LOAD_MOCKS = async ( }; /** - * Force additional USDC balance calls after navigation - * This simulates the app refreshing the balance when navigating between screens + * Removes claimed positions from redeemable positions (resolved markets) + * After claiming, redeemable positions should be removed so the UI updates correctly * @param mockServer - The mockttp server instance - * @deprecated Use POLYMARKET_POST_CASH_OUT_MOCKS instead, which includes balance refresh logic */ -export const POLYMARKET_FORCE_BALANCE_REFRESH_MOCKS = async ( +export const POLYMARKET_REMOVE_CLAIMED_POSITIONS_MOCKS = async ( mockServer: Mockttp, ) => { - // Inline the balance refresh logic that was previously in POLYMARKET_CASH_OUT_BALANCE_LOAD_MOCKS - // This is kept for backward compatibility but should use POLYMARKET_POST_CASH_OUT_MOCKS instead + // Override redeemable positions (resolved markets) to remove winning positions after claiming + // This removes all resolved market positions (including winning positions) so the UI updates correctly await mockServer - .forPost('/proxy') - .matching(async (request) => { - const urlParam = new URL(request.url).searchParams.get('url'); - const isPolygonRPC = Boolean( - urlParam?.includes('polygon') || urlParam?.includes('infura'), + .forGet('/proxy') + .matching((request) => { + const url = new URL(request.url).searchParams.get('url'); + return Boolean( + url && + /^https:\/\/data-api\.polymarket\.com\/positions\?.*user=0x[a-fA-F0-9]{40}.*$/.test( + url, + ) && + url.includes('redeemable=true'), ); - - if (isPolygonRPC) { - try { - const bodyText = await request.body.getText(); - const body = bodyText ? JSON.parse(bodyText) : undefined; - const isUSDCBalanceCall = - body?.method === 'eth_call' && - body?.params?.[0]?.to?.toLowerCase() === - USDC_CONTRACT_ADDRESS.toLowerCase(); - - return isUSDCBalanceCall; - } catch (error) { - return false; - } - } - return false; }) - .asPriority(1005) + .asPriority(PRIORITY.API_OVERRIDE) // Higher priority to override the original redeemable positions mock .thenCallback(() => ({ + // Return empty array - all resolved market positions (including winning positions) are removed after claiming statusCode: 200, - json: { - id: 50, - jsonrpc: '2.0', - result: POST_CASH_OUT_USDC_BALANCE_WEI, // 58.66 USDC - }, + json: [], })); - - await mockServer - .forPost() - .matching((request) => request.url.includes('polygon-rpc.com')) - .asPriority(1007) - .thenCallback(async (request) => { - const bodyText = await request.body.getText(); - const body = bodyText ? JSON.parse(bodyText) : undefined; - - if ( - body?.method === 'eth_call' && - body?.params?.[0]?.to?.toLowerCase() === - USDC_CONTRACT_ADDRESS.toLowerCase() - ) { - return { - statusCode: 200, - body: JSON.stringify({ - id: body?.id ?? 1, - jsonrpc: '2.0', - result: POST_CASH_OUT_USDC_BALANCE_WEI, // 58.66 USDC - }), - }; - } - - return { - statusCode: 200, - body: JSON.stringify({ - id: body?.id ?? 1, - jsonrpc: '2.0', - result: '0x', - }), - }; - }); }; /** @@ -1137,7 +1008,7 @@ export const POLYMARKET_REMOVE_CASHED_OUT_POSITION_MOCKS = async ( !url.includes('redeemable=true'), ); }) - .asPriority(1000) // Higher priority to override the original positions mock + .asPriority(PRIORITY.API_OVERRIDE) // Higher priority to override the original positions mock .thenCallback((request) => { const url = new URL(request.url).searchParams.get('url'); const userMatch = url?.match(/user=(0x[a-fA-F0-9]{40})/); @@ -1184,7 +1055,7 @@ export const POLYMARKET_REMOVE_CASHED_OUT_POSITION_MOCKS = async ( ), ); }) - .asPriority(1000) // Higher priority to override the original activity mock + .asPriority(PRIORITY.API_OVERRIDE) // Higher priority to override the original activity mock .thenCallback((request) => { const url = new URL(request.url).searchParams.get('url'); const userMatch = url?.match(/user=(0x[a-fA-F0-9]{40})/); @@ -1236,3 +1107,27 @@ export const POLYMARKET_REMOVE_CASHED_OUT_POSITION_MOCKS = async ( }; }); }; + +/** + * Mock for both Polymarket positions endpoints (current and resolved positions) + * Returns both types of positions data for user 0x5f7c8f3c8bedf5e7db63a34ef2f39322ca77fe72 + */ +export const POLYMARKET_ALL_POSITIONS_MOCKS = async (mockServer: Mockttp) => { + await POLYMARKET_CURRENT_POSITIONS_MOCKS(mockServer); + await POLYMARKET_RESOLVED_MARKETS_POSITIONS_MOCKS(mockServer); +}; + +/** + * This can be considered the default user profile + * Mock for all Polymarket endpoints (positions, redeemable positions, activity, UpNL, and value) + * Returns data for proxy wallet: 0x5f7c8f3c8bedf5e7db63a34ef2f39322ca77fe72 + */ +export const POLYMARKET_COMPLETE_MOCKS = async (mockServer: Mockttp) => { + await POLYMARKET_ALL_POSITIONS_MOCKS(mockServer); + await POLYMARKET_ACTIVITY_MOCKS(mockServer); + await POLYMARKET_UPNL_MOCKS(mockServer); + await POLYMARKET_USDC_BALANCE_MOCKS(mockServer); // Uses default balance + await POLYMARKET_EVENT_DETAILS_MOCKS(mockServer); + await POLYMARKET_ORDER_BOOK_MOCKS(mockServer); + await POLYMARKET_MARKET_FEEDS_MOCKS(mockServer); +}; diff --git a/e2e/api-mocking/mock-responses/polymarket/polymarket-positions-response.ts b/e2e/api-mocking/mock-responses/polymarket/polymarket-positions-response.ts index d656490a6864..3ac1042a036f 100644 --- a/e2e/api-mocking/mock-responses/polymarket/polymarket-positions-response.ts +++ b/e2e/api-mocking/mock-responses/polymarket/polymarket-positions-response.ts @@ -164,9 +164,9 @@ export const POLYMARKET_CURRENT_POSITIONS_RESPONSE = [ ]; /* *endpoint: /positions?user&redeemable=true -This is all your positions in resolved markets +This contains all lost positions in resolved markets (no winning positions) */ -export const POLYMARKET_RESOLVED_MARKETS_POSITIONS_RESPONSE = [ +export const POLYMARKET_RESOLVED_LOST_POSITIONS_RESPONSE = [ { proxyWallet: PROXY_WALLET_ADDRESS, asset: diff --git a/e2e/api-mocking/mock-responses/polymarket/polymarket-rpc-response.ts b/e2e/api-mocking/mock-responses/polymarket/polymarket-rpc-response.ts index 7ac440daae0f..1dc19c7feb59 100644 --- a/e2e/api-mocking/mock-responses/polymarket/polymarket-rpc-response.ts +++ b/e2e/api-mocking/mock-responses/polymarket/polymarket-rpc-response.ts @@ -40,6 +40,26 @@ export const MOCK_RPC_RESPONSES = { // Mock contract code for deployed contracts CONTRACT_CODE_RESULT: '0x608060405234801561001057600080fd5b50', + + // Mock transaction receipt for confirmed transactions + // This receipt indicates a successful transaction confirmation + TRANSACTION_RECEIPT_RESULT: { + transactionHash: + '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef', + transactionIndex: '0x0', + blockNumber: '0x1234568', + blockHash: + '0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890', + from: USER_WALLET_ADDRESS.toLowerCase(), + to: PROXY_WALLET_ADDRESS.toLowerCase(), + cumulativeGasUsed: '0x94670', + gasUsed: '0x94670', + contractAddress: null, + logs: [], + status: '0x1', // Success status + logsBloom: + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + }, }; // Re-export for backward compatibility diff --git a/e2e/docs/README.md b/e2e/docs/README.md index d1180c0b535d..85de560fedf5 100644 --- a/e2e/docs/README.md +++ b/e2e/docs/README.md @@ -193,9 +193,6 @@ new FixtureBuilder().build(); // With popular networks new FixtureBuilder().withPopularNetworks().build(); -// With Ganache network -new FixtureBuilder().withGanacheNetwork().build(); - // With connected test dapp new FixtureBuilder() .withPermissionControllerConnectedToTestDapp(buildPermissions(['0x539'])) diff --git a/e2e/framework/fixtures/FixtureBuilder.ts b/e2e/framework/fixtures/FixtureBuilder.ts index 2f541d2e66fd..1e2dfc4d8bbb 100644 --- a/e2e/framework/fixtures/FixtureBuilder.ts +++ b/e2e/framework/fixtures/FixtureBuilder.ts @@ -4,6 +4,7 @@ import { getTestDappLocalUrl, getMockServerPort, getTestDappLocalUrlByDappCounter, + AnvilPort, } from './FixtureUtils'; import { merge } from 'lodash'; import { encryptVault } from './helpers'; @@ -1267,7 +1268,13 @@ class FixtureBuilder { return this; } - withGanacheNetwork(chainId = '0x539') { + /** + * @deprecated Use withNetworkController instead + * @param chainId + * @param port + * @returns + */ + withGanacheNetwork(chainId = '0x539', port = AnvilPort()) { const fixtures = this.fixture.state.engine.backgroundState; // Generate a unique key for the new network client ID @@ -1282,7 +1289,7 @@ class FixtureBuilder { rpcEndpoints: [ { networkClientId: newNetworkClientId, - url: `http://localhost:${getGanachePort()}`, + url: `http://localhost:${port}`, type: 'custom', name: 'Localhost', }, diff --git a/e2e/framework/fixtures/FixtureHelper.ts b/e2e/framework/fixtures/FixtureHelper.ts index 89995795465f..ed157dc82039 100644 --- a/e2e/framework/fixtures/FixtureHelper.ts +++ b/e2e/framework/fixtures/FixtureHelper.ts @@ -405,7 +405,7 @@ export async function withFixtures( testSuite: TestSuiteFunction, ) { const { - fixture, + fixture: fixtureOption, restartDevice = false, smartContracts, disableLocalNodes = false, @@ -465,6 +465,14 @@ export async function withFixtures( ); } + // Resolve fixture after local nodes are started so dynamic ports are known + let resolvedFixture: FixtureBuilder; + if (typeof fixtureOption === 'function') { + resolvedFixture = await fixtureOption({ localNodes }); + } else { + resolvedFixture = fixtureOption; + } + // Handle dapps if (dapps && dapps.length > 0) { await handleDapps(dapps, dappServer); @@ -472,7 +480,7 @@ export async function withFixtures( // Start fixture server await startFixtureServer(fixtureServer); - await loadFixture(fixtureServer, { fixture }); + await loadFixture(fixtureServer, { fixture: resolvedFixture }); logger.debug( 'The fixture server is started, and the initial state is successfully loaded.', ); diff --git a/e2e/framework/fixtures/README.md b/e2e/framework/fixtures/README.md index 5c94642d423a..5995f2b8ac6a 100644 --- a/e2e/framework/fixtures/README.md +++ b/e2e/framework/fixtures/README.md @@ -29,21 +29,21 @@ describe('My Test Suite', () => { ## WithFixturesOptions Reference -| Option | Type | Required | Default | Description | -| ----------------------- | ----------------------- | -------- | ------- | ----------------------------------------------------------------------------------------------------- | -| `fixture` | `FixtureBuilder` | `true` | - | The fixture object created via FixtureBuilder | -| `restartDevice` | `boolean` | `false` | `false` | Whether to restart the device before the test | -| `smartContracts` | `string[]` | `false` | - | The list of contract strings to be deployed via the first seeder | -| `disableLocalNodes` | `boolean` | `false` | `false` | Disables all local nodes for the test | -| `dapps` | `DappOptions[]` | `false` | - | Lists the dapps that should be launched before the tests | -| `localNodeOptions` | `LocalNodeOptionsInput` | `false` | Anvil | Allows overriding the use of Anvil in favor of any other node | -| `testSpecificMock` | `TestSpecificMock` | `false` | - | Allows to set mocks that are specific to the test | -| `launcArgs` | `LaunchArgs` | `false` | `-` | Allows sending arbitrary launchArgs such as the fixtureServerPort | -| `languageAndLocale` | `LanguageAndLocale` | `false` | - | Set the device Language and Locale of the device | -| `permissions` | `object` | `false` | - | Allows setting specific device permissions | -| `endTestfn` | `fn()` | `false` | - | Allows providing a function that is executed at the end of the test before the cleanup | -| `skipReactNativeReload` | `boolean` | `false` | `false` | Skip React Native reload during cleanup to preserve app state between tests | -| `useCommandQueueServer` | `boolean` | `false` | `false` | Launches an instance of CommandQueueServer to create a queue of items the app consumes on E2E context | +| Option | Type | Required | Default | Description | +| ----------------------- | ------------------------------------------------------- | -------- | ------- | ----------------------------------------------------------------------------------------------------- | +| `fixture` | `FixtureBuilder \| (ctx: { localNodes?: LocalNode[] })` | `true` | - | The fixture object created via FixtureBuilder or function that returns a fixtureBuilder | +| `restartDevice` | `boolean` | `false` | `false` | Whether to restart the device before the test | +| `smartContracts` | `string[]` | `false` | - | The list of contract strings to be deployed via the first seeder | +| `disableLocalNodes` | `boolean` | `false` | `false` | Disables all local nodes for the test | +| `dapps` | `DappOptions[]` | `false` | - | Lists the dapps that should be launched before the tests | +| `localNodeOptions` | `LocalNodeOptionsInput` | `false` | Anvil | Allows overriding the use of Anvil in favor of any other node | +| `testSpecificMock` | `TestSpecificMock` | `false` | - | Allows to set mocks that are specific to the test | +| `launcArgs` | `LaunchArgs` | `false` | `-` | Allows sending arbitrary launchArgs such as the fixtureServerPort | +| `languageAndLocale` | `LanguageAndLocale` | `false` | - | Set the device Language and Locale of the device | +| `permissions` | `object` | `false` | - | Allows setting specific device permissions | +| `endTestfn` | `fn()` | `false` | - | Allows providing a function that is executed at the end of the test before the cleanup | +| `skipReactNativeReload` | `boolean` | `false` | `false` | Skip React Native reload during cleanup to preserve app state between tests | +| `useCommandQueueServer` | `boolean` | `false` | `false` | Launches an instance of CommandQueueServer to create a queue of items the app consumes on E2E context | ## Migration from Legacy Options diff --git a/e2e/framework/types.ts b/e2e/framework/types.ts index 7e8856dcfb3f..74429ebe8f25 100644 --- a/e2e/framework/types.ts +++ b/e2e/framework/types.ts @@ -213,7 +213,7 @@ export type TestSpecificMock = (mockServer: Mockttp) => Promise; /** * The options for the withFixtures function. - * @param {FixtureBuilder} fixture - The state of the fixture to load. + * @param {FixtureBuilder | ((ctx: { localNodes?: LocalNode[] }) => FixtureBuilder | Promise)} fixture - The state of the fixture to load or a function that returns a fixture builder. * @param {boolean} [restartDevice=false] - If true, restarts the app to apply the loaded fixture. * @param {string[]} [smartContracts] - The smart contracts to load for test. These will be deployed on the different {localNodeOptions} * @param {LocalNodeOptionsInput} [localNodeOptions] - The local node options to use for the test. @@ -226,7 +226,11 @@ export type TestSpecificMock = (mockServer: Mockttp) => Promise; * @param {() => Promise} [endTestfn] - The function to execute after the test is finished. */ export interface WithFixturesOptions { - fixture: FixtureBuilder; + fixture: + | FixtureBuilder + | ((ctx: { + localNodes?: LocalNode[]; + }) => FixtureBuilder | Promise); restartDevice?: boolean; smartContracts?: string[]; disableLocalNodes?: boolean; diff --git a/e2e/pages/Browser/Confirmations/FooterActions.ts b/e2e/pages/Browser/Confirmations/FooterActions.ts index f39303031085..b304b9c80e4a 100644 --- a/e2e/pages/Browser/Confirmations/FooterActions.ts +++ b/e2e/pages/Browser/Confirmations/FooterActions.ts @@ -17,6 +17,7 @@ class FooterActions { await Gestures.waitAndTap(this.confirmButton, { elemDescription: 'Confirm button', delay: 1800, + waitForElementToDisappear: device.getPlatform() === 'android', }); } diff --git a/e2e/pages/Predict/PredictClaimPage.ts b/e2e/pages/Predict/PredictClaimPage.ts new file mode 100644 index 000000000000..d4db100a71ea --- /dev/null +++ b/e2e/pages/Predict/PredictClaimPage.ts @@ -0,0 +1,22 @@ +import { Matchers, Gestures } from '../../framework'; +import { PredictClaimConfirmationSelectorsIDs } from '../../selectors/Predict/Predict.selectors'; + +class PredictClaimPage { + get container(): DetoxElement { + return Matchers.getElementByID( + PredictClaimConfirmationSelectorsIDs.CLAIM_BACKGROUND_CONTAINER, + ); + } + get claimConfirmButton(): DetoxElement { + return Matchers.getElementByID( + PredictClaimConfirmationSelectorsIDs.CLAIM_CONFIRM_BUTTON, + ); + } + async tapClaimConfirmButton(): Promise { + await Gestures.waitAndTap(this.claimConfirmButton, { + elemDescription: 'Claim confirm button', + }); + } +} + +export default new PredictClaimPage(); diff --git a/e2e/pages/Transactions/ActivitiesView.ts b/e2e/pages/Transactions/ActivitiesView.ts index 970a79e28203..cacf483151f2 100644 --- a/e2e/pages/Transactions/ActivitiesView.ts +++ b/e2e/pages/Transactions/ActivitiesView.ts @@ -120,10 +120,10 @@ class ActivitiesView { async tapOnPredictionsTab(): Promise { await Gestures.waitAndTap(this.predictionsTab); } - async tapCashedOutPosition(positionName: string): Promise { + async tapPredictPosition(positionName: string): Promise { const el = Matchers.getElementByText(positionName); await Gestures.waitAndTap(el, { - elemDescription: `Tapping Cashed Out Position: ${positionName}`, + elemDescription: `Tapping Predict Position: ${positionName}`, }); } } diff --git a/e2e/pages/wallet/WalletView.ts b/e2e/pages/wallet/WalletView.ts index 08591e12d628..8ce927f3422d 100644 --- a/e2e/pages/wallet/WalletView.ts +++ b/e2e/pages/wallet/WalletView.ts @@ -5,7 +5,7 @@ import { import { PredictTabViewSelectorsIDs, PredictPositionsHeaderSelectorsIDs, - getPredictPositionSelector, + PredictPositionSelectorsIDs, } from '../../selectors/Predict/Predict.selectors'; import Gestures from '../../framework/Gestures'; import Matchers from '../../framework/Matchers'; @@ -163,7 +163,14 @@ class WalletView { } getPredictCurrentPositionCardByIndex(index: number = 0): DetoxElement { return Matchers.getElementByID( - getPredictPositionSelector.currentPositionCard, + PredictPositionSelectorsIDs.CURRENT_POSITION_CARD, + index, + ); + } + + getPredictResolvedPositionCardByIndex(index: number = 0): DetoxElement { + return Matchers.getElementByID( + PredictPositionSelectorsIDs.RESOLVED_POSITION_CARD, index, ); } @@ -437,6 +444,11 @@ class WalletView { WalletViewSelectorsIDs.DEFI_POSITIONS_CONTAINER, ); } + get claimButton(): DetoxElement { + return Matchers.getElementByID( + PredictPositionsHeaderSelectorsIDs.CLAIM_BUTTON, + ); + } get defiPositionDetailsContainer(): DetoxElement { return Matchers.getElementByID( @@ -495,10 +507,7 @@ class WalletView { } async tapClaimButton(): Promise { - const elem = Matchers.getElementByID( - PredictPositionsHeaderSelectorsIDs.CLAIM_BUTTON, - ); - await Gestures.waitAndTap(elem, { + await Gestures.waitAndTap(this.claimButton, { elemDescription: 'Claim Button', }); } diff --git a/e2e/seeder/anvil-manager.ts b/e2e/seeder/anvil-manager.ts index 49bedfc7208d..76b2715eade2 100644 --- a/e2e/seeder/anvil-manager.ts +++ b/e2e/seeder/anvil-manager.ts @@ -249,6 +249,13 @@ class AnvilManager { return { walletClient, publicClient, testClient }; } + /** + * Returns the port the Anvil server is listening on (if started). + */ + getPort(): number | undefined { + return this.serverPort; + } + /** * Get all accounts available on the Anvil server * @returns {Promise} Array of account addresses diff --git a/e2e/selectors/Predict/Predict.selectors.ts b/e2e/selectors/Predict/Predict.selectors.ts index 63a2670fa205..93581c84ef36 100644 --- a/e2e/selectors/Predict/Predict.selectors.ts +++ b/e2e/selectors/Predict/Predict.selectors.ts @@ -96,12 +96,11 @@ export const PredictPositionsSelectorsIDs = { RESOLVED_MARKETS_HEADER: 'predict-resolved-markets-header', } as const; -// Helper functions for position selectors with unique identifiers -export const getPredictPositionSelector = { - currentPositionCard: 'predict-current-position-card', - resolvedPositionCard: (positionId: string) => - `predict-resolved-position-card-${positionId}`, -}; +// Predict position selectors +export const PredictPositionSelectorsIDs = { + CURRENT_POSITION_CARD: 'predict-current-position-card', + RESOLVED_POSITION_CARD: 'predict-resolved-position-card', +} as const; // ======================================== // PREDICT CASH OUT SELECTORS diff --git a/e2e/specs/accounts/error-boundary-srp-backup.spec.ts b/e2e/specs/accounts/error-boundary-srp-backup.spec.ts index 78b2c7190176..ce2f816359dd 100644 --- a/e2e/specs/accounts/error-boundary-srp-backup.spec.ts +++ b/e2e/specs/accounts/error-boundary-srp-backup.spec.ts @@ -11,7 +11,10 @@ import TestHelpers from '../../helpers'; import Assertions from '../../framework/Assertions'; import RevealSecretRecoveryPhrase from '../../pages/Settings/SecurityAndPrivacy/RevealSecretRecoveryPhrase'; import ErrorBoundaryView from '../../pages/ErrorBoundaryView/ErrorBoundaryView'; -import { buildPermissions } from '../../framework/fixtures/FixtureUtils'; +import { + AnvilPort, + buildPermissions, +} from '../../framework/fixtures/FixtureUtils'; import { setupMockPostRequest } from '../../api-mocking/helpers/mockHelpers'; import { Mockttp } from 'mockttp'; import { @@ -19,6 +22,8 @@ import { SECURITY_ALERTS_REQUEST_BODY, securityAlertsUrl, } from '../../api-mocking/mock-responses/security-alerts-mock'; +import { LocalNode } from '../../framework/types'; +import { AnvilManager } from '../../seeder/anvil-manager'; const PASSWORD = '123123123'; @@ -36,12 +41,28 @@ describe(RegressionAccounts('Error Boundary Screen'), () => { dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions(['0x539']), + ) + .build(); + }, restartDevice: true, testSpecificMock: async (mockServer: Mockttp) => { await setupMockPostRequest( diff --git a/e2e/specs/assets/import-custom-token.spec.ts b/e2e/specs/assets/import-custom-token.spec.ts index 2a871fb3f58c..253598992825 100644 --- a/e2e/specs/assets/import-custom-token.spec.ts +++ b/e2e/specs/assets/import-custom-token.spec.ts @@ -8,6 +8,9 @@ import { withFixtures } from '../../framework/fixtures/FixtureHelper'; import FixtureBuilder from '../../framework/fixtures/FixtureBuilder'; import { loginToApp } from '../../viewHelper'; import { SMART_CONTRACTS } from '../../../app/util/test/smart-contracts'; +import { AnvilPort } from '../../framework/fixtures/FixtureUtils'; +import { LocalNode } from '../../framework/types'; +import { AnvilManager } from '../../seeder/anvil-manager'; describe(RegressionAssets('Import custom token'), () => { beforeAll(async () => { @@ -18,12 +21,28 @@ describe(RegressionAssets('Import custom token'), () => { it('should Import custom token with auto-population', async () => { await withFixtures( { - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withNetworkEnabledMap({ - eip155: { '0x539': true }, - }) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withNetworkEnabledMap({ + eip155: { '0x539': true }, + }) + .build(); + }, restartDevice: true, smartContracts: [SMART_CONTRACTS.HST], }, @@ -34,11 +53,8 @@ describe(RegressionAssets('Import custom token'), () => { await loginToApp(); await WalletView.tapImportTokensButton(); - await ImportTokensView.switchToCustomTab(); - await ImportTokensView.tapOnNetworkInput(); - await ImportTokensView.swipeNetworkList(); - await ImportTokensView.tapNetworkOption('Localhost'); await ImportTokensView.typeTokenAddress(hstAddress); + await new Promise((resolve) => setTimeout(resolve, 20000)); await Assertions.expectElementToHaveText( ImportTokensView.symbolInput, 'TST', diff --git a/e2e/specs/assets/import-tokens-via-asset-watcher.spec.ts b/e2e/specs/assets/import-tokens-via-asset-watcher.spec.ts index f7ff84ffcf45..845666bbc41d 100644 --- a/e2e/specs/assets/import-tokens-via-asset-watcher.spec.ts +++ b/e2e/specs/assets/import-tokens-via-asset-watcher.spec.ts @@ -12,12 +12,17 @@ import Assertions from '../../framework/Assertions'; import AssetWatchBottomSheet from '../../pages/Transactions/AssetWatchBottomSheet'; import WalletView from '../../pages/wallet/WalletView'; import NetworkListModal from '../../pages/Network/NetworkListModal'; -import { buildPermissions } from '../../framework/fixtures/FixtureUtils'; +import { + AnvilPort, + buildPermissions, +} from '../../framework/fixtures/FixtureUtils'; import { DappVariants } from '../../framework/Constants'; import { setEthAccounts, Caip25EndowmentPermissionName, } from '@metamask/chain-agnostic-permission'; +import { LocalNode } from '../../framework/types'; +import { AnvilManager } from '../../seeder/anvil-manager'; const ERC20_CONTRACT = SMART_CONTRACTS.HST; @@ -47,12 +52,28 @@ describe(RegressionNetworkAbstractions('Asset Watch:'), () => { dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildERC20PermsForAddress(), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withPermissionControllerConnectedToTestDapp( + buildERC20PermsForAddress(), + ) + .build(); + }, restartDevice: true, smartContracts: [ERC20_CONTRACT], }, diff --git a/e2e/specs/assets/nft-details.spec.ts b/e2e/specs/assets/nft-details.spec.ts index be7b9ff175ce..a218c172c00b 100644 --- a/e2e/specs/assets/nft-details.spec.ts +++ b/e2e/specs/assets/nft-details.spec.ts @@ -8,8 +8,13 @@ import WalletView from '../../pages/wallet/WalletView'; import ImportNFTView from '../../pages/wallet/ImportNFTFlow/ImportNFTView'; import Assertions from '../../framework/Assertions'; import enContent from '../../../locales/languages/en.json'; -import { buildPermissions } from '../../framework/fixtures/FixtureUtils'; +import { + AnvilPort, + buildPermissions, +} from '../../framework/fixtures/FixtureUtils'; import { DappVariants } from '../../framework/Constants'; +import { LocalNode } from '../../framework/types'; +import { AnvilManager } from '../../seeder/anvil-manager'; describe.skip(RegressionAssets('NFT Details page'), () => { const NFT_CONTRACT = SMART_CONTRACTS.NFTS; @@ -22,12 +27,28 @@ describe.skip(RegressionAssets('NFT Details page'), () => { it('show nft details', async () => { await withFixtures( { - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions(['0x539']), + ) + .build(); + }, dapps: [ { dappVariant: DappVariants.TEST_DAPP, diff --git a/e2e/specs/assets/transaction.spec.ts b/e2e/specs/assets/transaction.spec.ts index 578a31b97e4d..1e95a2f33d88 100644 --- a/e2e/specs/assets/transaction.spec.ts +++ b/e2e/specs/assets/transaction.spec.ts @@ -15,6 +15,9 @@ import ToastModal from '../../pages/wallet/ToastModal'; import { Mockttp } from 'mockttp'; import { setupRemoteFeatureFlagsMock } from '../../api-mocking/helpers/remoteFeatureFlagsHelper'; import { oldConfirmationsRemoteFeatureFlags } from '../../api-mocking/mock-responses/feature-flags-mocks'; +import { LocalNode } from '../../framework/types'; +import { AnvilPort } from '../../framework/fixtures/FixtureUtils'; +import { AnvilManager } from '../../seeder/anvil-manager'; describe(RegressionAssets('Transaction'), () => { beforeAll(async () => { @@ -29,12 +32,28 @@ describe(RegressionAssets('Transaction'), () => { const TOKEN_NAME = enContent.unit.eth; await withFixtures( { - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withNetworkEnabledMap({ - eip155: { '0x539': true }, - }) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withNetworkEnabledMap({ + eip155: { '0x539': true }, + }) + .build(); + }, restartDevice: true, testSpecificMock: async (mockServer: Mockttp) => { await setupRemoteFeatureFlagsMock( diff --git a/e2e/specs/confirmations-redesigned/signatures/signatures-typed.spec.ts b/e2e/specs/confirmations-redesigned/signatures/signatures-typed.spec.ts index d772a20f40a5..f90df7ae272c 100644 --- a/e2e/specs/confirmations-redesigned/signatures/signatures-typed.spec.ts +++ b/e2e/specs/confirmations-redesigned/signatures/signatures-typed.spec.ts @@ -8,12 +8,17 @@ import TestDApp from '../../../pages/Browser/TestDApp'; import { loginToApp } from '../../../viewHelper'; import { withFixtures } from '../../../framework/fixtures/FixtureHelper'; import { SmokeConfirmationsRedesigned } from '../../../tags'; -import { buildPermissions } from '../../../framework/fixtures/FixtureUtils'; +import { + buildPermissions, + AnvilPort, +} from '../../../framework/fixtures/FixtureUtils'; import RowComponents from '../../../pages/Browser/Confirmations/RowComponents'; import { DappVariants } from '../../../framework/Constants'; import { Mockttp } from 'mockttp'; import { setupRemoteFeatureFlagsMock } from '../../../api-mocking/helpers/remoteFeatureFlagsHelper'; import { confirmationsRedesignedFeatureFlags } from '../../../api-mocking/mock-responses/feature-flags-mocks'; +import { LocalNode } from '../../../framework/types'; +import { AnvilManager } from '../../../seeder/anvil-manager'; const SIGNATURE_LIST = [ { @@ -68,12 +73,28 @@ describe(SmokeConfirmationsRedesigned('Typed Signature Requests'), () => { dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions(['0x539']), + ) + .build(); + }, restartDevice: true, testSpecificMock, }, diff --git a/e2e/specs/confirmations-redesigned/signatures/signatures.spec.ts b/e2e/specs/confirmations-redesigned/signatures/signatures.spec.ts index 21b5399283d4..7e4a98e9cecd 100644 --- a/e2e/specs/confirmations-redesigned/signatures/signatures.spec.ts +++ b/e2e/specs/confirmations-redesigned/signatures/signatures.spec.ts @@ -8,12 +8,17 @@ import TestDApp from '../../../pages/Browser/TestDApp'; import { loginToApp } from '../../../viewHelper'; import { withFixtures } from '../../../framework/fixtures/FixtureHelper'; import { SmokeConfirmationsRedesigned } from '../../../tags'; -import { buildPermissions } from '../../../framework/fixtures/FixtureUtils'; +import { + buildPermissions, + AnvilPort, +} from '../../../framework/fixtures/FixtureUtils'; import RowComponents from '../../../pages/Browser/Confirmations/RowComponents'; import { DappVariants } from '../../../framework/Constants'; import { Mockttp } from 'mockttp'; import { setupRemoteFeatureFlagsMock } from '../../../api-mocking/helpers/remoteFeatureFlagsHelper'; import { confirmationsRedesignedFeatureFlags } from '../../../api-mocking/mock-responses/feature-flags-mocks'; +import { LocalNode } from '../../../framework/types'; +import { AnvilManager } from '../../../seeder/anvil-manager'; const SIGNATURE_LIST = [ { @@ -62,12 +67,28 @@ describe(SmokeConfirmationsRedesigned('Signature Requests'), () => { dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions(['0x539']), + ) + .build(); + }, restartDevice: true, testSpecificMock, }, diff --git a/e2e/specs/confirmations-redesigned/transactions/contract-deployment.spec.ts b/e2e/specs/confirmations-redesigned/transactions/contract-deployment.spec.ts index ebc949e32df5..0c97c3567183 100644 --- a/e2e/specs/confirmations-redesigned/transactions/contract-deployment.spec.ts +++ b/e2e/specs/confirmations-redesigned/transactions/contract-deployment.spec.ts @@ -7,7 +7,10 @@ import ConfirmationUITypes from '../../../pages/Browser/Confirmations/Confirmati import FooterActions from '../../../pages/Browser/Confirmations/FooterActions'; import Assertions from '../../../framework/Assertions'; import { withFixtures } from '../../../framework/fixtures/FixtureHelper'; -import { buildPermissions } from '../../../framework/fixtures/FixtureUtils'; +import { + buildPermissions, + AnvilPort, +} from '../../../framework/fixtures/FixtureUtils'; import RowComponents from '../../../pages/Browser/Confirmations/RowComponents'; import { SIMULATION_ENABLED_NETWORKS_MOCK } from '../../../api-mocking/mock-responses/simulations'; import TestDApp from '../../../pages/Browser/TestDApp'; @@ -16,6 +19,8 @@ import { Mockttp } from 'mockttp'; import { setupMockRequest } from '../../../api-mocking/helpers/mockHelpers'; import { setupRemoteFeatureFlagsMock } from '../../../api-mocking/helpers/remoteFeatureFlagsHelper'; import { confirmationsRedesignedFeatureFlags } from '../../../api-mocking/mock-responses/feature-flags-mocks'; +import { LocalNode } from '../../../framework/types'; +import { AnvilManager } from '../../../seeder/anvil-manager'; describe(SmokeConfirmationsRedesigned('Contract Deployment'), () => { const testSpecificMock = async (mockServer: Mockttp) => { @@ -43,12 +48,28 @@ describe(SmokeConfirmationsRedesigned('Contract Deployment'), () => { dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions(['0x539']), + ) + .build(); + }, restartDevice: true, testSpecificMock, }, diff --git a/e2e/specs/confirmations-redesigned/transactions/contract-interaction.spec.ts b/e2e/specs/confirmations-redesigned/transactions/contract-interaction.spec.ts index ea829841da9a..3c70fd75ba99 100644 --- a/e2e/specs/confirmations-redesigned/transactions/contract-interaction.spec.ts +++ b/e2e/specs/confirmations-redesigned/transactions/contract-interaction.spec.ts @@ -7,7 +7,10 @@ import ConfirmationUITypes from '../../../pages/Browser/Confirmations/Confirmati import FooterActions from '../../../pages/Browser/Confirmations/FooterActions'; import Assertions from '../../../framework/Assertions'; import { withFixtures } from '../../../framework/fixtures/FixtureHelper'; -import { buildPermissions } from '../../../framework/fixtures/FixtureUtils'; +import { + buildPermissions, + AnvilPort, +} from '../../../framework/fixtures/FixtureUtils'; import RowComponents from '../../../pages/Browser/Confirmations/RowComponents'; import { SIMULATION_ENABLED_NETWORKS_MOCK } from '../../../api-mocking/mock-responses/simulations'; import TestDApp from '../../../pages/Browser/TestDApp'; @@ -16,6 +19,8 @@ import { Mockttp } from 'mockttp'; import { setupMockRequest } from '../../../api-mocking/helpers/mockHelpers'; import { setupRemoteFeatureFlagsMock } from '../../../api-mocking/helpers/remoteFeatureFlagsHelper'; import { confirmationsRedesignedFeatureFlags } from '../../../api-mocking/mock-responses/feature-flags-mocks'; +import { LocalNode } from '../../../framework/types'; +import { AnvilManager } from '../../../seeder/anvil-manager'; describe(SmokeConfirmationsRedesigned('Contract Interaction'), () => { const NFT_CONTRACT = SMART_CONTRACTS.NFTS; @@ -44,12 +49,28 @@ describe(SmokeConfirmationsRedesigned('Contract Interaction'), () => { dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions(['0x539']), + ) + .build(); + }, restartDevice: true, testSpecificMock, smartContracts: [NFT_CONTRACT], diff --git a/e2e/specs/confirmations-redesigned/transactions/dapp-initiated-transfer.spec.ts b/e2e/specs/confirmations-redesigned/transactions/dapp-initiated-transfer.spec.ts index 6a7e24debb05..6400ba89a13e 100644 --- a/e2e/specs/confirmations-redesigned/transactions/dapp-initiated-transfer.spec.ts +++ b/e2e/specs/confirmations-redesigned/transactions/dapp-initiated-transfer.spec.ts @@ -7,7 +7,10 @@ import ConfirmationUITypes from '../../../pages/Browser/Confirmations/Confirmati import FooterActions from '../../../pages/Browser/Confirmations/FooterActions'; import Assertions from '../../../framework/Assertions'; import { withFixtures } from '../../../framework/fixtures/FixtureHelper'; -import { buildPermissions } from '../../../framework/fixtures/FixtureUtils'; +import { + AnvilPort, + buildPermissions, +} from '../../../framework/fixtures/FixtureUtils'; import RowComponents from '../../../pages/Browser/Confirmations/RowComponents'; import { SEND_ETH_SIMULATION_MOCK, @@ -30,6 +33,8 @@ import { } from '../../../api-mocking/mock-responses/security-alerts-mock'; import { setupRemoteFeatureFlagsMock } from '../../../api-mocking/helpers/remoteFeatureFlagsHelper'; import { confirmationsRedesignedFeatureFlags } from '../../../api-mocking/mock-responses/feature-flags-mocks'; +import { LocalNode } from '../../../framework/types'; +import { AnvilManager } from '../../../seeder/anvil-manager'; const expectedEvents = { TRANSACTION_ADDED: 'Transaction Added', @@ -102,16 +107,32 @@ describe.skip(SmokeConfirmationsRedesigned('DApp Initiated Transfer'), () => { dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withNetworkEnabledMap({ - eip155: { '0x539': true }, - }) - .withMetaMetricsOptIn() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withNetworkEnabledMap({ + eip155: { '0x539': true }, + }) + .withMetaMetricsOptIn() + .withPermissionControllerConnectedToTestDapp( + buildPermissions(['0x539']), + ) + .build(); + }, restartDevice: true, testSpecificMock, endTestfn: async ({ mockServer }) => { diff --git a/e2e/specs/confirmations-redesigned/transactions/per-dapp-selected-network.spec.ts b/e2e/specs/confirmations-redesigned/transactions/per-dapp-selected-network.spec.ts index 035b0c3160f1..743916fc8da6 100644 --- a/e2e/specs/confirmations-redesigned/transactions/per-dapp-selected-network.spec.ts +++ b/e2e/specs/confirmations-redesigned/transactions/per-dapp-selected-network.spec.ts @@ -1,6 +1,9 @@ import FixtureBuilder from '../../../framework/fixtures/FixtureBuilder.ts'; import { withFixtures } from '../../../framework/fixtures/FixtureHelper.ts'; -import { buildPermissions } from '../../../framework/fixtures/FixtureUtils.ts'; +import { + buildPermissions, + AnvilPort, +} from '../../../framework/fixtures/FixtureUtils.ts'; import Browser from '../../../pages/Browser/BrowserView.ts'; import ConfirmationFooterActions from '../../../pages/Browser/Confirmations/FooterActions.ts'; import ConfirmationUITypes from '../../../pages/Browser/Confirmations/ConfirmationUITypes.ts'; @@ -19,6 +22,8 @@ import { DappVariants } from '../../../framework/Constants.ts'; import { setupRemoteFeatureFlagsMock } from '../../../api-mocking/helpers/remoteFeatureFlagsHelper.ts'; import { confirmationsRedesignedFeatureFlags } from '../../../api-mocking/mock-responses/feature-flags-mocks.ts'; import { Mockttp } from 'mockttp'; +import { LocalNode } from '../../../framework/types'; +import { AnvilManager } from '../../../seeder/anvil-manager'; const LOCAL_CHAIN_ID = '0x539'; const LOCAL_CHAIN_NAME = 'Localhost'; @@ -67,12 +72,28 @@ describe(SmokeConfirmationsRedesigned('Per Dapp Selected Network'), () => { dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions([LOCAL_CHAIN_ID]), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: LOCAL_CHAIN_ID, + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: LOCAL_CHAIN_NAME, + ticker: 'ETH', + }, + }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions([LOCAL_CHAIN_ID]), + ) + .build(); + }, restartDevice: true, testSpecificMock, }, @@ -147,12 +168,28 @@ describe(RegressionConfirmations('Per Dapp Selected Network'), () => { dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions([LOCAL_CHAIN_ID]), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: LOCAL_CHAIN_ID, + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: LOCAL_CHAIN_NAME, + ticker: 'ETH', + }, + }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions([LOCAL_CHAIN_ID]), + ) + .build(); + }, restartDevice: true, testSpecificMock, }, diff --git a/e2e/specs/confirmations-redesigned/transactions/send-max-transfer.spec.ts b/e2e/specs/confirmations-redesigned/transactions/send-max-transfer.spec.ts index 3058233af379..36526ae87f06 100644 --- a/e2e/specs/confirmations-redesigned/transactions/send-max-transfer.spec.ts +++ b/e2e/specs/confirmations-redesigned/transactions/send-max-transfer.spec.ts @@ -1,7 +1,10 @@ import { SmokeConfirmationsRedesigned } from '../../../tags'; import { loginToApp } from '../../../viewHelper'; import { withFixtures } from '../../../framework/fixtures/FixtureHelper'; -import { buildPermissions } from '../../../framework/fixtures/FixtureUtils'; +import { + buildPermissions, + AnvilPort, +} from '../../../framework/fixtures/FixtureUtils'; import { SEND_ETH_SIMULATION_MOCK, SIMULATION_ENABLED_NETWORKS_MOCK, @@ -20,6 +23,8 @@ import { import { Mockttp } from 'mockttp'; import { setupRemoteFeatureFlagsMock } from '../../../api-mocking/helpers/remoteFeatureFlagsHelper'; import { confirmationsRedesignedFeatureFlags } from '../../../api-mocking/mock-responses/feature-flags-mocks'; +import { LocalNode } from '../../../framework/types'; +import { AnvilManager } from '../../../seeder/anvil-manager'; const RECIPIENT = '0x0c54fccd2e384b4bb6f2e405bf5cbc15a017aafb'; @@ -63,15 +68,31 @@ describe(SmokeConfirmationsRedesigned('Send Max Transfer'), () => { it('handles max native asset', async () => { await withFixtures( { - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withNetworkEnabledMap({ - eip155: { '0x539': true }, - }) - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withNetworkEnabledMap({ + eip155: { '0x539': true }, + }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions(['0x539']), + ) + .build(); + }, restartDevice: true, testSpecificMock, }, diff --git a/e2e/specs/confirmations-redesigned/transactions/token-approve/approve.spec.ts b/e2e/specs/confirmations-redesigned/transactions/token-approve/approve.spec.ts index b47b66b7360c..f31bf18b3b90 100644 --- a/e2e/specs/confirmations-redesigned/transactions/token-approve/approve.spec.ts +++ b/e2e/specs/confirmations-redesigned/transactions/token-approve/approve.spec.ts @@ -7,7 +7,10 @@ import ConfirmationUITypes from '../../../../pages/Browser/Confirmations/Confirm import FooterActions from '../../../../pages/Browser/Confirmations/FooterActions'; import Assertions from '../../../../framework/Assertions'; import { withFixtures } from '../../../../framework/fixtures/FixtureHelper'; -import { buildPermissions } from '../../../../framework/fixtures/FixtureUtils'; +import { + buildPermissions, + AnvilPort, +} from '../../../../framework/fixtures/FixtureUtils'; import RowComponents from '../../../../pages/Browser/Confirmations/RowComponents'; import TokenApproveConfirmation from '../../../../pages/Confirmation/TokenApproveConfirmation'; import { SIMULATION_ENABLED_NETWORKS_MOCK } from '../../../../api-mocking/mock-responses/simulations'; @@ -17,6 +20,8 @@ import { setupMockRequest } from '../../../../api-mocking/helpers/mockHelpers'; import { Mockttp } from 'mockttp'; import { setupRemoteFeatureFlagsMock } from '../../../../api-mocking/helpers/remoteFeatureFlagsHelper'; import { confirmationsRedesignedFeatureFlags } from '../../../../api-mocking/mock-responses/feature-flags-mocks'; +import { LocalNode } from '../../../../framework/types'; +import { AnvilManager } from '../../../../seeder/anvil-manager'; describe(SmokeConfirmationsRedesigned('Token Approve - approve method'), () => { const ERC_20_CONTRACT = SMART_CONTRACTS.HST; @@ -43,12 +48,28 @@ describe(SmokeConfirmationsRedesigned('Token Approve - approve method'), () => { dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions(['0x539']), + ) + .build(); + }, restartDevice: true, testSpecificMock, smartContracts: [ERC_20_CONTRACT], @@ -116,12 +137,28 @@ describe(SmokeConfirmationsRedesigned('Token Approve - approve method'), () => { dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions(['0x539']), + ) + .build(); + }, restartDevice: true, testSpecificMock, smartContracts: [ERC_721_CONTRACT], diff --git a/e2e/specs/confirmations-redesigned/transactions/token-approve/increase-allowance.spec.ts b/e2e/specs/confirmations-redesigned/transactions/token-approve/increase-allowance.spec.ts index 393237a3898d..0dcbb29c1ffb 100644 --- a/e2e/specs/confirmations-redesigned/transactions/token-approve/increase-allowance.spec.ts +++ b/e2e/specs/confirmations-redesigned/transactions/token-approve/increase-allowance.spec.ts @@ -7,7 +7,10 @@ import ConfirmationUITypes from '../../../../pages/Browser/Confirmations/Confirm import FooterActions from '../../../../pages/Browser/Confirmations/FooterActions'; import Assertions from '../../../../framework/Assertions'; import { withFixtures } from '../../../../framework/fixtures/FixtureHelper'; -import { buildPermissions } from '../../../../framework/fixtures/FixtureUtils'; +import { + AnvilPort, + buildPermissions, +} from '../../../../framework/fixtures/FixtureUtils'; import RowComponents from '../../../../pages/Browser/Confirmations/RowComponents'; import TokenApproveConfirmation from '../../../../pages/Confirmation/TokenApproveConfirmation'; import { SIMULATION_ENABLED_NETWORKS_MOCK } from '../../../../api-mocking/mock-responses/simulations'; @@ -17,6 +20,8 @@ import { Mockttp } from 'mockttp'; import { setupMockRequest } from '../../../../api-mocking/helpers/mockHelpers'; import { confirmationsRedesignedFeatureFlags } from '../../../../api-mocking/mock-responses/feature-flags-mocks'; import { setupRemoteFeatureFlagsMock } from '../../../../api-mocking/helpers/remoteFeatureFlagsHelper'; +import { LocalNode } from '../../../../framework/types'; +import { AnvilManager } from '../../../../seeder/anvil-manager'; describe( SmokeConfirmationsRedesigned('Token Approve - increaseAllowance method'), @@ -44,12 +49,28 @@ describe( dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions(['0x539']), + ) + .build(); + }, restartDevice: true, testSpecificMock, smartContracts: [ERC_20_CONTRACT], diff --git a/e2e/specs/confirmations-redesigned/transactions/token-approve/set-approval-for-all.spec.ts b/e2e/specs/confirmations-redesigned/transactions/token-approve/set-approval-for-all.spec.ts index 298a02d8df62..686bf9e519c4 100644 --- a/e2e/specs/confirmations-redesigned/transactions/token-approve/set-approval-for-all.spec.ts +++ b/e2e/specs/confirmations-redesigned/transactions/token-approve/set-approval-for-all.spec.ts @@ -7,7 +7,10 @@ import ConfirmationUITypes from '../../../../pages/Browser/Confirmations/Confirm import FooterActions from '../../../../pages/Browser/Confirmations/FooterActions'; import Assertions from '../../../../framework/Assertions'; import { withFixtures } from '../../../../framework/fixtures/FixtureHelper'; -import { buildPermissions } from '../../../../framework/fixtures/FixtureUtils'; +import { + AnvilPort, + buildPermissions, +} from '../../../../framework/fixtures/FixtureUtils'; import RowComponents from '../../../../pages/Browser/Confirmations/RowComponents'; import TokenApproveConfirmation from '../../../../pages/Confirmation/TokenApproveConfirmation'; import { SIMULATION_ENABLED_NETWORKS_MOCK } from '../../../../api-mocking/mock-responses/simulations'; @@ -17,6 +20,8 @@ import { setupMockRequest } from '../../../../api-mocking/helpers/mockHelpers'; import { Mockttp } from 'mockttp'; import { setupRemoteFeatureFlagsMock } from '../../../../api-mocking/helpers/remoteFeatureFlagsHelper'; import { confirmationsRedesignedFeatureFlags } from '../../../../api-mocking/mock-responses/feature-flags-mocks'; +import { LocalNode } from '../../../../framework/types'; +import { AnvilManager } from '../../../../seeder/anvil-manager'; describe( SmokeConfirmationsRedesigned('Token Approve - setApprovalForAll method'), @@ -45,12 +50,28 @@ describe( dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions(['0x539']), + ) + .build(); + }, restartDevice: true, testSpecificMock, smartContracts: [ERC_721_CONTRACT], @@ -76,22 +97,39 @@ describe( // Check all expected row components are visible await Assertions.expectElementToBeVisible( RowComponents.AccountNetwork, + { + description: 'Account Network', + }, ); - await Assertions.expectElementToBeVisible(RowComponents.ApproveRow); + await Assertions.expectElementToBeVisible(RowComponents.ApproveRow, { + description: 'Approve Row', + }); await Assertions.expectElementToBeVisible( RowComponents.NetworkAndOrigin, + { + description: 'Network And Origin', + }, ); await Assertions.expectElementToBeVisible( RowComponents.GasFeesDetails, + { + description: 'Gas Fees Details', + }, ); await Assertions.expectElementToBeVisible( RowComponents.AdvancedDetails, + { + description: 'Advanced Details', + }, ); // Check spending cap is visible and has the correct value await Assertions.expectElementToHaveText( TokenApproveConfirmation.SpendingCapValue, 'All', + { + description: 'Spending Cap Value', + }, ); // Accept confirmation @@ -113,12 +151,28 @@ describe( dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions(['0x539']), + ) + .build(); + }, restartDevice: true, testSpecificMock, smartContracts: [ERC_1155_CONTRACT], @@ -167,12 +221,28 @@ describe( dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions(['0x539']), + ) + .build(); + }, restartDevice: true, testSpecificMock, smartContracts: [ERC_721_CONTRACT], diff --git a/e2e/specs/confirmations-redesigned/transactions/wallet-initiated-transfer.spec.ts b/e2e/specs/confirmations-redesigned/transactions/wallet-initiated-transfer.spec.ts index e82e74c94256..e26d54d472c7 100644 --- a/e2e/specs/confirmations-redesigned/transactions/wallet-initiated-transfer.spec.ts +++ b/e2e/specs/confirmations-redesigned/transactions/wallet-initiated-transfer.spec.ts @@ -1,7 +1,10 @@ import { SmokeConfirmationsRedesigned } from '../../../tags'; import { loginToApp } from '../../../viewHelper'; import { withFixtures } from '../../../framework/fixtures/FixtureHelper'; -import { buildPermissions } from '../../../framework/fixtures/FixtureUtils'; +import { + AnvilPort, + buildPermissions, +} from '../../../framework/fixtures/FixtureUtils'; import { SEND_ETH_SIMULATION_MOCK, SIMULATION_ENABLED_NETWORKS_MOCK, @@ -22,6 +25,8 @@ import { } from '../../../api-mocking/helpers/mockHelpers'; import { setupRemoteFeatureFlagsMock } from '../../../api-mocking/helpers/remoteFeatureFlagsHelper'; import { confirmationsRedesignedFeatureFlags } from '../../../api-mocking/mock-responses/feature-flags-mocks'; +import { LocalNode } from '../../../framework/types'; +import { AnvilManager } from '../../../seeder/anvil-manager'; const RECIPIENT = '0x0c54fccd2e384b4bb6f2e405bf5cbc15a017aafb'; const AMOUNT = '1'; @@ -65,15 +70,31 @@ describe(SmokeConfirmationsRedesigned('Wallet Initiated Transfer'), () => { it('sends native asset', async () => { await withFixtures( { - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withNetworkEnabledMap({ - eip155: { '0x539': true }, - }) - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withNetworkEnabledMap({ + eip155: { '0x539': true }, + }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions(['0x539']), + ) + .build(); + }, restartDevice: true, testSpecificMock, }, diff --git a/e2e/specs/confirmations/advanced-gas-fees.mock.spec.ts b/e2e/specs/confirmations/advanced-gas-fees.mock.spec.ts index efca3bbc4f74..79e4a5ae4be4 100644 --- a/e2e/specs/confirmations/advanced-gas-fees.mock.spec.ts +++ b/e2e/specs/confirmations/advanced-gas-fees.mock.spec.ts @@ -11,6 +11,9 @@ import Assertions from '../../framework/Assertions'; import { Mockttp } from 'mockttp'; import { oldConfirmationsRemoteFeatureFlags } from '../../api-mocking/mock-responses/feature-flags-mocks'; import { setupRemoteFeatureFlagsMock } from '../../api-mocking/helpers/remoteFeatureFlagsHelper'; +import { AnvilPort } from '../../framework/fixtures/FixtureUtils'; +import { LocalNode } from '../../framework/types'; +import { AnvilManager } from '../../seeder/anvil-manager'; const VALID_ADDRESS = '0xebe6CcB6B55e1d094d9c58980Bc10Fed69932cAb'; const testSpecificMock = async (mockServer: Mockttp) => { @@ -26,7 +29,25 @@ describe( it('should edit priority gas settings and send ETH', async () => { await withFixtures( { - fixture: new FixtureBuilder().withGanacheNetwork().build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .build(); + }, restartDevice: true, testSpecificMock, }, diff --git a/e2e/specs/confirmations/approve-custom-erc20.spec.ts b/e2e/specs/confirmations/approve-custom-erc20.spec.ts index eb4abbbec1e8..23631c284256 100644 --- a/e2e/specs/confirmations/approve-custom-erc20.spec.ts +++ b/e2e/specs/confirmations/approve-custom-erc20.spec.ts @@ -9,11 +9,16 @@ import { SMART_CONTRACTS } from '../../../app/util/test/smart-contracts'; import ContractApprovalBottomSheet from '../../pages/Browser/ContractApprovalBottomSheet'; import Assertions from '../../framework/Assertions'; import { ActivitiesViewSelectorsText } from '../../selectors/Transactions/ActivitiesView.selectors'; -import { buildPermissions } from '../../framework/fixtures/FixtureUtils'; +import { + buildPermissions, + AnvilPort, +} from '../../framework/fixtures/FixtureUtils'; import { DappVariants } from '../../framework/Constants'; import { Mockttp } from 'mockttp'; import { setupRemoteFeatureFlagsMock } from '../../api-mocking/helpers/remoteFeatureFlagsHelper'; import { oldConfirmationsRemoteFeatureFlags } from '../../api-mocking/mock-responses/feature-flags-mocks'; +import { LocalNode } from '../../framework/types'; +import { AnvilManager } from '../../seeder/anvil-manager'; const HST_CONTRACT = SMART_CONTRACTS.HST; @@ -33,12 +38,28 @@ describe(RegressionConfirmations('ERC20 tokens'), () => { dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions(['0x539']), + ) + .build(); + }, restartDevice: true, smartContracts: [HST_CONTRACT], testSpecificMock, diff --git a/e2e/specs/confirmations/approve-default-erc20.spec.ts b/e2e/specs/confirmations/approve-default-erc20.spec.ts index b142df459866..2c53848a1755 100644 --- a/e2e/specs/confirmations/approve-default-erc20.spec.ts +++ b/e2e/specs/confirmations/approve-default-erc20.spec.ts @@ -11,11 +11,16 @@ import ContractApprovalBottomSheet from '../../pages/Browser/ContractApprovalBot import Assertions from '../../framework/Assertions'; import TabBarComponent from '../../pages/wallet/TabBarComponent'; import TestDApp from '../../pages/Browser/TestDApp'; -import { buildPermissions } from '../../framework/fixtures/FixtureUtils'; +import { + buildPermissions, + AnvilPort, +} from '../../framework/fixtures/FixtureUtils'; import { DappVariants } from '../../framework/Constants'; import { Mockttp } from 'mockttp'; import { setupRemoteFeatureFlagsMock } from '../../api-mocking/helpers/remoteFeatureFlagsHelper'; import { oldConfirmationsRemoteFeatureFlags } from '../../api-mocking/mock-responses/feature-flags-mocks'; +import { LocalNode } from '../../framework/types'; +import { AnvilManager } from '../../seeder/anvil-manager'; const HST_CONTRACT = SMART_CONTRACTS.HST; const EXPECTED_TOKEN_AMOUNT = '7'; @@ -31,12 +36,28 @@ describe(RegressionConfirmations('ERC20 tokens'), () => { await withFixtures( { - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions(['0x539']), + ) + .build(); + }, dapps: [ { dappVariant: DappVariants.TEST_DAPP, diff --git a/e2e/specs/confirmations/approve-erc721.spec.ts b/e2e/specs/confirmations/approve-erc721.spec.ts index c32d6787462a..8c77aea22dbb 100644 --- a/e2e/specs/confirmations/approve-erc721.spec.ts +++ b/e2e/specs/confirmations/approve-erc721.spec.ts @@ -8,10 +8,15 @@ import { DappVariants } from '../../framework/Constants'; import { SMART_CONTRACTS } from '../../../app/util/test/smart-contracts'; import { ActivitiesViewSelectorsText } from '../../selectors/Transactions/ActivitiesView.selectors'; import Assertions from '../../framework/Assertions'; -import { buildPermissions } from '../../framework/fixtures/FixtureUtils'; +import { + buildPermissions, + AnvilPort, +} from '../../framework/fixtures/FixtureUtils'; import { Mockttp } from 'mockttp'; import { setupRemoteFeatureFlagsMock } from '../../api-mocking/helpers/remoteFeatureFlagsHelper'; import { oldConfirmationsRemoteFeatureFlags } from '../../api-mocking/mock-responses/feature-flags-mocks'; +import { LocalNode } from '../../framework/types'; +import { AnvilManager } from '../../seeder/anvil-manager'; describe(RegressionConfirmations('ERC721 tokens'), () => { const NFT_CONTRACT = SMART_CONTRACTS.NFTS; @@ -31,12 +36,28 @@ describe(RegressionConfirmations('ERC721 tokens'), () => { dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions(['0x539']), + ) + .build(); + }, restartDevice: true, smartContracts: [NFT_CONTRACT], testSpecificMock, diff --git a/e2e/specs/confirmations/batch-transfer-erc1155.spec.ts b/e2e/specs/confirmations/batch-transfer-erc1155.spec.ts index 8362fd3e78ea..b177fc11b5b0 100644 --- a/e2e/specs/confirmations/batch-transfer-erc1155.spec.ts +++ b/e2e/specs/confirmations/batch-transfer-erc1155.spec.ts @@ -10,12 +10,17 @@ import Assertions from '../../framework/Assertions'; import { ContractApprovalBottomSheetSelectorsText } from '../../selectors/Browser/ContractApprovalBottomSheet.selectors'; import ContractApprovalBottomSheet from '../../pages/Browser/ContractApprovalBottomSheet'; import { DappVariants } from '../../framework/Constants'; -import { buildPermissions } from '../../framework/fixtures/FixtureUtils'; +import { + buildPermissions, + AnvilPort, +} from '../../framework/fixtures/FixtureUtils'; import { Mockttp } from 'mockttp'; import { setupRemoteFeatureFlagsMock } from '../../api-mocking/helpers/remoteFeatureFlagsHelper'; import { oldConfirmationsRemoteFeatureFlags } from '../../api-mocking/mock-responses/feature-flags-mocks'; import WalletView from '../../pages/wallet/WalletView'; import NetworkListModal from '../../pages/Network/NetworkListModal'; +import { LocalNode } from '../../framework/types'; +import { AnvilManager } from '../../seeder/anvil-manager'; describe(RegressionConfirmations('ERC1155 token'), () => { const ERC1155_CONTRACT = SMART_CONTRACTS.ERC1155; @@ -35,12 +40,28 @@ describe(RegressionConfirmations('ERC1155 token'), () => { dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions(['0x539']), + ) + .build(); + }, restartDevice: true, smartContracts: [ERC1155_CONTRACT], testSpecificMock, diff --git a/e2e/specs/confirmations/increase-allowance-erc20.spec.ts b/e2e/specs/confirmations/increase-allowance-erc20.spec.ts index df4d6f26eb5b..3f152c1257a9 100644 --- a/e2e/specs/confirmations/increase-allowance-erc20.spec.ts +++ b/e2e/specs/confirmations/increase-allowance-erc20.spec.ts @@ -8,13 +8,18 @@ import { SMART_CONTRACTS } from '../../../app/util/test/smart-contracts'; import ContractApprovalBottomSheet from '../../pages/Browser/ContractApprovalBottomSheet'; import Assertions from '../../framework/Assertions'; import { ActivitiesViewSelectorsText } from '../../selectors/Transactions/ActivitiesView.selectors'; -import { buildPermissions } from '../../framework/fixtures/FixtureUtils'; +import { + buildPermissions, + AnvilPort, +} from '../../framework/fixtures/FixtureUtils'; import { DappVariants } from '../../framework/Constants'; import { Mockttp } from 'mockttp'; import { setupRemoteFeatureFlagsMock } from '../../api-mocking/helpers/remoteFeatureFlagsHelper'; import { oldConfirmationsRemoteFeatureFlags } from '../../api-mocking/mock-responses/feature-flags-mocks'; import NetworkListModal from '../../pages/Network/NetworkListModal'; import WalletView from '../../pages/wallet/WalletView'; +import { LocalNode } from '../../framework/types'; +import { AnvilManager } from '../../seeder/anvil-manager'; const HST_CONTRACT = SMART_CONTRACTS.HST; @@ -34,12 +39,28 @@ describe(RegressionConfirmations('ERC20 - Increase Allowance'), () => { dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions(['0x539']), + ) + .build(); + }, restartDevice: true, smartContracts: [HST_CONTRACT], testSpecificMock, diff --git a/e2e/specs/confirmations/send-erc20-with-dapp.spec.ts b/e2e/specs/confirmations/send-erc20-with-dapp.spec.ts index ca8627c1f615..1e5899b1ddc1 100644 --- a/e2e/specs/confirmations/send-erc20-with-dapp.spec.ts +++ b/e2e/specs/confirmations/send-erc20-with-dapp.spec.ts @@ -11,11 +11,16 @@ import { ActivitiesViewSelectorsText } from '../../selectors/Transactions/Activi import TabBarComponent from '../../pages/wallet/TabBarComponent'; import TestDApp from '../../pages/Browser/TestDApp'; import Assertions from '../../framework/Assertions'; -import { buildPermissions } from '../../framework/fixtures/FixtureUtils'; +import { + buildPermissions, + AnvilPort, +} from '../../framework/fixtures/FixtureUtils'; import { DappVariants } from '../../framework/Constants'; import { Mockttp } from 'mockttp'; import { setupRemoteFeatureFlagsMock } from '../../api-mocking/helpers/remoteFeatureFlagsHelper'; import { oldConfirmationsRemoteFeatureFlags } from '../../api-mocking/mock-responses/feature-flags-mocks'; +import { LocalNode } from '../../framework/types'; +import { AnvilManager } from '../../seeder/anvil-manager'; const HST_CONTRACT = SMART_CONTRACTS.HST; @@ -35,15 +40,29 @@ describe(RegressionConfirmations('ERC20 tokens'), () => { dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withNetworkEnabledMap({ - eip155: { '0x539': true }, - }) - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withNetworkEnabledMap({ eip155: { '0x539': true } }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions(['0x539']), + ) + .build(); + }, restartDevice: true, smartContracts: [HST_CONTRACT], testSpecificMock, diff --git a/e2e/specs/confirmations/send-erc721.spec.ts b/e2e/specs/confirmations/send-erc721.spec.ts index 45b69d9808bf..6f748937c9ec 100644 --- a/e2e/specs/confirmations/send-erc721.spec.ts +++ b/e2e/specs/confirmations/send-erc721.spec.ts @@ -7,13 +7,18 @@ import { withFixtures } from '../../framework/fixtures/FixtureHelper'; import { SMART_CONTRACTS } from '../../../app/util/test/smart-contracts'; import { ActivitiesViewSelectorsText } from '../../selectors/Transactions/ActivitiesView.selectors'; import Assertions from '../../framework/Assertions'; -import { buildPermissions } from '../../framework/fixtures/FixtureUtils'; +import { + AnvilPort, + buildPermissions, +} from '../../framework/fixtures/FixtureUtils'; import { DappVariants } from '../../framework/Constants'; import { Mockttp } from 'mockttp'; import { setupRemoteFeatureFlagsMock } from '../../api-mocking/helpers/remoteFeatureFlagsHelper'; import { oldConfirmationsRemoteFeatureFlags } from '../../api-mocking/mock-responses/feature-flags-mocks'; import NetworkListModal from '../../pages/Network/NetworkListModal'; import WalletView from '../../pages/wallet/WalletView'; +import { LocalNode } from '../../framework/types'; +import { AnvilManager } from '../../seeder/anvil-manager'; describe(RegressionConfirmations('ERC721 tokens'), () => { const NFT_CONTRACT = SMART_CONTRACTS.NFTS; @@ -33,12 +38,28 @@ describe(RegressionConfirmations('ERC721 tokens'), () => { dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions(['0x539']), + ) + .build(); + }, restartDevice: true, smartContracts: [NFT_CONTRACT], testSpecificMock, diff --git a/e2e/specs/confirmations/send-failing-contract.spec.ts b/e2e/specs/confirmations/send-failing-contract.spec.ts index 9bfb6fbabe1f..6cb29d313efe 100644 --- a/e2e/specs/confirmations/send-failing-contract.spec.ts +++ b/e2e/specs/confirmations/send-failing-contract.spec.ts @@ -7,11 +7,16 @@ import { withFixtures } from '../../framework/fixtures/FixtureHelper'; import { SMART_CONTRACTS } from '../../../app/util/test/smart-contracts'; import { ActivitiesViewSelectorsText } from '../../selectors/Transactions/ActivitiesView.selectors'; import Assertions from '../../framework/Assertions'; -import { buildPermissions } from '../../framework/fixtures/FixtureUtils'; +import { + buildPermissions, + AnvilPort, +} from '../../framework/fixtures/FixtureUtils'; import { DappVariants } from '../../framework/Constants'; import { Mockttp } from 'mockttp'; import { setupRemoteFeatureFlagsMock } from '../../api-mocking/helpers/remoteFeatureFlagsHelper'; import { oldConfirmationsRemoteFeatureFlags } from '../../api-mocking/mock-responses/feature-flags-mocks'; +import { LocalNode } from '../../framework/types'; +import { AnvilManager } from '../../seeder/anvil-manager'; describe.skip(RegressionConfirmations('Failing contracts'), () => { const FAILING_CONTRACT = SMART_CONTRACTS.FAILING; @@ -31,12 +36,28 @@ describe.skip(RegressionConfirmations('Failing contracts'), () => { dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions(['0x539']), + ) + .build(); + }, restartDevice: true, smartContracts: [FAILING_CONTRACT], testSpecificMock, diff --git a/e2e/specs/confirmations/send-to-contract-address.spec.ts b/e2e/specs/confirmations/send-to-contract-address.spec.ts index 83b3a615c341..936c32f835fa 100644 --- a/e2e/specs/confirmations/send-to-contract-address.spec.ts +++ b/e2e/specs/confirmations/send-to-contract-address.spec.ts @@ -14,6 +14,9 @@ import { DappVariants } from '../../framework/Constants'; import { Mockttp } from 'mockttp'; import { setupRemoteFeatureFlagsMock } from '../../api-mocking/helpers/remoteFeatureFlagsHelper'; import { oldConfirmationsRemoteFeatureFlags } from '../../api-mocking/mock-responses/feature-flags-mocks'; +import { LocalNode } from '../../framework/types'; +import { AnvilPort } from '../../framework/fixtures/FixtureUtils'; +import { AnvilManager } from '../../seeder/anvil-manager'; const HST_CONTRACT = SMART_CONTRACTS.HST; @@ -35,7 +38,25 @@ describe.skip(RegressionConfirmations('Send to contract address'), () => { dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder().withGanacheNetwork().build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .build(); + }, restartDevice: true, smartContracts: [HST_CONTRACT], testSpecificMock, diff --git a/e2e/specs/confirmations/set-approval-for-all-erc1155.spec.ts b/e2e/specs/confirmations/set-approval-for-all-erc1155.spec.ts index cac4d31a82a8..afbff8fcf356 100644 --- a/e2e/specs/confirmations/set-approval-for-all-erc1155.spec.ts +++ b/e2e/specs/confirmations/set-approval-for-all-erc1155.spec.ts @@ -9,11 +9,16 @@ import { ActivitiesViewSelectorsText } from '../../selectors/Transactions/Activi import Assertions from '../../framework/Assertions'; import { ContractApprovalBottomSheetSelectorsText } from '../../selectors/Browser/ContractApprovalBottomSheet.selectors'; import ContractApprovalBottomSheet from '../../pages/Browser/ContractApprovalBottomSheet'; -import { buildPermissions } from '../../framework/fixtures/FixtureUtils'; +import { + AnvilPort, + buildPermissions, +} from '../../framework/fixtures/FixtureUtils'; import { DappVariants } from '../../framework/Constants'; import { Mockttp } from 'mockttp'; import { setupRemoteFeatureFlagsMock } from '../../api-mocking/helpers/remoteFeatureFlagsHelper'; import { oldConfirmationsRemoteFeatureFlags } from '../../api-mocking/mock-responses/feature-flags-mocks'; +import { LocalNode } from '../../framework/types'; +import { AnvilManager } from '../../seeder/anvil-manager'; describe.skip(RegressionConfirmations('ERC1155 token'), () => { const ERC1155_CONTRACT = SMART_CONTRACTS.ERC1155; @@ -33,12 +38,28 @@ describe.skip(RegressionConfirmations('ERC1155 token'), () => { dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions(['0x539']), + ) + .build(); + }, restartDevice: true, smartContracts: [ERC1155_CONTRACT], testSpecificMock, diff --git a/e2e/specs/confirmations/set-approve-for-all-erc721.spec.ts b/e2e/specs/confirmations/set-approve-for-all-erc721.spec.ts index 6546f787a258..a3bcf25540b6 100644 --- a/e2e/specs/confirmations/set-approve-for-all-erc721.spec.ts +++ b/e2e/specs/confirmations/set-approve-for-all-erc721.spec.ts @@ -9,13 +9,18 @@ import { ActivitiesViewSelectorsText } from '../../selectors/Transactions/Activi import Assertions from '../../framework/Assertions'; import { ContractApprovalBottomSheetSelectorsText } from '../../selectors/Browser/ContractApprovalBottomSheet.selectors'; import ContractApprovalBottomSheet from '../../pages/Browser/ContractApprovalBottomSheet'; -import { buildPermissions } from '../../framework/fixtures/FixtureUtils'; +import { + buildPermissions, + AnvilPort, +} from '../../framework/fixtures/FixtureUtils'; import { DappVariants } from '../../framework/Constants'; import { Mockttp } from 'mockttp'; import { setupRemoteFeatureFlagsMock } from '../../api-mocking/helpers/remoteFeatureFlagsHelper'; import { oldConfirmationsRemoteFeatureFlags } from '../../api-mocking/mock-responses/feature-flags-mocks'; import NetworkListModal from '../../pages/Network/NetworkListModal'; import WalletView from '../../pages/wallet/WalletView'; +import { LocalNode } from '../../framework/types'; +import { AnvilManager } from '../../seeder/anvil-manager'; describe(RegressionConfirmations('ERC721 token'), () => { const NFT_CONTRACT = SMART_CONTRACTS.NFTS; @@ -35,12 +40,28 @@ describe(RegressionConfirmations('ERC721 token'), () => { dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions(['0x539']), + ) + .build(); + }, restartDevice: true, smartContracts: [NFT_CONTRACT], testSpecificMock, diff --git a/e2e/specs/confirmations/signatures/ethereum-sign.spec.ts b/e2e/specs/confirmations/signatures/ethereum-sign.spec.ts index cb6c9a2029d8..670985e29cd4 100644 --- a/e2e/specs/confirmations/signatures/ethereum-sign.spec.ts +++ b/e2e/specs/confirmations/signatures/ethereum-sign.spec.ts @@ -6,12 +6,17 @@ import TestDApp from '../../../pages/Browser/TestDApp'; import FixtureBuilder from '../../../framework/fixtures/FixtureBuilder'; import { withFixtures } from '../../../framework/fixtures/FixtureHelper'; import Assertions from '../../../framework/Assertions'; -import { buildPermissions } from '../../../framework/fixtures/FixtureUtils'; +import { + buildPermissions, + AnvilPort, +} from '../../../framework/fixtures/FixtureUtils'; import { DappVariants } from '../../../framework/Constants'; import { RegressionConfirmations } from '../../../tags'; import { Mockttp } from 'mockttp'; import { setupRemoteFeatureFlagsMock } from '../../../api-mocking/helpers/remoteFeatureFlagsHelper'; import { oldConfirmationsRemoteFeatureFlags } from '../../../api-mocking/mock-responses/feature-flags-mocks'; +import { LocalNode } from '../../../framework/types'; +import { AnvilManager } from '../../../seeder/anvil-manager'; describe(RegressionConfirmations('Ethereum Sign'), () => { it('Sign in with Ethereum', async () => { @@ -29,12 +34,28 @@ describe(RegressionConfirmations('Ethereum Sign'), () => { dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions(['0x539']), + ) + .build(); + }, restartDevice: true, testSpecificMock, }, diff --git a/e2e/specs/confirmations/signatures/personal-sign.spec.ts b/e2e/specs/confirmations/signatures/personal-sign.spec.ts index 5ecdd968edb0..4be3ce72b229 100644 --- a/e2e/specs/confirmations/signatures/personal-sign.spec.ts +++ b/e2e/specs/confirmations/signatures/personal-sign.spec.ts @@ -6,12 +6,17 @@ import TestDApp from '../../../pages/Browser/TestDApp'; import FixtureBuilder from '../../../framework/fixtures/FixtureBuilder'; import { withFixtures } from '../../../framework/fixtures/FixtureHelper'; import Assertions from '../../../framework/Assertions'; -import { buildPermissions } from '../../../framework/fixtures/FixtureUtils'; +import { + buildPermissions, + AnvilPort, +} from '../../../framework/fixtures/FixtureUtils'; import { DappVariants } from '../../../framework/Constants'; import { Mockttp } from 'mockttp'; import { setupRemoteFeatureFlagsMock } from '../../../api-mocking/helpers/remoteFeatureFlagsHelper'; import { oldConfirmationsRemoteFeatureFlags } from '../../../api-mocking/mock-responses/feature-flags-mocks'; import { RegressionConfirmations } from '../../../tags'; +import { LocalNode } from '../../../framework/types'; +import { AnvilManager } from '../../../seeder/anvil-manager'; describe(RegressionConfirmations('Personal Sign'), () => { const testSpecificMock = async (mockServer: Mockttp) => { @@ -33,12 +38,28 @@ describe(RegressionConfirmations('Personal Sign'), () => { dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions(['0x539']), + ) + .build(); + }, restartDevice: true, testSpecificMock, }, diff --git a/e2e/specs/confirmations/signatures/typed-sign-v3.spec.ts b/e2e/specs/confirmations/signatures/typed-sign-v3.spec.ts index c1c80eaa6a3c..f8eb22d6563b 100644 --- a/e2e/specs/confirmations/signatures/typed-sign-v3.spec.ts +++ b/e2e/specs/confirmations/signatures/typed-sign-v3.spec.ts @@ -6,12 +6,17 @@ import TestDApp from '../../../pages/Browser/TestDApp'; import FixtureBuilder from '../../../framework/fixtures/FixtureBuilder'; import { withFixtures } from '../../../framework/fixtures/FixtureHelper'; import Assertions from '../../../framework/Assertions'; -import { buildPermissions } from '../../../framework/fixtures/FixtureUtils'; +import { + buildPermissions, + AnvilPort, +} from '../../../framework/fixtures/FixtureUtils'; import { DappVariants } from '../../../framework/Constants'; import { Mockttp } from 'mockttp'; import { setupRemoteFeatureFlagsMock } from '../../../api-mocking/helpers/remoteFeatureFlagsHelper'; import { oldConfirmationsRemoteFeatureFlags } from '../../../api-mocking/mock-responses/feature-flags-mocks'; import { RegressionConfirmations } from '../../../tags'; +import { LocalNode } from '../../../framework/types'; +import { AnvilManager } from '../../../seeder/anvil-manager'; describe(RegressionConfirmations('Typed Sign V3'), () => { const testSpecificMock = async (mockServer: Mockttp) => { @@ -33,12 +38,28 @@ describe(RegressionConfirmations('Typed Sign V3'), () => { dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions(['0x539']), + ) + .build(); + }, restartDevice: true, testSpecificMock, }, diff --git a/e2e/specs/confirmations/signatures/typed-sign-v4.spec.ts b/e2e/specs/confirmations/signatures/typed-sign-v4.spec.ts index f8ff058b5a65..d1a79a0c4478 100644 --- a/e2e/specs/confirmations/signatures/typed-sign-v4.spec.ts +++ b/e2e/specs/confirmations/signatures/typed-sign-v4.spec.ts @@ -6,12 +6,17 @@ import TestDApp from '../../../pages/Browser/TestDApp'; import FixtureBuilder from '../../../framework/fixtures/FixtureBuilder'; import { withFixtures } from '../../../framework/fixtures/FixtureHelper'; import Assertions from '../../../framework/Assertions'; -import { buildPermissions } from '../../../framework/fixtures/FixtureUtils'; +import { + buildPermissions, + AnvilPort, +} from '../../../framework/fixtures/FixtureUtils'; import { DappVariants } from '../../../framework/Constants'; import { Mockttp } from 'mockttp'; import { setupRemoteFeatureFlagsMock } from '../../../api-mocking/helpers/remoteFeatureFlagsHelper'; import { oldConfirmationsRemoteFeatureFlags } from '../../../api-mocking/mock-responses/feature-flags-mocks'; import { RegressionConfirmations } from '../../../tags'; +import { LocalNode } from '../../../framework/types'; +import { AnvilManager } from '../../../seeder/anvil-manager'; describe(RegressionConfirmations('Typed Sign V4'), () => { const testSpecificMock = async (mockServer: Mockttp) => { @@ -33,12 +38,28 @@ describe(RegressionConfirmations('Typed Sign V4'), () => { dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions(['0x539']), + ) + .build(); + }, restartDevice: true, testSpecificMock, }, diff --git a/e2e/specs/confirmations/signatures/typed-sign.spec.ts b/e2e/specs/confirmations/signatures/typed-sign.spec.ts index c319f26cc97d..b4f00588e383 100644 --- a/e2e/specs/confirmations/signatures/typed-sign.spec.ts +++ b/e2e/specs/confirmations/signatures/typed-sign.spec.ts @@ -6,12 +6,17 @@ import TestDApp from '../../../pages/Browser/TestDApp'; import FixtureBuilder from '../../../framework/fixtures/FixtureBuilder'; import { withFixtures } from '../../../framework/fixtures/FixtureHelper'; import Assertions from '../../../framework/Assertions'; -import { buildPermissions } from '../../../framework/fixtures/FixtureUtils'; +import { + buildPermissions, + AnvilPort, +} from '../../../framework/fixtures/FixtureUtils'; import { DappVariants } from '../../../framework/Constants'; import { Mockttp } from 'mockttp'; import { setupRemoteFeatureFlagsMock } from '../../../api-mocking/helpers/remoteFeatureFlagsHelper'; import { oldConfirmationsRemoteFeatureFlags } from '../../../api-mocking/mock-responses/feature-flags-mocks'; import { RegressionConfirmations } from '../../../tags'; +import { LocalNode } from '../../../framework/types'; +import { AnvilManager } from '../../../seeder/anvil-manager'; describe(RegressionConfirmations('Typed Sign'), () => { const testSpecificMock = async (mockServer: Mockttp) => { @@ -33,12 +38,28 @@ describe(RegressionConfirmations('Typed Sign'), () => { dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withPermissionControllerConnectedToTestDapp( + buildPermissions(['0x539']), + ) + .build(); + }, restartDevice: true, testSpecificMock, }, diff --git a/e2e/specs/predict/helpers/predict-helpers.ts b/e2e/specs/predict/helpers/predict-helpers.ts new file mode 100644 index 000000000000..371345b56681 --- /dev/null +++ b/e2e/specs/predict/helpers/predict-helpers.ts @@ -0,0 +1,28 @@ +import { createLogger, LogLevel } from '../../../framework/logger'; + +const logger = createLogger({ + name: 'PredictHelpers', + level: LogLevel.INFO, +}); + +/** + * Location coordinates for Portugal (required for Predictions, specifically when US engineers aredebugging locally) + */ +export const PORTUGAL_LOCATION = { + lat: 41.1318702, + lon: -7.798836, +}; + +export class PredictHelpers { + /** + * Sets the device location to Portugal coordinates. + * Required for Predictions feature access in e2e tests. + */ + static async setPortugalLocation() { + logger.info('[PredictHelpers] Setting device location to Portugal...'); + await device.setLocation(PORTUGAL_LOCATION.lat, PORTUGAL_LOCATION.lon); + logger.info( + '[PredictHelpers] Device location set to Portugal successfully', + ); + } +} diff --git a/e2e/specs/predict/predict-cash-out.spec.ts b/e2e/specs/predict/predict-cash-out.spec.ts index cc65f174d9f7..fd95927db53d 100644 --- a/e2e/specs/predict/predict-cash-out.spec.ts +++ b/e2e/specs/predict/predict-cash-out.spec.ts @@ -88,9 +88,9 @@ describe(SmokePredictions('Predictions'), () => { await TabBarComponent.tapActivity(); await ActivitiesView.tapOnPredictionsTab(); - // await ActivitiesView.tapCashedOutPosition(positionDetails.name); + // await ActivitiesView.tapPredictPosition(positionDetails.name); await Assertions.expectTextDisplayed('Cashed out'); - await ActivitiesView.tapCashedOutPosition(positionDetails.name); + await ActivitiesView.tapPredictPosition(positionDetails.name); await Assertions.expectElementToBeVisible( PredictActivityDetails.container, ); diff --git a/e2e/specs/predict/predict-claim-positions.spec.ts b/e2e/specs/predict/predict-claim-positions.spec.ts new file mode 100644 index 000000000000..6c36737cbe80 --- /dev/null +++ b/e2e/specs/predict/predict-claim-positions.spec.ts @@ -0,0 +1,107 @@ +import { withFixtures } from '../../framework/fixtures/FixtureHelper'; +import FixtureBuilder from '../../framework/fixtures/FixtureBuilder'; +import { SmokePredictions } from '../../tags'; +import { loginToApp } from '../../viewHelper'; +import Assertions from '../../framework/Assertions'; +import WalletView from '../../pages/wallet/WalletView'; +import { + remoteFeatureFlagPredictEnabled, + confirmationsRedesignedFeatureFlags, +} from '../../api-mocking/mock-responses/feature-flags-mocks'; +import { + POLYMARKET_COMPLETE_MOCKS, + POLYMARKET_POSITIONS_WITH_WINNINGS_MOCKS, + POLYMARKET_REMOVE_CLAIMED_POSITIONS_MOCKS, + POLYMARKET_TRANSACTION_SENTINEL_MOCKS, + POLYMARKET_UPDATE_USDC_BALANCE_MOCKS, +} from '../../api-mocking/mock-responses/polymarket/polymarket-mocks'; +import { Mockttp } from 'mockttp'; +import { setupRemoteFeatureFlagsMock } from '../../api-mocking/helpers/remoteFeatureFlagsHelper'; +import PredictClaimPage from '../../pages/Predict/PredictClaimPage'; + +import { + POLYMARKET_RESOLVED_LOST_POSITIONS_RESPONSE, + POLYMARKET_WINNING_POSITIONS_RESPONSE, +} from '../../api-mocking/mock-responses/polymarket/polymarket-positions-response'; +import { PredictHelpers } from './helpers/predict-helpers'; + +/* +Test Scenario: Claim positions + Verifies the claim flow for a predictions position: + 1. Navigate to Predictions tab and verify balance is $28.16 + 2. Verify Claim Button is visible with $20.00 claimable amount + 3. Tap Claim Button + 4. Complete claim transaction + 5. Verify balance updated to $48.16 and all resolved positions (loss positions + winning positions) are removed from the UI + */ + +const PredictionMarketFeature = async (mockServer: Mockttp) => { + await setupRemoteFeatureFlagsMock(mockServer, { + ...remoteFeatureFlagPredictEnabled(true), + ...Object.assign({}, ...confirmationsRedesignedFeatureFlags), + }); + await POLYMARKET_COMPLETE_MOCKS(mockServer); + await POLYMARKET_TRANSACTION_SENTINEL_MOCKS(mockServer); + await POLYMARKET_POSITIONS_WITH_WINNINGS_MOCKS(mockServer, true); // Include winnings for claim flow +}; +describe(SmokePredictions('Predictions'), () => { + it('should claim positions', async () => { + await withFixtures( + { + fixture: new FixtureBuilder().withPolygon().build(), + restartDevice: true, + testSpecificMock: PredictionMarketFeature, + }, + async ({ mockServer }) => { + await PredictHelpers.setPortugalLocation(); + await loginToApp(); + + // Claim button is animated - disabling sync to prevent test hang + await device.disableSynchronization(); + + await WalletView.tapOnPredictionsTab(); + + await Assertions.expectElementToBeVisible( + WalletView.PredictionsTabContainer, + ); + + await WalletView.tapClaimButton(); + await Assertions.expectElementToBeVisible(PredictClaimPage.container); + + // Set up mocks to remove claimed positions after tapping claim button + await POLYMARKET_REMOVE_CLAIMED_POSITIONS_MOCKS(mockServer); + await POLYMARKET_UPDATE_USDC_BALANCE_MOCKS(mockServer, 'claim'); + + await PredictClaimPage.tapClaimConfirmButton(); + await device.enableSynchronization(); + + await Assertions.expectElementToBeVisible(WalletView.container); + + /* + Verify that all resolved positions (lost positions + winning positions) are removed after claiming + Resolved positions include both: + 1. Lost positions (from POLYMARKET_RESOLVED_LOST_POSITIONS_RESPONSE) + 2. Winning positions (from POLYMARKET_WINNING_POSITIONS_RESPONSE) + */ + const allResolvedPositions = [ + ...POLYMARKET_RESOLVED_LOST_POSITIONS_RESPONSE, + ...POLYMARKET_WINNING_POSITIONS_RESPONSE, + ]; + + for (const position of allResolvedPositions) { + await Assertions.expectTextNotDisplayed(position.title, { + description: `Resolved position "${position.title}" should not be visible after claiming`, + }); + } + + await Assertions.expectElementToNotBeVisible(WalletView.claimButton, { + description: 'Claim button should not be visible', + }); + /* there is a bug where balances are not updating quick enough. + Leaving this commented for now. Once the bug is fixed we shoudl uncomment. + */ + // await Assertions.expectTextDisplayed('$48.16'); + }, + ); + }); +}); diff --git a/e2e/specs/quarantine/edit-recipient-address.failing.ts b/e2e/specs/quarantine/edit-recipient-address.failing.ts index 9799e20b5904..7467aca83861 100644 --- a/e2e/specs/quarantine/edit-recipient-address.failing.ts +++ b/e2e/specs/quarantine/edit-recipient-address.failing.ts @@ -11,6 +11,9 @@ import TabBarComponent from '../../pages/wallet/TabBarComponent'; import { withFixtures } from '../../framework/fixtures/FixtureHelper'; import FixtureBuilder from '../../framework/fixtures/FixtureBuilder'; import ActivitiesView from '../../pages/Transactions/ActivitiesView'; +import { LocalNode } from '../../framework/types'; +import { AnvilPort } from '../../framework/fixtures/FixtureUtils'; +import { AnvilManager } from '../../seeder/anvil-manager'; const INCORRECT_SEND_ADDRESS = '0xebe6CcB6B55e1d094d9c58980Bc10Fed69932cAb'; const CORRECT_SEND_ADDRESS = '0x37cc5ef6bfe753aeaf81f945efe88134b238face'; @@ -27,7 +30,25 @@ describe( it('should display correct send address after edit', async () => { await withFixtures( { - fixture: new FixtureBuilder().withGanacheNetwork().build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .build(); + }, restartDevice: true, }, async () => { diff --git a/e2e/specs/quarantine/security-alert-send-eth.failing.ts b/e2e/specs/quarantine/security-alert-send-eth.failing.ts index 3e3a8a079322..1fa6fb0d49c1 100644 --- a/e2e/specs/quarantine/security-alert-send-eth.failing.ts +++ b/e2e/specs/quarantine/security-alert-send-eth.failing.ts @@ -19,6 +19,9 @@ import { } from '../../api-mocking/mock-responses/security-alerts-mock'; import { setupRemoteFeatureFlagsMock } from '../../api-mocking/helpers/remoteFeatureFlagsHelper'; import { confirmationsRedesignedFeatureFlags } from '../../api-mocking/mock-responses/feature-flags-mocks'; +import { LocalNode } from '../../framework/types'; +import { AnvilPort } from '../../framework/fixtures/FixtureUtils'; +import { AnvilManager } from '../../seeder/anvil-manager'; const BENIGN_ADDRESS_MOCK = '0x50587E46C5B96a3F6f9792922EC647F13E6EFAE4'; @@ -29,7 +32,25 @@ describe(SmokeConfirmationsRedesigned('Security Alert API - Send flow'), () => { ) => { await withFixtures( { - fixture: new FixtureBuilder().withGanacheNetwork().build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .build(); + }, restartDevice: true, testSpecificMock, }, diff --git a/e2e/specs/quarantine/send-eth.failing.ts b/e2e/specs/quarantine/send-eth.failing.ts index f7a32b994399..f726acaf2189 100644 --- a/e2e/specs/quarantine/send-eth.failing.ts +++ b/e2e/specs/quarantine/send-eth.failing.ts @@ -12,6 +12,9 @@ import { withFixtures } from '../../framework/fixtures/FixtureHelper'; import { SMART_CONTRACTS } from '../../../app/util/test/smart-contracts'; import Assertions from '../../framework/Assertions'; import TokenOverview from '../../pages/wallet/TokenOverview'; +import { LocalNode } from '../../framework/types'; +import { AnvilPort } from '../../framework/fixtures/FixtureUtils'; +import { AnvilManager } from '../../seeder/anvil-manager'; // This test was migrated to the new framework but should be reworked to use withFixtures properly describe(RegressionConfirmations('Send ETH'), () => { @@ -27,7 +30,25 @@ describe(RegressionConfirmations('Send ETH'), () => { const RECIPIENT = '0x1FDb169Ef12954F20A15852980e1F0C122BfC1D6'; await withFixtures( { - fixture: new FixtureBuilder().withGanacheNetwork().build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .build(); + }, restartDevice: true, }, async () => { @@ -54,7 +75,25 @@ describe(RegressionConfirmations('Send ETH'), () => { await withFixtures( { - fixture: new FixtureBuilder().withGanacheNetwork().build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .build(); + }, restartDevice: true, smartContracts: [MULTISIG_CONTRACT], }, @@ -84,7 +123,25 @@ describe(RegressionConfirmations('Send ETH'), () => { await withFixtures( { - fixture: new FixtureBuilder().withGanacheNetwork().build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .build(); + }, restartDevice: true, }, async () => { diff --git a/e2e/specs/quarantine/swap-action-regression.failing.ts b/e2e/specs/quarantine/swap-action-regression.failing.ts index fec5dace160c..7ba186d9cf5e 100644 --- a/e2e/specs/quarantine/swap-action-regression.failing.ts +++ b/e2e/specs/quarantine/swap-action-regression.failing.ts @@ -1,5 +1,5 @@ import { withFixtures } from '../../framework/fixtures/FixtureHelper'; -import { LocalNodeType } from '../../framework/types'; +import { LocalNode, LocalNodeType } from '../../framework/types'; import FixtureBuilder from '../../framework/fixtures/FixtureBuilder'; import TabBarComponent from '../../pages/wallet/TabBarComponent'; import WalletView from '../../pages/wallet/WalletView'; @@ -11,6 +11,8 @@ import { import { loginToApp } from '../../viewHelper'; import { prepareSwapsTestEnvironment } from '../swaps/helpers/prepareSwapsTestEnvironment'; import { testSpecificMock } from '../swaps/helpers/swap-mocks'; +import { AnvilPort } from '../../framework/fixtures/FixtureUtils'; +import { AnvilManager } from '../../seeder/anvil-manager'; describe(RegressionTrade('Multiple Swaps from Actions'), (): void => { beforeEach(async (): Promise => { @@ -20,10 +22,26 @@ describe(RegressionTrade('Multiple Swaps from Actions'), (): void => { it('should complete a USDC to DAI swap from the token chart', async (): Promise => { await withFixtures( { - fixture: new FixtureBuilder() - .withGanacheNetwork('0x1') - .withDisabledSmartTransactions() - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withDisabledSmartTransactions() + .build(); + }, localNodeOptions: [ { type: LocalNodeType.anvil, diff --git a/e2e/specs/send/send-erc20-token.spec.ts b/e2e/specs/send/send-erc20-token.spec.ts index b21eaceed525..74688e9e23b5 100644 --- a/e2e/specs/send/send-erc20-token.spec.ts +++ b/e2e/specs/send/send-erc20-token.spec.ts @@ -4,9 +4,10 @@ import SendView from '../../pages/Send/RedesignedSendView'; import WalletView from '../../pages/wallet/WalletView'; import { DappVariants } from '../../framework/Constants'; import { SmokeConfirmationsRedesigned } from '../../tags'; -import { buildPermissions } from '../../framework/fixtures/FixtureUtils'; +import { AnvilPort } from '../../framework/fixtures/FixtureUtils'; import { loginToApp } from '../../viewHelper'; import { withFixtures } from '../../framework/fixtures/FixtureHelper'; +import { AnvilManager } from '../../seeder/anvil-manager'; const RECIPIENT = '0x0c54fccd2e384b4bb6f2e405bf5cbc15a017aafb'; @@ -19,32 +20,45 @@ describe(SmokeConfirmationsRedesigned('Send ERC20 asset'), () => { dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .withTokensForAllPopularNetworks([ - { - address: '0x0000000000000000000000000000000000000000', - symbol: 'ETH', - decimals: 18, - name: 'Ethereum', - }, - { - address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', - symbol: 'USDC', - decimals: 6, - name: 'USD Coin', - }, - { - address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', - symbol: 'DAI', - decimals: 18, - name: 'Dai Stablecoin', - }, - ]) - .build(), + fixture: ({ localNodes }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withTokensForAllPopularNetworks([ + { + address: '0x0000000000000000000000000000000000000000', + symbol: 'ETH', + decimals: 18, + name: 'Ethereum', + }, + { + address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', + symbol: 'USDC', + decimals: 6, + name: 'USD Coin', + }, + { + address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', + symbol: 'DAI', + decimals: 18, + name: 'Dai Stablecoin', + }, + ]) + .build(); + }, restartDevice: true, }, async () => { @@ -71,32 +85,45 @@ describe(SmokeConfirmationsRedesigned('Send ERC20 asset'), () => { dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .withTokensForAllPopularNetworks([ - { - address: '0x0000000000000000000000000000000000000000', - symbol: 'ETH', - decimals: 18, - name: 'Ethereum', - }, - { - address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', - symbol: 'USDC', - decimals: 6, - name: 'USD Coin', - }, - { - address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', - symbol: 'DAI', - decimals: 18, - name: 'Dai Stablecoin', - }, - ]) - .build(), + fixture: ({ localNodes }) => { + const node = localNodes?.[0] as unknown as { getPort?: () => number }; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withTokensForAllPopularNetworks([ + { + address: '0x0000000000000000000000000000000000000000', + symbol: 'ETH', + decimals: 18, + name: 'Ethereum', + }, + { + address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', + symbol: 'USDC', + decimals: 6, + name: 'USD Coin', + }, + { + address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', + symbol: 'DAI', + decimals: 18, + name: 'Dai Stablecoin', + }, + ]) + .build(); + }, restartDevice: true, }, async () => { @@ -123,32 +150,45 @@ describe(SmokeConfirmationsRedesigned('Send ERC20 asset'), () => { dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .withTokensForAllPopularNetworks([ - { - address: '0x0000000000000000000000000000000000000000', - symbol: 'ETH', - decimals: 18, - name: 'Ethereum', - }, - { - address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', - symbol: 'USDC', - decimals: 6, - name: 'USD Coin', - }, - { - address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', - symbol: 'DAI', - decimals: 18, - name: 'Dai Stablecoin', - }, - ]) - .build(), + fixture: ({ localNodes }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withTokensForAllPopularNetworks([ + { + address: '0x0000000000000000000000000000000000000000', + symbol: 'ETH', + decimals: 18, + name: 'Ethereum', + }, + { + address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', + symbol: 'USDC', + decimals: 6, + name: 'USD Coin', + }, + { + address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', + symbol: 'DAI', + decimals: 18, + name: 'Dai Stablecoin', + }, + ]) + .build(); + }, restartDevice: true, }, async () => { diff --git a/e2e/specs/send/send-native-token.spec.ts b/e2e/specs/send/send-native-token.spec.ts index fb9be43761c0..115c72ef581e 100644 --- a/e2e/specs/send/send-native-token.spec.ts +++ b/e2e/specs/send/send-native-token.spec.ts @@ -6,9 +6,11 @@ import WalletView from '../../pages/wallet/WalletView'; import { Assertions } from '../../framework'; import { DappVariants } from '../../framework/Constants'; import { SmokeConfirmationsRedesigned } from '../../tags'; -import { buildPermissions } from '../../framework/fixtures/FixtureUtils'; +import { AnvilPort } from '../../framework/fixtures/FixtureUtils'; import { loginToApp } from '../../viewHelper'; import { withFixtures } from '../../framework/fixtures/FixtureHelper'; +import { LocalNode } from '../../framework/types'; +import { AnvilManager } from '../../seeder/anvil-manager'; const RECIPIENT = '0x0c54fccd2e384b4bb6f2e405bf5cbc15a017aafb'; @@ -21,12 +23,25 @@ describe(SmokeConfirmationsRedesigned('Send native asset'), () => { dappVariant: DappVariants.TEST_DAPP, }, ], - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withPermissionControllerConnectedToTestDapp( - buildPermissions(['0x539']), - ) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .build(); + }, restartDevice: true, }, async () => { diff --git a/e2e/specs/settings/addressbook-send-add-contact.spec.ts b/e2e/specs/settings/addressbook-send-add-contact.spec.ts index 48fd5d16c472..e0948bfb7c4d 100644 --- a/e2e/specs/settings/addressbook-send-add-contact.spec.ts +++ b/e2e/specs/settings/addressbook-send-add-contact.spec.ts @@ -22,6 +22,9 @@ import { import { confirmationsRedesignedFeatureFlags } from '../../api-mocking/mock-responses/feature-flags-mocks'; import AddContactView from '../../pages/Settings/Contacts/AddContactView'; import DeleteContactBottomSheet from '../../pages/Settings/Contacts/DeleteContactBottomSheet'; +import { LocalNode } from '../../framework/types'; +import { AnvilPort } from '../../framework/fixtures/FixtureUtils'; +import { AnvilManager } from '../../seeder/anvil-manager'; const INVALID_ADDRESS = '0xB8B4EE5B1b693971eB60bDa15211570df2dB221L'; const MYTH_ADDRESS = '0x1FDb169Ef12954F20A15852980e1F0C122BfC1D6'; @@ -79,13 +82,29 @@ describe(RegressionWalletPlatform('Addressbook Tests'), () => { it('should add a contact via send flow and go to contacts view', async () => { await withFixtures( { - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withNetworkEnabledMap({ - eip155: { '0x539': true }, - }) - .withProfileSyncingDisabled() - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withNetworkEnabledMap({ + eip155: { '0x539': true }, + }) + .withProfileSyncingDisabled() + .build(); + }, restartDevice: true, testSpecificMock, }, @@ -118,13 +137,29 @@ describe(RegressionWalletPlatform('Addressbook Tests'), () => { it('should show invalid address error message on send flow', async () => { await withFixtures( { - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withNetworkEnabledMap({ - eip155: { '0x539': true }, - }) - .withProfileSyncingDisabled() - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withNetworkEnabledMap({ + eip155: { '0x539': true }, + }) + .withProfileSyncingDisabled() + .build(); + }, restartDevice: true, testSpecificMock, }, @@ -146,13 +181,29 @@ describe(RegressionWalletPlatform('Addressbook Tests'), () => { async () => { await withFixtures( { - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withNetworkEnabledMap({ - eip155: { '0x539': true }, - }) - .withProfileSyncingDisabled() - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withNetworkEnabledMap({ + eip155: { '0x539': true }, + }) + .withProfileSyncingDisabled() + .build(); + }, testSpecificMock, restartDevice: true, }, diff --git a/e2e/specs/settings/delete-wallet.spec.ts b/e2e/specs/settings/delete-wallet.spec.ts index e88210f9ae7f..c2cee1d3c3a9 100644 --- a/e2e/specs/settings/delete-wallet.spec.ts +++ b/e2e/specs/settings/delete-wallet.spec.ts @@ -54,13 +54,6 @@ describe( await ChangePasswordView.tapIUnderstandCheckBox(); await ChangePasswordView.tapSubmitButton(); - // bug on CI when tap wallet button makes change password continue - // github issue: https://github.com/MetaMask/metamask-mobile/issues/16758 - // TODO: remove this once the issue is fixed - if (device.getPlatform() === 'ios' && process.env.CI) { - await TabBarComponent.tapWallet(); - } - //wait for screen transitions after password change await Assertions.expectElementToNotBeVisible( ChangePasswordView.submitButton, diff --git a/e2e/specs/settings/example-anvil-e2e.spec.ts b/e2e/specs/settings/example-anvil-e2e.spec.ts index c2e1fe10c363..0d2e212c8ef3 100644 --- a/e2e/specs/settings/example-anvil-e2e.spec.ts +++ b/e2e/specs/settings/example-anvil-e2e.spec.ts @@ -7,6 +7,9 @@ import QuoteView from '../../pages/swaps/QuoteView'; import SwapView from '../../pages/swaps/SwapView'; import WalletActionsBottomSheet from '../../pages/wallet/WalletActionsBottomSheet'; import ActivitiesView from '../../pages/Transactions/ActivitiesView'; +import { LocalNode } from '../../framework/types'; +import { AnvilPort } from '../../framework/fixtures/FixtureUtils'; +import { AnvilManager } from '../../seeder/anvil-manager'; const sourceTokenSymbol = 'ETH'; const destTokenSymbol = 'DAI'; @@ -17,7 +20,26 @@ describe.skip('NFT Details page', () => { it('show nft details', async () => { await withFixtures( { - fixture: new FixtureBuilder().withGanacheNetwork().build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .build(); + }, + restartDevice: true, }, async () => { // Launch app and login diff --git a/e2e/specs/wallet/balance-privacy-toggle.spec.ts b/e2e/specs/wallet/balance-privacy-toggle.spec.ts index 08e36bb8e1d6..f4e9e4ca20b3 100644 --- a/e2e/specs/wallet/balance-privacy-toggle.spec.ts +++ b/e2e/specs/wallet/balance-privacy-toggle.spec.ts @@ -5,6 +5,9 @@ import { loginToApp } from '../../viewHelper'; import WalletView from '../../pages/wallet/WalletView'; import TabBarComponent from '../../pages/wallet/TabBarComponent'; import Assertions from '../../framework/Assertions'; +import { LocalNode } from '../../framework/types'; +import { AnvilPort } from '../../framework/fixtures/FixtureUtils'; +import { AnvilManager } from '../../seeder/anvil-manager'; const EXPECTED_HIDDEN_BALANCE: string = '••••••••••••'; @@ -16,10 +19,26 @@ describe(RegressionWalletPlatform('Balance Privacy Toggle'), (): void => { it('should toggle balance visibility when balance container is tapped', async (): Promise => { await withFixtures( { - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withETHAsPrimaryCurrency() // Set primary currency to ETH - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withETHAsPrimaryCurrency() // Set primary currency to ETH + .build(); + }, restartDevice: true, }, async (): Promise => { diff --git a/e2e/specs/wallet/send-ERC-token.spec.ts b/e2e/specs/wallet/send-ERC-token.spec.ts index 05dcd8d9f716..b68c43902613 100644 --- a/e2e/specs/wallet/send-ERC-token.spec.ts +++ b/e2e/specs/wallet/send-ERC-token.spec.ts @@ -16,6 +16,9 @@ import { setupRemoteFeatureFlagsMock } from '../../api-mocking/helpers/remoteFea import { oldConfirmationsRemoteFeatureFlags } from '../../api-mocking/mock-responses/feature-flags-mocks'; import { SMART_CONTRACTS } from '../../../app/util/test/smart-contracts'; import { Mockttp } from 'mockttp'; +import { LocalNode } from '../../framework/types'; +import { AnvilPort } from '../../framework/fixtures/FixtureUtils'; +import { AnvilManager } from '../../seeder/anvil-manager'; const SEND_ADDRESS = '0xebe6CcB6B55e1d094d9c58980Bc10Fed69932cAb'; @@ -28,12 +31,28 @@ describe(RegressionWalletPlatform('Send ERC Token'), () => { it('should send erc token successfully', async () => { await withFixtures( { - fixture: new FixtureBuilder() - .withGanacheNetwork() - .withNetworkEnabledMap({ - eip155: { '0x539': true }, - }) - .build(), + fixture: ({ localNodes }: { localNodes?: LocalNode[] }) => { + const node = localNodes?.[0] as unknown as AnvilManager; + const rpcPort = + node instanceof AnvilManager + ? (node.getPort() ?? AnvilPort()) + : undefined; + + return new FixtureBuilder() + .withNetworkController({ + providerConfig: { + chainId: '0x539', + rpcUrl: `http://localhost:${rpcPort ?? AnvilPort()}`, + type: 'custom', + nickname: 'Local RPC', + ticker: 'ETH', + }, + }) + .withNetworkEnabledMap({ + eip155: { '0x539': true }, + }) + .build(); + }, restartDevice: true, smartContracts: [SMART_CONTRACTS.HST], testSpecificMock: async (mockServer: Mockttp) => { diff --git a/package.json b/package.json index 39c673fd52a5..20577bae664f 100644 --- a/package.json +++ b/package.json @@ -244,7 +244,7 @@ "@metamask/metamask-eth-abis": "3.1.1", "@metamask/mobile-wallet-protocol-core": "^0.3.1", "@metamask/mobile-wallet-protocol-wallet-client": "^0.2.1", - "@metamask/multichain-account-service": "^2.0.0", + "@metamask/multichain-account-service": "^2.0.1", "@metamask/multichain-api-client": "^0.7.0", "@metamask/multichain-api-middleware": "1.2.4", "@metamask/multichain-network-controller": "^2.0.0", @@ -289,7 +289,7 @@ "@metamask/swaps-controller": "^15.0.0", "@metamask/token-search-discovery-controller": "^4.0.0", "@metamask/transaction-controller": "patch:@metamask/transaction-controller@npm%3A61.0.0#~/.yarn/patches/@metamask-transaction-controller-npm-61.0.0-cccac388c7.patch", - "@metamask/tron-wallet-snap": "^1.5.1", + "@metamask/tron-wallet-snap": "^1.6.1", "@metamask/utils": "^11.8.1", "@ngraveio/bc-ur": "^1.1.6", "@nktkas/hyperliquid": "^0.25.4", diff --git a/wdio/screen-objects/BridgeScreen.js b/wdio/screen-objects/BridgeScreen.js index 2f3997da6b10..3381dc86b12d 100644 --- a/wdio/screen-objects/BridgeScreen.js +++ b/wdio/screen-objects/BridgeScreen.js @@ -113,15 +113,8 @@ class BridgeScreen { else { // Try multiple iOS element selection strategies console.log(`Looking for iOS token with ID: asset-${tokenNetworkId}-${token}`); - - try { - tokenButton = await AppwrightSelectors.getElementByNameiOS(this._device, `asset-${tokenNetworkId}-${token}`); - console.log('Found token button by Name'); - } catch (error) { - console.log('Name selector failed, trying ID selector for iOS...'); - tokenButton = await AppwrightSelectors.getElementByID(this._device, `asset-${tokenNetworkId}-${token}`); - console.log('Found token button by ID'); - } + tokenButton = await AppwrightSelectors.getElementByID(this._device, `asset-${tokenNetworkId}-${token}`); + } await appwrightExpect(tokenButton).toBeVisible({ timeout: 10000 }); console.log('Token button found and visible'); diff --git a/wdio/screen-objects/SendScreen.js b/wdio/screen-objects/SendScreen.js index 61abff6e5c8e..3037ae4a4a81 100644 --- a/wdio/screen-objects/SendScreen.js +++ b/wdio/screen-objects/SendScreen.js @@ -44,7 +44,7 @@ class SendScreen { } get reviewButton() { - return AppwrightSelectors.getElementByID(this._device, 'review-button-send'); + return AppwrightSelectors.getElementByID(this._device, 'review-button'); } get sendAddressInputField() { @@ -100,13 +100,15 @@ class SendScreen { } else { console.log('Typing address in send address field'); const element = await AppwrightSelectors.getElementByCatchAll(this._device, 'Enter address to send to'); - console.log('element got found', address); await AppwrightGestures.typeText(element, address); } } async clickOnReviewButton() { - const reviewButton = await this.reviewButton; + const reviewButton = await AppwrightSelectors.getElementByID(this._device, 'review-button'); + await appwrightExpect(reviewButton).toBeVisible({timeout: 30000}); + + console.log('Review button visible, tapping'); await reviewButton.tap(); } diff --git a/yarn.lock b/yarn.lock index d4156207fbfc..85eca594b1f8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7923,9 +7923,9 @@ __metadata: languageName: node linkType: hard -"@metamask/multichain-account-service@npm:^2.0.0": - version: 2.0.0 - resolution: "@metamask/multichain-account-service@npm:2.0.0" +"@metamask/multichain-account-service@npm:^2.0.1": + version: 2.0.1 + resolution: "@metamask/multichain-account-service@npm:2.0.1" dependencies: "@ethereumjs/util": "npm:^9.1.0" "@metamask/base-controller": "npm:^9.0.0" @@ -7948,7 +7948,7 @@ __metadata: "@metamask/providers": ^22.0.0 "@metamask/snaps-controllers": ^14.0.0 webextension-polyfill: ^0.10.0 || ^0.11.0 || ^0.12.0 - checksum: 10/40e84247ca763b508b0a7db654b5b36f8062126f9323beefc56b938fe85b1cced452f474e3a9a9154a5b8dd6e00945bc4ba8a1f1a54cf09631266abdd30e1334 + checksum: 10/787f4bdb486cd32a52951edb66a384a1676086e5daab9fc4318cf353a12938aab5d297936c6bcb3face2b725a858820d569fc57c9014b8f6bcd7bc71347801d0 languageName: node linkType: hard @@ -8914,10 +8914,10 @@ __metadata: languageName: node linkType: hard -"@metamask/tron-wallet-snap@npm:^1.5.1": - version: 1.5.1 - resolution: "@metamask/tron-wallet-snap@npm:1.5.1" - checksum: 10/89bab80d3d9a6892650da1904f5312a6b0a1b07070757d911373463b8b95baa2daeeea605df7541035948bfb75621170b52d82b8c39930e914ad04b7dce9b57b +"@metamask/tron-wallet-snap@npm:^1.6.1": + version: 1.6.1 + resolution: "@metamask/tron-wallet-snap@npm:1.6.1" + checksum: 10/549f0dad4bfaee091bb5ff9bc3d5b9db124121ac77c40da67261d32f71a239cd4db0914436e0c9fb5a2eb9b82b254078d86b41dab6ba32b92359954595fc39c3 languageName: node linkType: hard @@ -34328,7 +34328,7 @@ __metadata: "@metamask/mobile-provider": "npm:^3.0.0" "@metamask/mobile-wallet-protocol-core": "npm:^0.3.1" "@metamask/mobile-wallet-protocol-wallet-client": "npm:^0.2.1" - "@metamask/multichain-account-service": "npm:^2.0.0" + "@metamask/multichain-account-service": "npm:^2.0.1" "@metamask/multichain-api-client": "npm:^0.7.0" "@metamask/multichain-api-middleware": "npm:1.2.4" "@metamask/multichain-network-controller": "npm:^2.0.0" @@ -34378,7 +34378,7 @@ __metadata: "@metamask/test-dapp-solana": "npm:^0.3.0" "@metamask/token-search-discovery-controller": "npm:^4.0.0" "@metamask/transaction-controller": "patch:@metamask/transaction-controller@npm%3A61.0.0#~/.yarn/patches/@metamask-transaction-controller-npm-61.0.0-cccac388c7.patch" - "@metamask/tron-wallet-snap": "npm:^1.5.1" + "@metamask/tron-wallet-snap": "npm:^1.6.1" "@metamask/utils": "npm:^11.8.1" "@ngraveio/bc-ur": "npm:^1.1.6" "@nktkas/hyperliquid": "npm:^0.25.4"