Skip to content

Commit 134b7f4

Browse files
test(perps): use testIDs for Close All Positions unit tests
Remove the MMDS BottomSheet mock and assert via shared selectors instead. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 4f61bc9 commit 134b7f4

3 files changed

Lines changed: 103 additions & 113 deletions

File tree

app/components/UI/Perps/Perps.testIds.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,20 @@ export const PerpsPositionsViewSelectorsIDs = {
306306
POSITIONS_SECTION_TITLE: 'perps-positions-section-title',
307307
};
308308

309+
// ========================================
310+
// PERPS CLOSE ALL POSITIONS VIEW SELECTORS
311+
// ========================================
312+
313+
export const PerpsCloseAllPositionsViewSelectorsIDs = {
314+
SHEET: 'perps-close-all-positions-sheet',
315+
TITLE: 'perps-close-all-positions-title',
316+
DESCRIPTION: 'perps-close-all-positions-description',
317+
EMPTY_STATE: 'perps-close-all-positions-empty-state',
318+
CLOSING_STATE: 'perps-close-all-positions-closing-state',
319+
KEEP_BUTTON: 'perps-close-all-positions-keep-button',
320+
CLOSE_ALL_BUTTON: 'perps-close-all-positions-close-all-button',
321+
} as const;
322+
309323
export const PerpsPositionDetailsViewSelectorsIDs = {
310324
CANDLESTICK_CHART: 'candlestick-chart',
311325
TRADINGVIEW_CHART: 'tradingview-chart',

app/components/UI/Perps/Views/PerpsCloseAllPositionsView/PerpsCloseAllPositionsView.test.tsx

Lines changed: 50 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
usePerpsRewardAccountOptedIn,
99
} from '../../hooks';
1010
import { InternalAccount } from '@metamask/keyring-internal-api';
11+
import { PerpsCloseAllPositionsViewSelectorsIDs } from '../../Perps.testIds';
1112

