Skip to content

Commit 17ef3b4

Browse files
authored
fix: perf test perps (MetaMask#23863)
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** Fix perps performance e2e tests. Tasks done: - Updated tests according UI changes - Remove dead code - Unified numeric keyboard component for different flows - Added a patch in appwright to set geoLocation in BrowserStack and avoid perps blocks -> from main finally <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Updates perps performance tests to new UI, adds open/close position flow, refactors numeric input via shared AmountScreen, and sets BrowserStack geoLocation to FR. > > - **Tests (performance)**: > - Add `appwright/tests/performance/login/perps-add-funds.spec.js` (add funds flow + quote timings). > - Add `appwright/tests/performance/login/perps-position-management.spec.js` (select market, set leverage, place order, close position with retry, per-device account selection). > - Remove outdated `perps-onboarding.spec.js`. > - **Screen Objects (Perps)**: > - New: `PerpsMarketDetailsView`, `PerpsOrderView` (leverage, keypad, place order), `PerpsPositionDetailsView` (close with retry, state check), `PerpsPositionsView`, `PerpsClosePositionView`. > - Update `PerpsDepositScreen`: new getters (`backButton`, `addFundsButton`, `totalText`), visibility checks, `tapBackButton`, `isAddFundsVisible`, `isTotalVisible`. > - Update `PerpsMarketListView`: header expect, `selectMarket(symbol)`. > - Update `PerpsTabView`: new tab id, add `startTrading` action, expect usage. > - **Utilities/Infra**: > - Add `selectAccountDevice` in `Flows.js` (map device to account); adjust flows usage. > - Remove `TimerHelper.withTimer` helper. > - Set BrowserStack `geoLocation: 'FR'`. > - `BridgeScreen.enterSourceTokenAmount` now delegates to `AmountScreen`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit eb2abeb. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 053257b commit 17ef3b4

15 files changed

Lines changed: 480 additions & 144 deletions
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { test } from '../../../fixtures/performance-test.js';
2+
3+
import TimerHelper from '../../../utils/TimersHelper.js';
4+
import LoginScreen from '../../../../wdio/screen-objects/LoginScreen.js';
5+
import WalletMainScreen from '../../../../wdio/screen-objects/WalletMainScreen.js';
6+
import TabBarModal from '../../../../wdio/screen-objects/Modals/TabBarModal.js';
7+
import WalletActionModal from '../../../../wdio/screen-objects/Modals/WalletActionModal.js';
8+
import PerpsTutorialScreen from '../../../../wdio/screen-objects/PerpsTutorialScreen.js';
9+
import PerpsMarketListView from '../../../../wdio/screen-objects/PerpsMarketListView.js';
10+
import PerpsTabView from '../../../../wdio/screen-objects/PerpsTabView.js';
11+
import PerpsDepositScreen from '../../../../wdio/screen-objects/PerpsDepositScreen.js';
12+
import { login } from '../../../utils/Flows.js';
13+
14+
async function screensSetup(device) {
15+
const screens = [
16+
LoginScreen,
17+
WalletMainScreen,
18+
TabBarModal,
19+
WalletActionModal,
20+
PerpsTutorialScreen,
21+
PerpsMarketListView,
22+
PerpsTabView,
23+
PerpsDepositScreen,
24+
];
25+
screens.forEach((screen) => {
26+
screen.device = device;
27+
});
28+
}
29+
30+
/* Scenario 5: Perps add funds */
31+
test('Perps add funds', async ({ device, performanceTracker }, testInfo) => {
32+
test.setTimeout(10 * 60 * 1000); // 10 minutes
33+
34+
const selectPerpsMainScreenTimer = new TimerHelper(
35+
'Select Perps Main Screen',
36+
);
37+
const openAddFundsTimer = new TimerHelper('Open Add Funds');
38+
const getQuoteTimer = new TimerHelper('Get Quote');
39+
await screensSetup(device);
40+
41+
await login(device);
42+
await TabBarModal.tapActionButton();
43+
44+
// Open Perps Main Screen
45+
selectPerpsMainScreenTimer.start();
46+
await WalletActionModal.tapPerpsButton();
47+
selectPerpsMainScreenTimer.stop();
48+
performanceTracker.addTimer(selectPerpsMainScreenTimer);
49+
50+
// Skip tutorial
51+
await PerpsTutorialScreen.tapSkip();
52+
53+
// Open Add Funds flow
54+
openAddFundsTimer.start();
55+
await PerpsTutorialScreen.tapAddFunds();
56+
await PerpsDepositScreen.isAmountInputVisible();
57+
openAddFundsTimer.stop();
58+
performanceTracker.addTimer(openAddFundsTimer);
59+
60+
// Get quote
61+
getQuoteTimer.start();
62+
await PerpsDepositScreen.fillUsdAmount(5);
63+
await PerpsDepositScreen.isAddFundsVisible();
64+
await PerpsDepositScreen.isTotalVisible();
65+
getQuoteTimer.stop();
66+
performanceTracker.addTimer(getQuoteTimer);
67+
await performanceTracker.attachToTest(testInfo);
68+
});
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import { test } from '../../../fixtures/performance-test.js';
2+
3+
import TimerHelper from '../../../utils/TimersHelper.js';
4+
import OnboardingSheet from '../../../../wdio/screen-objects/Onboarding/OnboardingSheet.js';
5+
import CreatePasswordScreen from '../../../../wdio/screen-objects/Onboarding/CreatePasswordScreen.js';
6+
import WalletMainScreen from '../../../../wdio/screen-objects/WalletMainScreen.js';
7+
import TabBarModal from '../../../../wdio/screen-objects/Modals/TabBarModal.js';
8+
import WalletActionModal from '../../../../wdio/screen-objects/Modals/WalletActionModal.js';
9+
import PerpsTutorialScreen from '../../../../wdio/screen-objects/PerpsTutorialScreen.js';
10+
import PerpsMarketListView from '../../../../wdio/screen-objects/PerpsMarketListView.js';
11+
import PerpsTabView from '../../../../wdio/screen-objects/PerpsTabView.js';
12+
import PerpsDepositScreen from '../../../../wdio/screen-objects/PerpsDepositScreen.js';
13+
import PerpsMarketDetailsView from '../../../../wdio/screen-objects/PerpsMarketDetailsView.js';
14+
import PerpsOrderView from '../../../../wdio/screen-objects/PerpsOrderView.js';
15+
import PerpsClosePositionView from '../../../../wdio/screen-objects/PerpsClosePositionView.js';
16+
import PerpsPositionDetailsView from '../../../../wdio/screen-objects/PerpsPositionDetailsView.js';
17+
import PerpsPositionsView from '../../../../wdio/screen-objects/PerpsPositionsView.js';
18+
import { login, selectAccountDevice } from '../../../utils/Flows.js';
19+
20+
async function screensSetup(device) {
21+
const screens = [
22+
OnboardingSheet,
23+
CreatePasswordScreen,
24+
WalletMainScreen,
25+
TabBarModal,
26+
WalletActionModal,
27+
PerpsTutorialScreen,
28+
PerpsMarketListView,
29+
PerpsTabView,
30+
PerpsDepositScreen,
31+
PerpsMarketDetailsView,
32+
PerpsOrderView,
33+
PerpsClosePositionView,
34+
PerpsPositionDetailsView,
35+
PerpsPositionsView,
36+
];
37+
screens.forEach((screen) => {
38+
screen.device = device;
39+
});
40+
}
41+
42+
/* Scenario 5: Perps onboarding + add funds 10 USD ARB.USDC + Open Position + Close Position */
43+
test('Perps open position and close it', async ({
44+
device,
45+
performanceTracker,
46+
}, testInfo) => {
47+
test.setTimeout(10 * 60 * 1000); // 10 minutes
48+
49+
const selectPerpsMainScreenTimer = new TimerHelper(
50+
'Select Perps Main Screen',
51+
);
52+
const skipTutorialTimer = new TimerHelper('Skip Tutorial');
53+
const selectMarketTimer = new TimerHelper('Select Market BTC');
54+
const openOrderScreenTimer = new TimerHelper('Open Order Screen');
55+
const openPositionTimer = new TimerHelper('Open Long Position');
56+
const setLeverageTimer = new TimerHelper('Set Leverage');
57+
const closePositionTimer = new TimerHelper('Close Position');
58+
await screensSetup(device);
59+
await login(device);
60+
61+
// Perps requires independent account for each device to avoid clashes when running tests in parallel
62+
await selectAccountDevice(device, testInfo);
63+
64+
await TabBarModal.tapActionButton();
65+
66+
selectPerpsMainScreenTimer.start();
67+
await WalletActionModal.tapPerpsButton();
68+
selectPerpsMainScreenTimer.stop();
69+
performanceTracker.addTimer(selectPerpsMainScreenTimer);
70+
71+
// Skip tutorial
72+
skipTutorialTimer.start();
73+
await PerpsTutorialScreen.tapSkip();
74+
skipTutorialTimer.stop();
75+
performanceTracker.addTimer(skipTutorialTimer);
76+
77+
selectMarketTimer.start();
78+
// Selecting BTC market
79+
await PerpsMarketListView.selectMarket('BTC');
80+
selectMarketTimer.stop();
81+
performanceTracker.addTimer(selectMarketTimer);
82+
83+
// TODO: Add a check to see if the position is open
84+
// If position open, fail the test
85+
if (await PerpsPositionDetailsView.isPositionOpen()) {
86+
throw new Error('Position is already open');
87+
}
88+
89+
// Open Position
90+
openOrderScreenTimer.start();
91+
await PerpsMarketDetailsView.tapLongButton();
92+
openOrderScreenTimer.stop();
93+
performanceTracker.addTimer(openOrderScreenTimer);
94+
95+
// Set leverage to 40x
96+
setLeverageTimer.start();
97+
await PerpsOrderView.setLeverage(40);
98+
setLeverageTimer.stop();
99+
performanceTracker.addTimer(setLeverageTimer);
100+
101+
openPositionTimer.start();
102+
await PerpsOrderView.tapPlaceOrder();
103+
openPositionTimer.stop();
104+
performanceTracker.addTimer(openPositionTimer);
105+
106+
// Close Position
107+
closePositionTimer.start();
108+
await PerpsPositionDetailsView.closePositionWithRetry();
109+
closePositionTimer.stop();
110+
performanceTracker.addTimer(closePositionTimer);
111+
112+
await performanceTracker.attachToTest(testInfo);
113+
});

appwright/tests/performance/onboarding/perps-onboarding.spec.js

Lines changed: 0 additions & 97 deletions
This file was deleted.

appwright/utils/Flows.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,55 @@ import AppwrightGestures from '../../e2e/framework/AppwrightGestures.js';
1919
import AppwrightSelectors from '../../e2e/framework/AppwrightSelectors.js';
2020
import { expect } from 'appwright';
2121

22+
export async function selectAccountDevice(device, testInfo) {
23+
// Access device name from testInfo.project.use.device
24+
const deviceName = testInfo.project.use.device.name;
25+
console.log(`📱 Device executing the test: ${deviceName}`);
26+
27+
let accountName;
28+
29+
// Define account mapping based on device name
30+
// The device names must match those in appwright.config.ts or device-matrix.json
31+
switch (deviceName) {
32+
case 'Samsung Galaxy S23 Ultra':
33+
accountName = 'Account 3';
34+
break;
35+
case 'Google Pixel 8 Pro':
36+
console.log(
37+
`🔄 Account 1 is selected by default in the app for device: ${deviceName}`,
38+
);
39+
return;
40+
case 'iPhone 16 Pro Max':
41+
accountName = 'Account 4';
42+
break;
43+
case 'iPhone 12':
44+
accountName = 'Account 5';
45+
break;
46+
default:
47+
console.log(
48+
`🔄 Account 1 is selected by default in the app for device: ${deviceName}`,
49+
);
50+
return;
51+
}
52+
// Account 2 is called stable and not used in this function
53+
54+
console.log(
55+
`🔄 Switching to account: ${accountName} for device: ${deviceName}`,
56+
);
57+
58+
// Set device for screen objects
59+
WalletMainScreen.device = device;
60+
AccountListComponent.device = device;
61+
62+
// Perform account switch
63+
await WalletMainScreen.tapIdenticon();
64+
await AccountListComponent.isComponentDisplayed();
65+
await AccountListComponent.tapOnAccountByName(accountName);
66+
67+
// Verify we are back on main screen (tapping account usually closes modal)
68+
await WalletMainScreen.isMainWalletViewVisible();
69+
}
70+
2271
export async function onboardingFlowImportSRP(device, srp) {
2372
WelcomeScreen.device = device;
2473
TermOfUseScreen.device = device;

appwright/utils/TimersHelper.js

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -56,22 +56,6 @@ class TimerHelper {
5656
get id() {
5757
return this._id;
5858
}
59-
60-
// Runs the provided async function while timing it, and automatically
61-
// registers the timer with the given performanceTracker.
62-
// Usage:
63-
// await TimerHelper.withTimer(performanceTracker, 'Step name', async () => { /* ... */ });
64-
static async withTimer(performanceTracker, id, fn) {
65-
const timer = new TimerHelper(id);
66-
timer.start();
67-
try {
68-
const result = await fn();
69-
return result;
70-
} finally {
71-
timer.stop();
72-
performanceTracker.addTimer(timer);
73-
}
74-
}
7559
}
7660

7761
export default TimerHelper;

e2e/framework/services/providers/browserstack/BrowserStackConfigBuilder.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ export class BrowserStackConfigBuilder {
6464
appProfiling: 'true',
6565
selfHeal: 'true',
6666
networkProfile: '4g-lte-advanced-good',
67+
geoLocation: 'FR',
6768
},
6869
'appium:autoGrantPermissions': true,
6970
'appium:app': appBsUrl,

0 commit comments

Comments
 (0)