Skip to content

Commit 229cac5

Browse files
authored
Merge branch 'main' into fix-hardcode-remove-gns-ff
2 parents b9a7939 + 8118bf1 commit 229cac5

File tree

154 files changed

+5058
-2256
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

154 files changed

+5058
-2256
lines changed

app/components/Nav/Main/MainNavigator.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,9 @@ import {
100100
PerpsScreenStack,
101101
PerpsModalStack,
102102
PerpsTutorialCarousel,
103-
selectPerpsEnabledFlag,
104103
} from '../../UI/Perps';
105-
import {
106-
PredictScreenStack,
107-
PredictModalStack,
108-
selectPredictEnabledFlag,
109-
} from '../../UI/Predict';
104+
import { PredictScreenStack, PredictModalStack } from '../../UI/Predict';
105+
import { useFeatureFlag, FeatureFlagNames } from '../../hooks/useFeatureFlag';
110106
import { selectAssetsTrendingTokensEnabled } from '../../../selectors/featureFlagController/assetsTrendingTokens';
111107
import PerpsPositionTransactionView from '../../UI/Perps/Views/PerpsTransactionsView/PerpsPositionTransactionView';
112108
import PerpsOrderTransactionView from '../../UI/Perps/Views/PerpsTransactionsView/PerpsOrderTransactionView';
@@ -921,11 +917,15 @@ const SampleFeatureFlow = () => (
921917

922918
const MainNavigator = () => {
923919
// Get feature flag state for conditional Perps screen registration
924-
const perpsEnabledFlag = useSelector(selectPerpsEnabledFlag);
920+
const perpsEnabledFlag = useFeatureFlag(
921+
FeatureFlagNames.perpsPerpTradingEnabled,
922+
);
925923
const isEvmSelected = useSelector(selectIsEvmNetworkSelected);
926924
const isPerpsEnabled = useMemo(() => perpsEnabledFlag, [perpsEnabledFlag]);
927925
// Get feature flag state for conditional Predict screen registration
928-
const predictEnabledFlag = useSelector(selectPredictEnabledFlag);
926+
const predictEnabledFlag = useFeatureFlag(
927+
FeatureFlagNames.predictTradingEnabled,
928+
);
929929
const isPredictEnabled = useMemo(
930930
() => predictEnabledFlag,
931931
[predictEnabledFlag],

app/components/UI/Bridge/Views/BridgeView/BridgeView.styles.ts

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -26,32 +26,6 @@ export const createStyles = (params: { theme: Theme }) => {
2626
button: {
2727
width: '100%',
2828
},
29-
arrowContainer: {
30-
position: 'relative',
31-
alignItems: 'center',
32-
height: 1,
33-
backgroundColor: theme.colors.border.muted,
34-
},
35-
arrowCircle: {
36-
position: 'absolute',
37-
top: -22,
38-
backgroundColor: theme.colors.background.alternative,
39-
width: 44,
40-
height: 44,
41-
borderRadius: 22,
42-
display: 'flex',
43-
alignItems: 'center',
44-
justifyContent: 'center',
45-
},
46-
arrow: {
47-
fontSize: 20,
48-
color: theme.colors.text.default,
49-
lineHeight: 20,
50-
height: 20,
51-
includeFontPadding: false,
52-
textAlignVertical: 'center',
53-
paddingTop: 1,
54-
},
5529
quoteContainer: {
5630
flex: 1,
5731
justifyContent: 'flex-end',
@@ -77,7 +51,7 @@ export const createStyles = (params: { theme: Theme }) => {
7751
textAlign: 'center',
7852
},
7953
destTokenArea: {
80-
marginTop: 16,
54+
// marginTop: 16,
8155
},
8256
});
8357
};

app/components/UI/Bridge/Views/BridgeView/__snapshots__/BridgeView.test.tsx.snap

Lines changed: 154 additions & 72 deletions
Large diffs are not rendered by default.

app/components/UI/Bridge/Views/BridgeView/index.tsx

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import Text, {
1717
TextColor,
1818
TextVariant,
1919
} from '../../../../../component-library/components/Texts/Text';
20-
import { IconName } from '../../../../../component-library/components/Icons/Icon';
2120
import {
2221
getDecimalChainId,
2322
getNetworkImageSource,
@@ -55,9 +54,6 @@ import { strings } from '../../../../../../locales/i18n';
5554
import useSubmitBridgeTx from '../../../../../util/bridge/hooks/useSubmitBridgeTx';
5655
import Engine from '../../../../../core/Engine';
5756
import Routes from '../../../../../constants/navigation/Routes';
58-
import ButtonIcon, {
59-
ButtonIconSizes,
60-
} from '../../../../../component-library/components/Buttons/ButtonIcon';
6157
import QuoteDetailsCard from '../../components/QuoteDetailsCard';
6258
import { useBridgeQuoteRequest } from '../../hooks/useBridgeQuoteRequest';
6359
import { useBridgeQuoteData } from '../../hooks/useBridgeQuoteData';
@@ -86,6 +82,7 @@ import { isNullOrUndefined } from '@metamask/utils';
8682
import { useBridgeQuoteEvents } from '../../hooks/useBridgeQuoteEvents/index.ts';
8783
import { SwapsKeypad } from '../../components/SwapsKeypad/index.tsx';
8884
import { useGasIncluded } from '../../hooks/useGasIncluded';
85+
import { FLipQuoteButton } from '../../components/FlipQuoteButton/index.tsx';
8986

9087
export interface BridgeRouteParams {
9188
sourcePage: string;
@@ -485,7 +482,7 @@ const BridgeView = () => {
485482
// @ts-expect-error The type is incorrect, this will work
486483
<ScreenView contentContainerStyle={styles.screen}>
487484
<Box style={styles.content}>
488-
<Box style={styles.inputsContainer} gap={8}>
485+
<Box style={styles.inputsContainer}>
489486
<TokenInputArea
490487
ref={inputRef}
491488
amount={sourceAmount}
@@ -509,17 +506,10 @@ const BridgeView = () => {
509506
latestAtomicBalance={latestSourceBalance?.atomicBalance}
510507
isSourceToken
511508
/>
512-
<Box style={styles.arrowContainer}>
513-
<Box style={styles.arrowCircle}>
514-
<ButtonIcon
515-
iconName={IconName.SwapVertical}
516-
onPress={handleSwitchTokens(destTokenAmount)}
517-
disabled={!destChainId || !destToken}
518-
testID="arrow-button"
519-
size={ButtonIconSizes.Lg}
520-
/>
521-
</Box>
522-
</Box>
509+
<FLipQuoteButton
510+
onPress={handleSwitchTokens(destTokenAmount)}
511+
disabled={!destChainId || !destToken || !sourceToken}
512+
/>
523513
<TokenInputArea
524514
amount={destTokenAmount}
525515
token={destToken}
Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
import React from 'react';
2+
import { fireEvent } from '@testing-library/react-native';
3+
import { FLipQuoteButton } from './index';
4+
import renderWithProvider from '../../../../../util/test/renderWithProvider';
5+
import { initialState } from '../../_mocks_/initialState';
6+
7+
const mockOnPress = jest.fn();
8+
9+
const renderFlipQuoteButton = (disabled: boolean = false) =>
10+
renderWithProvider(
11+
<FLipQuoteButton onPress={mockOnPress} disabled={disabled} />,
12+
{
13+
state: initialState,
14+
},
15+
);
16+
17+
describe('FLipQuoteButton', () => {
18+
beforeEach(() => {
19+
jest.clearAllMocks();
20+
});
21+
22+
afterEach(() => {
23+
jest.resetAllMocks();
24+
});
25+
26+
describe('Rendering', () => {
27+
it('renders with enabled state', () => {
28+
const { toJSON, getByTestId } = renderFlipQuoteButton(false);
29+
30+
expect(getByTestId('arrow-button')).toBeTruthy();
31+
expect(toJSON()).toMatchSnapshot();
32+
});
33+
34+
it('renders with disabled state', () => {
35+
const { toJSON, getByTestId } = renderFlipQuoteButton(true);
36+
37+
expect(getByTestId('arrow-button')).toBeTruthy();
38+
expect(toJSON()).toMatchSnapshot();
39+
});
40+
41+
it('renders SwapVertical icon', () => {
42+
const { getByTestId } = renderFlipQuoteButton(false);
43+
const button = getByTestId('arrow-button');
44+
45+
expect(button).toBeTruthy();
46+
});
47+
});
48+
49+
describe('Interaction - Enabled State', () => {
50+
it('calls onPress when button is pressed and enabled', () => {
51+
const { getByTestId } = renderFlipQuoteButton(false);
52+
const button = getByTestId('arrow-button');
53+
54+
fireEvent.press(button);
55+
56+
expect(mockOnPress).toHaveBeenCalledTimes(1);
57+
});
58+
59+
it('handles onPressIn event when enabled', () => {
60+
const { getByTestId } = renderFlipQuoteButton(false);
61+
const button = getByTestId('arrow-button');
62+
63+
fireEvent(button, 'pressIn');
64+
65+
// Component should handle pressIn without errors
66+
expect(button).toBeTruthy();
67+
});
68+
69+
it('handles onPressOut event when enabled', () => {
70+
const { getByTestId } = renderFlipQuoteButton(false);
71+
const button = getByTestId('arrow-button');
72+
73+
fireEvent(button, 'pressOut');
74+
75+
// Component should handle pressOut without errors
76+
expect(button).toBeTruthy();
77+
});
78+
79+
it('handles complete press cycle with pressIn and pressOut', () => {
80+
const { getByTestId } = renderFlipQuoteButton(false);
81+
const button = getByTestId('arrow-button');
82+
83+
fireEvent(button, 'pressIn');
84+
fireEvent.press(button);
85+
fireEvent(button, 'pressOut');
86+
87+
expect(mockOnPress).toHaveBeenCalledTimes(1);
88+
});
89+
});
90+
91+
describe('Interaction - Disabled State', () => {
92+
it('sets onPress handler to undefined when disabled', () => {
93+
const { getByTestId } = renderFlipQuoteButton(true);
94+
const button = getByTestId('arrow-button');
95+
96+
expect(button.props.onPress).toBeUndefined();
97+
});
98+
99+
it('sets onPressIn handler to undefined when disabled', () => {
100+
const { getByTestId } = renderFlipQuoteButton(true);
101+
const button = getByTestId('arrow-button');
102+
103+
expect(button.props.onPressIn).toBeUndefined();
104+
});
105+
106+
it('sets onPressOut handler to undefined when disabled', () => {
107+
const { getByTestId } = renderFlipQuoteButton(true);
108+
const button = getByTestId('arrow-button');
109+
110+
expect(button.props.onPressOut).toBeUndefined();
111+
});
112+
113+
it('has disabled prop set to true when disabled', () => {
114+
const { getByTestId } = renderFlipQuoteButton(true);
115+
const button = getByTestId('arrow-button');
116+
117+
expect(button.props.disabled).toBe(true);
118+
});
119+
});
120+
121+
describe('Press State Management', () => {
122+
it('updates pressed state on pressIn', () => {
123+
const { getByTestId } = renderFlipQuoteButton(false);
124+
const button = getByTestId('arrow-button');
125+
126+
fireEvent(button, 'pressIn');
127+
128+
// Pressed state should be true, affecting the button's style
129+
expect(button).toBeTruthy();
130+
});
131+
132+
it('resets pressed state on pressOut', () => {
133+
const { getByTestId } = renderFlipQuoteButton(false);
134+
const button = getByTestId('arrow-button');
135+
136+
fireEvent(button, 'pressIn');
137+
fireEvent(button, 'pressOut');
138+
139+
// Pressed state should be false, resetting the button's style
140+
expect(button).toBeTruthy();
141+
});
142+
143+
it('maintains pressed state when transitioning from pressIn to press', () => {
144+
const { getByTestId } = renderFlipQuoteButton(false);
145+
const button = getByTestId('arrow-button');
146+
147+
fireEvent(button, 'pressIn');
148+
fireEvent.press(button);
149+
150+
expect(mockOnPress).toHaveBeenCalledTimes(1);
151+
expect(button).toBeTruthy();
152+
});
153+
});
154+
155+
describe('Accessibility', () => {
156+
it('has accessible property set to true', () => {
157+
const { getByTestId } = renderFlipQuoteButton(false);
158+
const button = getByTestId('arrow-button');
159+
160+
expect(button.props.accessible).toBe(true);
161+
});
162+
163+
it('maintains accessibility when disabled', () => {
164+
const { getByTestId } = renderFlipQuoteButton(true);
165+
const button = getByTestId('arrow-button');
166+
167+
expect(button.props.accessible).toBe(true);
168+
expect(button.props.disabled).toBe(true);
169+
});
170+
171+
it('has testID for test identification', () => {
172+
const { getByTestId } = renderFlipQuoteButton(false);
173+
174+
expect(getByTestId('arrow-button')).toBeTruthy();
175+
});
176+
});
177+
178+
describe('Edge Cases', () => {
179+
it('handles rapid successive presses when enabled', () => {
180+
const { getByTestId } = renderFlipQuoteButton(false);
181+
const button = getByTestId('arrow-button');
182+
183+
fireEvent.press(button);
184+
fireEvent.press(button);
185+
fireEvent.press(button);
186+
187+
expect(mockOnPress).toHaveBeenCalledTimes(3);
188+
});
189+
190+
it('handles pressIn without corresponding pressOut', () => {
191+
const { getByTestId } = renderFlipQuoteButton(false);
192+
const button = getByTestId('arrow-button');
193+
194+
fireEvent(button, 'pressIn');
195+
// No pressOut called
196+
197+
expect(button).toBeTruthy();
198+
});
199+
200+
it('handles pressOut without preceding pressIn', () => {
201+
const { getByTestId } = renderFlipQuoteButton(false);
202+
const button = getByTestId('arrow-button');
203+
204+
fireEvent(button, 'pressOut');
205+
206+
expect(button).toBeTruthy();
207+
});
208+
209+
it('maintains disabled state with all handlers undefined', () => {
210+
const { getByTestId } = renderFlipQuoteButton(true);
211+
const button = getByTestId('arrow-button');
212+
213+
expect(button.props.onPress).toBeUndefined();
214+
expect(button.props.onPressIn).toBeUndefined();
215+
expect(button.props.onPressOut).toBeUndefined();
216+
expect(button.props.disabled).toBe(true);
217+
});
218+
});
219+
220+
describe('Props Validation', () => {
221+
it('accepts and uses onPress callback prop', () => {
222+
const customCallback = jest.fn();
223+
const { getByTestId } = renderWithProvider(
224+
<FLipQuoteButton onPress={customCallback} disabled={false} />,
225+
{ state: initialState },
226+
);
227+
228+
const button = getByTestId('arrow-button');
229+
fireEvent.press(button);
230+
231+
expect(customCallback).toHaveBeenCalledTimes(1);
232+
});
233+
234+
it('respects disabled prop set to false', () => {
235+
const { getByTestId } = renderFlipQuoteButton(false);
236+
const button = getByTestId('arrow-button');
237+
238+
fireEvent.press(button);
239+
240+
expect(mockOnPress).toHaveBeenCalled();
241+
});
242+
243+
it('respects disabled prop set to true', () => {
244+
const { getByTestId } = renderFlipQuoteButton(true);
245+
const button = getByTestId('arrow-button');
246+
247+
expect(button.props.disabled).toBe(true);
248+
expect(button.props.onPress).toBeUndefined();
249+
});
250+
});
251+
});

0 commit comments

Comments
 (0)