1213
// Mock all dependencies
1314
jest.mock('@react-navigation/native', () => ({
@@ -45,88 +46,6 @@ jest.mock('../../hooks/usePerpsEventTracking', () => ({
4546
usePerpsEventTracking: jest.fn(),
4647
}));
4748

48-
jest.mock('@metamask/design-system-react-native', () => {
49-
const MockReact = jest.requireActual('react');
50-
const { View, Text, TouchableOpacity } = jest.requireActual('react-native');
51-
const actual = jest.requireActual('@metamask/design-system-react-native');
52-
53-
const BottomSheet = MockReact.forwardRef(
54-
(
55-
{
56-
children,
57-
}: {
58-
children: React.ReactNode;
59-
},
60-
ref: React.Ref<{
61-
onOpenBottomSheet: () => void;
62-
onCloseBottomSheet: (callback?: () => void) => void;
63-
}>,
64-
) => {
65-
MockReact.useImperativeHandle(ref, () => ({
66-
onOpenBottomSheet: jest.fn(),
67-
onCloseBottomSheet: (callback?: () => void) => {
68-
callback?.();
69-
},
70-
}));
71-
72-
return <View>{children}</View>;
73-
},
74-
);
75-
BottomSheet.displayName = 'BottomSheet';
76-
77-
const BottomSheetHeader = ({ children }: { children: React.ReactNode }) => (
78-
<View>
79-
{typeof children === 'string' ? <Text>{children}</Text> : children}
80-
</View>
81-
);
82-
83-
const BottomSheetFooter = ({
84-
primaryButtonProps,
85-
secondaryButtonProps,
86-
}: {
87-
primaryButtonProps?: {
88-
children?: React.ReactNode;
89-
onPress?: () => void;
90-
isDisabled?: boolean;
91-
};
92-
secondaryButtonProps?: {
93-
children?: React.ReactNode;
94-
onPress?: () => void;
95-
isDisabled?: boolean;
96-
};
97-
}) => (
98-
<View>
99-
{secondaryButtonProps && (
100-
<TouchableOpacity
101-
onPress={secondaryButtonProps.onPress}
102-
disabled={secondaryButtonProps.isDisabled}
103-
>
104-
<Text>{secondaryButtonProps.children}</Text>
105-
</TouchableOpacity>
106-
)}
107-
{primaryButtonProps && (
108-
<TouchableOpacity
109-
onPress={primaryButtonProps.onPress}
110-
disabled={primaryButtonProps.isDisabled}
111-
>
112-
<Text>{primaryButtonProps.children}</Text>
113-
</TouchableOpacity>
114-
)}
115-
</View>
116-
);
117-
118-
return {
119-
...actual,
120-
BottomSheet,
121-
BottomSheetHeader,
122-
BottomSheetFooter,
123-
ButtonsAlignment: {
124-
Horizontal: 'Horizontal',
125-
Vertical: 'Vertical',
126-
},
127-
};
128-
});
129-
13049
jest.mock('../../components/PerpsCloseSummary', () => 'PerpsCloseSummary');
13150

13251
const mockUsePerpsLivePositions = usePerpsLivePositions as jest.MockedFunction<
@@ -235,10 +154,12 @@ describe('PerpsCloseAllPositionsView', () => {
235154
});
236155

237156
// Act
238-
const { getByText } = render(<PerpsCloseAllPositionsView />);
157+
const { getByTestId } = render(<PerpsCloseAllPositionsView />);
239158

240159
// Assert
241-
expect(getByText('perps.close_all_modal.title')).toBeOnTheScreen();
160+
expect(
161+
getByTestId(PerpsCloseAllPositionsViewSelectorsIDs.TITLE),
162+
).toBeOnTheScreen();
242163
});
243164

244165
it('renders empty state when no positions', () => {
@@ -249,19 +170,25 @@ describe('PerpsCloseAllPositionsView', () => {
249170
});
250171

251172
// Act
252-
const { getByText } = render(<PerpsCloseAllPositionsView />);
173+
const { getByTestId } = render(<PerpsCloseAllPositionsView />);
253174

254175
// Assert
255-
expect(getByText('perps.position.no_positions')).toBeOnTheScreen();
176+
expect(
177+
getByTestId(PerpsCloseAllPositionsViewSelectorsIDs.EMPTY_STATE),
178+
).toBeOnTheScreen();
256179
});
257180

258181
it('renders close all positions view with positions', () => {
259182
// Arrange & Act
260-
const { getByText } = render(<PerpsCloseAllPositionsView />);
183+
const { getByTestId } = render(<PerpsCloseAllPositionsView />);
261184

262185
// Assert
263-
expect(getByText('perps.close_all_modal.title')).toBeOnTheScreen();
264-
expect(getByText('perps.close_all_modal.description')).toBeOnTheScreen();
186+
expect(
187+
getByTestId(PerpsCloseAllPositionsViewSelectorsIDs.TITLE),
188+
).toBeOnTheScreen();
189+
expect(
190+
getByTestId(PerpsCloseAllPositionsViewSelectorsIDs.DESCRIPTION),
191+
).toBeOnTheScreen();
265192
});
266193

267194
it('renders loading state when closing', () => {
@@ -272,20 +199,25 @@ describe('PerpsCloseAllPositionsView', () => {
272199
});
273200

274201
// Act
275-
const { getAllByText } = render(<PerpsCloseAllPositionsView />);
202+
const { getByTestId } = render(<PerpsCloseAllPositionsView />);
276203

277204
// Assert
278-
const closingElements = getAllByText('perps.close_all_modal.closing');
279-
expect(closingElements.length).toBeGreaterThan(0);
205+
expect(
206+
getByTestId(PerpsCloseAllPositionsViewSelectorsIDs.CLOSING_STATE),
207+
).toBeOnTheScreen();
280208
});
281209

282210
it('displays footer buttons with correct labels', () => {
283211
// Arrange & Act
284-
const { getByText } = render(<PerpsCloseAllPositionsView />);
212+
const { getByTestId } = render(<PerpsCloseAllPositionsView />);
285213

286214
// Assert
287-
expect(getByText('perps.close_all_modal.keep_positions')).toBeOnTheScreen();
288-
expect(getByText('perps.close_all_modal.close_all')).toBeOnTheScreen();
215+
expect(
216+
getByTestId(PerpsCloseAllPositionsViewSelectorsIDs.KEEP_BUTTON),
217+
).toBeOnTheScreen();
218+
expect(
219+
getByTestId(PerpsCloseAllPositionsViewSelectorsIDs.CLOSE_ALL_BUTTON),
220+
).toBeOnTheScreen();
289221
});
290222

291223
it('shows closing label on close button when in progress', () => {
@@ -296,11 +228,15 @@ describe('PerpsCloseAllPositionsView', () => {
296228
});
297229

298230
// Act
299-
const { getAllByText } = render(<PerpsCloseAllPositionsView />);
231+
const { getByTestId } = render(<PerpsCloseAllPositionsView />);
300232

301233
// Assert
302-
const closingElements = getAllByText('perps.close_all_modal.closing');
303-
expect(closingElements.length).toBeGreaterThan(0);
234+
expect(
235+
getByTestId(PerpsCloseAllPositionsViewSelectorsIDs.CLOSE_ALL_BUTTON),
236+
).toBeOnTheScreen();
237+
expect(
238+
getByTestId(PerpsCloseAllPositionsViewSelectorsIDs.CLOSING_STATE),
239+
).toBeOnTheScreen();
304240
});
305241

306242
it('renders with empty positions gracefully', () => {
@@ -311,18 +247,22 @@ describe('PerpsCloseAllPositionsView', () => {
311247
});
312248

313249
// Act
314-
const { getByText } = render(<PerpsCloseAllPositionsView />);
250+
const { getByTestId } = render(<PerpsCloseAllPositionsView />);
315251

316252
// Assert
317-
expect(getByText('perps.position.no_positions')).toBeOnTheScreen();
253+
expect(
254+
getByTestId(PerpsCloseAllPositionsViewSelectorsIDs.EMPTY_STATE),
255+
).toBeOnTheScreen();
318256
});
319257

320258
it('renders PerpsCloseSummary when not closing', () => {
321259
// Arrange & Act
322-
const { getByText } = render(<PerpsCloseAllPositionsView />);
260+
const { getByTestId } = render(<PerpsCloseAllPositionsView />);
323261

324262
// Assert
325-
expect(getByText('perps.close_all_modal.description')).toBeOnTheScreen();
263+
expect(
264+
getByTestId(PerpsCloseAllPositionsViewSelectorsIDs.DESCRIPTION),
265+
).toBeOnTheScreen();
326266
});
327267

328268
it('calls usePerpsRewardAccountOptedIn with totalEstimatedPoints', () => {
@@ -368,10 +308,12 @@ describe('PerpsCloseAllPositionsView', () => {
368308
});
369309

370310
// Act
371-
const { getByText } = render(<PerpsCloseAllPositionsView />);
311+
const { getByTestId } = render(<PerpsCloseAllPositionsView />);
372312

373313
// Assert
374-
expect(getByText('perps.close_all_modal.description')).toBeOnTheScreen();
314+
expect(
315+
getByTestId(PerpsCloseAllPositionsViewSelectorsIDs.DESCRIPTION),
316+
).toBeOnTheScreen();
375317
expect(mockUsePerpsRewardAccountOptedIn).toHaveBeenCalled();
376318
});
377319

@@ -383,10 +325,12 @@ describe('PerpsCloseAllPositionsView', () => {
383325
});
384326

385327
// Act
386-
const { getByText } = render(<PerpsCloseAllPositionsView />);
328+
const { getByTestId } = render(<PerpsCloseAllPositionsView />);
387329

388330
// Assert
389-
expect(getByText('perps.close_all_modal.description')).toBeOnTheScreen();
331+
expect(
332+
getByTestId(PerpsCloseAllPositionsViewSelectorsIDs.DESCRIPTION),
333+
).toBeOnTheScreen();
390334
expect(mockUsePerpsRewardAccountOptedIn).toHaveBeenCalled();
391335
});
392336
});

