Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions app/components/Views/AssetDetails/AssetDetails.view.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import '../../../util/test/component-view/mocks';
import { renderAssetDetailsView } from '../../../util/test/component-view/renderers/assetDetails';
import { describeForPlatforms } from '../../../util/test/platform';

// addresses Regression: #25100 – Token Details page shows wrong network

describeForPlatforms('AssetDetails', () => {
it('displays network name from token chainId, not from selected network', () => {
const polygonTokenAddress = '0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619';

const { getAllByText, queryByText } = renderAssetDetailsView({
deterministicFiat: true,
routeParams: {
address: polygonTokenAddress,
chainId: '0x89',
asset: {
address: polygonTokenAddress,
symbol: 'WETH',
decimals: 18,
name: 'Wrapped Ether',
image: '',
isNative: false,
isETH: false,
aggregators: [],
},
},
});

// Network name should appear twice: header subtitle + "Network" section body
const polygonTexts = getAllByText('Polygon');
expect(polygonTexts.length).toBeGreaterThanOrEqual(2);

// The globally selected network (Ethereum Main Network) should NOT appear
expect(queryByText('Ethereum Main Network')).toBeNull();
});
});
17 changes: 17 additions & 0 deletions app/components/Views/WalletActions/WalletActions.view.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import '../../../util/test/component-view/mocks';
import { renderWalletActionsView } from '../../../util/test/component-view/renderers/walletActions';
import { WalletActionsBottomSheetSelectorsIDs } from './WalletActionsBottomSheet.testIds';
import { describeForPlatforms } from '../../../util/test/platform';

// Regression: #24972 – Perps missing from Trade menu when non-EVM network selected
describeForPlatforms('WalletActions', () => {
it('shows Perps button when non-EVM network is selected', () => {
const { getByTestId } = renderWalletActionsView({
isEvmSelected: false,
});

expect(
getByTestId(WalletActionsBottomSheetSelectorsIDs.PERPS_BUTTON),
).toBeOnTheScreen();
});
});
91 changes: 91 additions & 0 deletions app/util/test/component-view/presets/assetDetails.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { createStateFixture } from '../stateFixture';
import type { DeepPartial } from '../../renderWithProvider';
import type { RootState } from '../../../../reducers';

interface InitialStateAssetDetailsOptions {
deterministicFiat?: boolean;
}

export const initialStateAssetDetails = (
options?: InitialStateAssetDetailsOptions,
) => {
const builder = createStateFixture()
.withMinimalAccounts()
.withMinimalMainnetNetwork()
.withMinimalMultichainNetwork(true)
.withMinimalKeyringController()
.withMinimalTokenRates()
.withMinimalMultichainAssetsRates()
.withMinimalAnalyticsController()
.withAccountTreeForSelectedAccount()
.withRemoteFeatureFlags({})
.withOverrides({
engine: {
backgroundState: {
// Add Polygon alongside Mainnet (deepMerge preserves 0x1)
NetworkController: {
networkConfigurationsByChainId: {
'0x89': {
chainId: '0x89',
rpcEndpoints: [
{
networkClientId: 'polygon-mainnet',
url: 'https://polygon-rpc.com',
type: 'custom',
},
],
defaultRpcEndpointIndex: 0,
blockExplorerUrls: ['https://polygonscan.com'],
defaultBlockExplorerUrlIndex: 0,
name: 'Polygon',
nativeCurrency: 'POL',
},
},
networksMetadata: {
'polygon-mainnet': {
status: 'available',
EIPS: { 1559: true },
},
},
},
CurrencyRateController: {
currentCurrency: 'USD',
currencyRates: {
ETH: { conversionRate: 2000 },
POL: { conversionRate: 0.5 },
},
},
PreferencesController: {
isIpfsGatewayEnabled: false,
},
TokenBalancesController: { tokenBalances: {} },
TokensController: {
allTokens: {},
allDetectedTokens: {},
allIgnoredTokens: {},
},
},
},
settings: { primaryCurrency: 'ETH' },
} as unknown as DeepPartial<RootState>);

if (options?.deterministicFiat) {
builder.withOverrides({
engine: {
backgroundState: {
CurrencyRateController: {
currentCurrency: 'USD',
currencyRates: {
ETH: { conversionRate: 2000 },
POL: { conversionRate: 0.5 },
},
},
TokenRatesController: { marketData: {} },
MultichainAssetsRatesController: { conversionRates: {} },
},
},
} as unknown as DeepPartial<RootState>);
}

return builder;
};
92 changes: 92 additions & 0 deletions app/util/test/component-view/presets/walletActions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { createStateFixture } from '../stateFixture';
import type { DeepPartial } from '../../renderWithProvider';
import type { RootState } from '../../../../reducers';

