Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
8 changes: 4 additions & 4 deletions .github/workflows/create-release-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ on:
description: 'A semantic version. eg: x.x.x'
required: true
previous-version-ref:
description: 'Previous release version reference (tag or commit hash). eg: v7.7.0'
description: 'Previous release version branch name, tag or commit hash (e.g., release/7.7.0, v7.7.0, or 76fbc500034db9779e9ff7ce637ac5be1da0493d)'
required: true
jobs:
generate-build-version:
Expand All @@ -23,15 +23,15 @@ jobs:

create-release-pr:
needs: generate-build-version
uses: MetaMask/github-tools/.github/workflows/create-release-pr.yml@75cfa5085bee4804dadaa2516a47c4ff37278b35
uses: MetaMask/github-tools/.github/workflows/create-release-pr.yml@d15d78647c5493e12cc55717504fbf10aabd05a9
with:
platform: mobile
checkout-base-branch: ${{ inputs.checkout-base-branch }}
release-pr-base-branch: ${{ inputs.release-pr-base-branch }}
semver-version: ${{ inputs.semver-version }}
previous-version-tag: ${{ inputs.previous-version-ref }}
previous-version-ref: ${{ inputs.previous-version-ref }}
mobile-build-version: ${{ needs.generate-build-version.outputs.build-version }}
github-tools-version: 75cfa5085bee4804dadaa2516a47c4ff37278b35
github-tools-version: d15d78647c5493e12cc55717504fbf10aabd05a9