app/components/UI/Perps/Views/PerpsCloseAllPositionsView/PerpsCloseAllPositionsView.tsx

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import {
3737
PERPS_EVENT_VALUE,
3838
type ClosePositionsResult,
3939
} from '@metamask/perps-controller';
40+
import { PerpsCloseAllPositionsViewSelectorsIDs } from '../../Perps.testIds';
4041

4142
interface PerpsCloseAllPositionsViewProps {
4243
sheetRef?: React.RefObject<BottomSheetRef | null>;
@@ -225,6 +226,7 @@ const PerpsCloseAllPositionsView: React.FC<PerpsCloseAllPositionsViewProps> = ({
225226
onPress: handleKeepButtonPress,
226227
size: ButtonSize.Lg,
227228
isDisabled: isClosing,
229+
testID: PerpsCloseAllPositionsViewSelectorsIDs.KEEP_BUTTON,
228230
}),
229231
[handleKeepButtonPress, isClosing],
230232
);
@@ -238,6 +240,7 @@ const PerpsCloseAllPositionsView: React.FC<PerpsCloseAllPositionsViewProps> = ({
238240
size: ButtonSize.Lg,
239241
isDisabled: isClosing,
240242
isDanger: true,
243+
testID: PerpsCloseAllPositionsViewSelectorsIDs.CLOSE_ALL_BUTTON,
241244
}),
242245
[handleCloseAll, isClosing],
243246
);
@@ -248,8 +251,16 @@ const PerpsCloseAllPositionsView: React.FC<PerpsCloseAllPositionsViewProps> = ({
248251
// Show loading state while fetching positions
249252
if (isInitialLoading) {
250253
return (
251-
<BottomSheet ref={sheetRef} goBack={goBack} onClose={onClose}>
252-
<BottomSheetHeader onClose={handleClose}>
254+
<BottomSheet
255+
ref={sheetRef}
256+
goBack={goBack}
257+
onClose={onClose}
258+
testID={PerpsCloseAllPositionsViewSelectorsIDs.SHEET}
259+
>
260+
<BottomSheetHeader
261+
onClose={handleClose}
262+
testID={PerpsCloseAllPositionsViewSelectorsIDs.TITLE}
263+
>
253264
{strings('perps.close_all_modal.title')}
254265
</BottomSheetHeader>
255266
<Box paddingHorizontal={4}>
@@ -267,15 +278,24 @@ const PerpsCloseAllPositionsView: React.FC<PerpsCloseAllPositionsViewProps> = ({
267278
// Show empty state if no positions
268279
if (!positions || positions.length === 0) {
269280
return (
270-
<BottomSheet ref={sheetRef} goBack={goBack} onClose={onClose}>
271-
<BottomSheetHeader onClose={handleClose}>
281+
<BottomSheet
282+
ref={sheetRef}
283+
goBack={goBack}
284+
onClose={onClose}
285+
testID={PerpsCloseAllPositionsViewSelectorsIDs.SHEET}
286+
>
287+
<BottomSheetHeader
288+
onClose={handleClose}
289+
testID={PerpsCloseAllPositionsViewSelectorsIDs.TITLE}
290+
>
272291
{strings('perps.close_all_modal.title')}
273292
</BottomSheetHeader>
274293
<Box paddingHorizontal={4}>
275294
<View style={styles.emptyContainer}>
276295
<Text
277296
variant={TextVariant.BodyMd}
278297
color={TextColor.TextAlternative}
298+
testID={PerpsCloseAllPositionsViewSelectorsIDs.EMPTY_STATE}
279299
>
280300
{strings('perps.position.no_positions')}
281301
</Text>
@@ -286,8 +306,16 @@ const PerpsCloseAllPositionsView: React.FC<PerpsCloseAllPositionsViewProps> = ({
286306
}
287307

288308
return (
289-
<BottomSheet ref={sheetRef} goBack={goBack} onClose={onClose}>
290-
<BottomSheetHeader onClose={handleClose}>
309+
<BottomSheet
310+
ref={sheetRef}
311+
goBack={goBack}
312+
onClose={onClose}
313+
testID={PerpsCloseAllPositionsViewSelectorsIDs.SHEET}
314+
>
315+
<BottomSheetHeader
316+
onClose={handleClose}
317+
testID={PerpsCloseAllPositionsViewSelectorsIDs.TITLE}
318+
>
291319
{strings('perps.close_all_modal.title')}
292320
</BottomSheetHeader>
293321

@@ -296,12 +324,16 @@ const PerpsCloseAllPositionsView: React.FC<PerpsCloseAllPositionsViewProps> = ({
296324
variant={TextVariant.BodyMd}
297325
color={TextColor.TextAlternative}
298326
style={styles.description}
327+
testID={PerpsCloseAllPositionsViewSelectorsIDs.DESCRIPTION}
299328
>
300329
{strings('perps.close_all_modal.description')}
301330
</Text>
302331

303332
{isClosing ? (
304-
<View style={styles.loadingContainer}>
333+
<View
334+
style={styles.loadingContainer}
335+
testID={PerpsCloseAllPositionsViewSelectorsIDs.CLOSING_STATE}
336+
>
305337
<ActivityIndicator
306338
size="large"
307339
color={theme.colors.primary.default}

0 commit comments

Comments
 (0)