interface InitialStateWalletActionsOptions {
isEvmSelected?: boolean;
}

export const initialStateWalletActions = (
options?: InitialStateWalletActionsOptions,
) => {
const isEvmSelected = options?.isEvmSelected ?? false;

const builder = createStateFixture()
.withMinimalAccounts()
.withMinimalMainnetNetwork()
.withMinimalMultichainNetwork(isEvmSelected)
.withOverrides({
engine: {
backgroundState: {
MultichainNetworkController: {
selectedMultichainNetworkChainId:
'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
},
},
},
} as unknown as DeepPartial<RootState>)
.withMinimalKeyringController()
.withMinimalTokenRates()
.withMinimalMultichainAssetsRates()
.withMinimalMultichainBalances()
.withMinimalMultichainAssets()
.withMinimalAnalyticsController()
.withAccountTreeForSelectedAccount()
.withRemoteFeatureFlags({
perpsPerpTradingEnabled: {
enabled: true,
minimumVersion: '1.0.0',
},
})
.withOverrides({
engine: {
backgroundState: {
PreferencesController: {
isIpfsGatewayEnabled: false,
},
TokenBalancesController: { tokenBalances: {} },
TokensController: {
allTokens: {},
allDetectedTokens: {},
allIgnoredTokens: {},
},
CurrencyRateController: {
currentCurrency: 'USD',
currencyRates: {
ETH: { conversionRate: 2000 },
},
},
EarnController: {
pooled_staking: {
isEligible: true,
},
lending: {
positions: [],
markets: [],
},
},
},
},
settings: {
basicFunctionalityEnabled: true,
primaryCurrency: 'ETH',
},
swaps: {
'0x1': { isLive: true },
hasOnboarded: false,
isLive: true,
},
fiatOrders: {
networks: [
{
active: true,
chainId: '1',
chainName: 'Ethereum Mainnet',
nativeTokenSupported: true,
},
],
},
} as unknown as DeepPartial<RootState>);

return builder;
};
40 changes: 40 additions & 0 deletions app/util/test/component-view/renderers/assetDetails.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import '../mocks';
import React from 'react';
import type { DeepPartial } from '../../renderWithProvider';
import type { RootState } from '../../../../reducers';
import { renderComponentViewScreen } from '../render';
import AssetDetailsContainer from '../../../../components/Views/AssetDetails';
import { initialStateAssetDetails } from '../presets/assetDetails';

interface RenderAssetDetailsViewOptions {
overrides?: DeepPartial<RootState>;
deterministicFiat?: boolean;
routeParams: {
address: string;
chainId: string;
asset: Record<string, unknown>;
};
}

/**
* Renders AssetDetails view with a sensible default AssetDetails preset.
* Pass overrides to tweak the state for each specific test.
*/
export function renderAssetDetailsView(
options: RenderAssetDetailsViewOptions,
): ReturnType<typeof renderComponentViewScreen> {
const { overrides, deterministicFiat, routeParams } = options;

const builder = initialStateAssetDetails({ deterministicFiat });
if (overrides) {
builder.withOverrides(overrides);
}
const state = builder.build();

return renderComponentViewScreen(
AssetDetailsContainer as unknown as React.ComponentType,
{ name: 'AssetDetails' },
{ state },
routeParams,
);
}
31 changes: 31 additions & 0 deletions app/util/test/component-view/renderers/walletActions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import '../mocks';
import React from 'react';
import type { DeepPartial } from '../../renderWithProvider';
import type { RootState } from '../../../../reducers';
import { renderComponentViewScreen } from '../render';
import Routes from '../../../../constants/navigation/Routes';
import WalletActions from '../../../../components/Views/WalletActions';
import { initialStateWalletActions } from '../presets/walletActions';

interface RenderWalletActionsViewOptions {
overrides?: DeepPartial<RootState>;
isEvmSelected?: boolean;
}

export function renderWalletActionsView(
options: RenderWalletActionsViewOptions = {},
): ReturnType<typeof renderComponentViewScreen> {
const { overrides, isEvmSelected } = options;

const builder = initialStateWalletActions({ isEvmSelected });
if (overrides) {
builder.withOverrides(overrides);
}
const state = builder.build();

return renderComponentViewScreen(
WalletActions as unknown as React.ComponentType,
{ name: Routes.MODAL.WALLET_ACTIONS },
{ state },
);
}
Loading