secrets:
# This token needs read permissions to metamask-planning & write permissions to metamask-mobile
Expand Down
1 change: 1 addition & 0 deletions app/components/UI/Navbar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1864,6 +1864,7 @@ export function getPerpsTransactionsDetailsNavbar(navigation, title) {
const leftAction = () => navigation.pop();

return {
headerTitleAlign: 'center',
headerTitle: () => (
<NavbarTitle
style={innerStyles.perpsTransactionsTitle}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,6 @@ export const styleSheet = (params: { theme: Theme }) => {
paddingHorizontal: 16,
minHeight: 72, // Consistent height for FlashList
},
transactionIcon: {
width: 36,
height: 36,
borderRadius: 18,
},
tokenIconContainer: {
width: 36,
height: 36,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import { TouchableOpacity, View } from 'react-native';
import { PerpsMarketHeaderSelectorsIDs } from '../../../../../../e2e/selectors/Perps/Perps.selectors';
import ButtonIcon, {
ButtonIconSizes,
} from '../../../../../component-library/components/Buttons/ButtonIcon';
Expand All @@ -13,12 +14,10 @@ import Text, {
TextVariant,
} from '../../../../../component-library/components/Texts/Text';
import { useStyles } from '../../../../../component-library/hooks';
import RemoteImage from '../../../../Base/RemoteImage';
import type { PerpsMarketData } from '../../controllers/types';
import { usePerpsAssetMetadata } from '../../hooks/usePerpsAssetsMetadata';
import { styleSheet } from './PerpsMarketHeader.styles';
import { PerpsMarketHeaderSelectorsIDs } from '../../../../../../e2e/selectors/Perps/Perps.selectors';
import LivePriceHeader from '../LivePriceDisplay/LivePriceHeader';
import PerpsTokenLogo from '../PerpsTokenLogo';
import { styleSheet } from './PerpsMarketHeader.styles';

interface PerpsMarketHeaderProps {
market: PerpsMarketData;
Expand All @@ -34,7 +33,6 @@ const PerpsMarketHeader: React.FC<PerpsMarketHeaderProps> = ({
testID,
}) => {
const { styles } = useStyles(styleSheet, {});
const { assetUrl } = usePerpsAssetMetadata(market.symbol);

return (
<View style={styles.container} testID={testID}>
Expand All @@ -53,11 +51,11 @@ const PerpsMarketHeader: React.FC<PerpsMarketHeaderProps> = ({

{/* Icon Section */}
<View style={styles.perpIcon}>
{assetUrl ? (
<RemoteImage source={{ uri: assetUrl }} style={styles.tokenIcon} />
) : (
<Icon name={IconName.Coin} size={IconSize.Lg} />
)}
<PerpsTokenLogo
symbol={market.symbol}
size={40}
style={styles.tokenIcon}
/>
</View>

{/* Left Section */}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,7 @@ const styleSheet = (params: { theme: Theme }) => {
backgroundColor: colors.background.default,
},
perpIcon: {
width: 32,
height: 32,
marginRight: 16,
borderRadius: 16,
overflow: 'hidden',
backgroundColor: colors.background.alternative,
},
tokenIcon: {
width: 32,
height: 32,
borderRadius: 16,
},
leftSection: {
flexDirection: 'row',
Expand Down Expand Up @@ -61,9 +51,6 @@ const styleSheet = (params: { theme: Theme }) => {
paddingHorizontal: 4,
borderRadius: 2,
},
networkAvatar: {
marginRight: 16,
},
});
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react-native';
import PerpsMarketRowItem from './PerpsMarketRowItem';
import type { PerpsMarketData } from '../../controllers/types';
import { usePerpsAssetMetadata } from '../../hooks/usePerpsAssetsMetadata';
import { getPerpsMarketRowItemSelector } from '../../../../../../e2e/selectors/Perps/Perps.selectors';

const { TouchableOpacity } = jest.requireActual('react-native');
Expand All @@ -23,12 +22,19 @@ jest.mock('../../../../../component-library/hooks', () => ({
}),
}));

jest.mock('../../hooks/usePerpsAssetsMetadata', () => ({
usePerpsAssetMetadata: jest.fn(),
}));
const mockUsePerpsAssetMetadata = usePerpsAssetMetadata as jest.MockedFunction<
typeof usePerpsAssetMetadata
>;
// Mock PerpsTokenLogo
jest.mock('../PerpsTokenLogo', () => {
const { View } = jest.requireActual('react-native');
return function MockPerpsTokenLogo({
symbol,
testID,
}: {
symbol: string;
testID?: string;
}) {
return <View testID={testID || 'perps-token-logo'} data-symbol={symbol} />;
};
});

jest.mock('../../hooks/stream', () => ({
usePerpsLivePrices: jest.fn(() => ({})), // Return empty object - no live prices in tests
Expand All @@ -39,13 +45,6 @@ const mockUsePerpsLivePrices = usePerpsLivePrices as jest.MockedFunction<
typeof usePerpsLivePrices
>;

jest.mock('../../../../Base/RemoteImage', () => {
const { View } = jest.requireActual('react-native');
return function MockRemoteImage({ source }: { source: { uri: string } }) {
return <View testID="remote-image" data-uri={source.uri} />;
};
});

// Mock react-redux for AvatarToken component
jest.mock('react-redux', () => ({
...jest.requireActual('react-redux'),
Expand All @@ -65,11 +64,6 @@ describe('PerpsMarketRowItem', () => {

beforeEach(() => {
jest.clearAllMocks();
mockUsePerpsAssetMetadata.mockReturnValue({
assetUrl: '',
error: null,
hasError: false,
});
});

describe('Component Rendering', () => {
Expand All @@ -92,18 +86,14 @@ describe('PerpsMarketRowItem', () => {
});

describe('Asset Image Handling', () => {
it('renders RemoteImage when assetUrl is available', () => {
mockUsePerpsAssetMetadata.mockReturnValue({
assetUrl: 'https://example.com/btc.png',
error: null,
hasError: false,
});

it('renders PerpsTokenLogo component', () => {
render(<PerpsMarketRowItem market={mockMarketData} />);

const remoteImage = screen.getByTestId('remote-image');
expect(remoteImage).toBeOnTheScreen();
expect(remoteImage.props['data-uri']).toBe('https://example.com/btc.png');
const tokenLogo = screen.getByTestId(
getPerpsMarketRowItemSelector.rowItem('BTC'),
);
expect(tokenLogo).toBeOnTheScreen();
expect(tokenLogo.props['data-symbol']).toBe('BTC');
});
});

Expand Down Expand Up @@ -289,34 +279,6 @@ describe('PerpsMarketRowItem', () => {
});
});

describe('Asset Metadata Integration', () => {
it('calls usePerpsAssetMetadata with correct symbol', () => {
const customMarket = {
...mockMarketData,
symbol: 'ETH',
};

render(<PerpsMarketRowItem market={customMarket} />);

expect(mockUsePerpsAssetMetadata).toHaveBeenCalledWith('ETH');
});

it('handles different asset URLs correctly', () => {
mockUsePerpsAssetMetadata.mockReturnValue({
assetUrl: 'https://assets.metamask.io/eth.svg',
error: null,
hasError: false,
});

render(<PerpsMarketRowItem market={mockMarketData} />);

const remoteImage = screen.getByTestId('remote-image');
expect(remoteImage.props['data-uri']).toBe(
'https://assets.metamask.io/eth.svg',
);
});
});

describe('Live Price Updates', () => {
beforeEach(() => {
// Reset the mock to default empty object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,7 @@ import Text, {
} from '../../../../../component-library/components/Texts/Text';
import { PerpsMarketRowItemProps } from './PerpsMarketRowItem.types';
import styleSheet from './PerpsMarketRowItem.styles';
import Avatar, {
AvatarSize,
AvatarVariant,
} from '../../../../../component-library/components/Avatars/Avatar';
import { usePerpsAssetMetadata } from '../../hooks/usePerpsAssetsMetadata';
import RemoteImage from '../../../../Base/RemoteImage';
import PerpsTokenLogo from '../PerpsTokenLogo';
import { usePerpsLivePrices } from '../../hooks/stream';
import type { PerpsMarketData } from '../../controllers/types';
import {
Expand All @@ -26,7 +21,6 @@ import { PERPS_CONSTANTS } from '../../constants/perpsConfig';

const PerpsMarketRowItem = ({ market, onPress }: PerpsMarketRowItemProps) => {
const { styles } = useStyles(styleSheet, {});
const { assetUrl } = usePerpsAssetMetadata(market.symbol);

// Subscribe to live prices for just this symbol
const livePrices = usePerpsLivePrices({
Expand Down Expand Up @@ -103,18 +97,11 @@ const PerpsMarketRowItem = ({ market, onPress }: PerpsMarketRowItemProps) => {
<TouchableOpacity style={styles.container} onPress={handlePress}>
<View style={styles.leftSection}>
<View style={styles.perpIcon}>
{assetUrl ? (
<RemoteImage source={{ uri: assetUrl }} style={styles.tokenIcon} />
) : (
<Avatar
variant={AvatarVariant.Token}
name={displayMarket.symbol}
size={AvatarSize.Md}
testID={getPerpsMarketRowItemSelector.rowItem(
displayMarket.symbol,
)}
/>
)}
<PerpsTokenLogo
symbol={displayMarket.symbol}
size={32}
testID={getPerpsMarketRowItemSelector.rowItem(displayMarket.symbol)}
/>
</View>

<View style={styles.tokenInfo}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,6 @@ const styleSheet = (params: { theme: Theme }) => {
overflow: 'hidden',
backgroundColor: colors.background.alternative,
},
tokenIcon: {
width: 40,
height: 40,
borderRadius: 20,
},
headerLeft: {
flex: 1,
alignItems: 'flex-start',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,17 @@ import { PerpsOpenOrderCardSelectorsIDs } from '../../../../../../e2e/selectors/
import PerpsOpenOrderCard from './PerpsOpenOrderCard';
import type { Order } from '../../controllers/types';

// Mock asset metadata hook
jest.mock('../../hooks/usePerpsAssetsMetadata', () => ({
usePerpsAssetMetadata: jest.fn().mockReturnValue({
assetUrl: 'https://example.com/eth.png',
}),
}));

// Mock RemoteImage
jest.mock('../../../../Base/RemoteImage', () => ({
// Mock PerpsTokenLogo
jest.mock('../PerpsTokenLogo', () => ({
__esModule: true,
default: ({
_source,
style,
testID,
}: {
_source: unknown;
style: unknown;
testID?: string;
}) => {
default: ({ size, testID }: { size: number; testID?: string }) => {
const { View } = jest.requireActual('react-native');
return <View testID={testID || 'remote-image'} style={style} />;
return (
<View
testID={testID || 'perps-token-logo'}
style={{ width: size, height: size }}
/>
);
},
}));

Expand Down Expand Up @@ -69,13 +59,13 @@ describe('PerpsOpenOrderCard', () => {
it('renders with icon when showIcon is true', () => {
render(<PerpsOpenOrderCard order={mockOrder} showIcon />);

expect(screen.getByTestId('remote-image')).toBeOnTheScreen();
expect(screen.getByTestId('perps-token-logo')).toBeOnTheScreen();
});

it('renders without icon when showIcon is false', () => {
render(<PerpsOpenOrderCard order={mockOrder} showIcon={false} />);

expect(screen.queryByTestId('remote-image')).not.toBeOnTheScreen();
expect(screen.queryByTestId('perps-token-logo')).not.toBeOnTheScreen();
});

it('renders right accessory when provided', () => {
Expand Down Expand Up @@ -307,16 +297,11 @@ describe('PerpsOpenOrderCard', () => {
expect(screen.getByText('Market Order')).toBeOnTheScreen();
});

it('renders correctly without asset URL', () => {
const mockUsePerpsAssetMetadata = jest.requireMock(
'../../hooks/usePerpsAssetsMetadata',
).usePerpsAssetMetadata;
mockUsePerpsAssetMetadata.mockReturnValueOnce({ assetUrl: null });

it('renders correctly with PerpsTokenLogo handling asset URLs internally', () => {
render(<PerpsOpenOrderCard order={mockOrder} showIcon />);

// Should show fallback icon when no asset URL
expect(screen.queryByTestId('remote-image')).not.toBeOnTheScreen();
// Should show PerpsTokenLogo which handles asset URLs internally
expect(screen.getByTestId('perps-token-logo')).toBeOnTheScreen();
});
});

Expand Down
Loading
Loading