Skip to content

Commit 3bf2cf9

Browse files
authored
test: add assertions to claim activity view (#22075)
<!-- 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** This PR adds assertions to claim flow ## **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] > Adds mocks to surface REDEEM activity after claiming and updates e2e to verify activity details, amounts, and balance refresh. > > - **Mocks (Polymarket)**: > - Add `POLYMARKET_CLAIMED_POSITIONS_ACTIVITY_RESPONSE` and new helper `POLYMARKET_ADD_CLAIMED_POSITIONS_TO_ACTIVITY_MOCKS` to prepend `REDEEM` transactions to `activity`. > - Wire new activity mock into claim flow; keep resolved positions empty post-claim and refresh USDC balance. > - **E2E Tests**: > - Update `predict-claim-positions.spec.ts` to verify claim button disappears, navigate to Activity → Predictions, open each claimed item, and assert formatted amounts; verify wallet balance on iOS. > - Adjust synchronization handling and mock sequencing in the claim flow. > - **Page Objects**: > - Add `amountDisplay` getter to `predictionsActivityDetails` for asserting displayed amounts. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit d77f5ec. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 0c80dc9 commit 3bf2cf9

File tree

4 files changed

+157
-15
lines changed

4 files changed

+157
-15
lines changed

e2e/api-mocking/mock-responses/polymarket/polymarket-activity-response.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,3 +345,56 @@ export const POLYMARKET_ACTIVITY_RESPONSE = [
345345
profileImageOptimized: '',
346346
},
347347
];
348+
349+
export const POLYMARKET_CLAIMED_POSITIONS_ACTIVITY_RESPONSE = [
350+
{
351+
proxyWallet: PROXY_WALLET_ADDRESS,
352+
timestamp: 1762189059,
353+
conditionId:
354+
'0xbf97a1420a810787dc6ffa2810f1d1d91977267e542b8685ecd21e622567a46c',
355+
type: 'REDEEM',
356+
size: 15,
357+
usdcSize: 15,
358+
transactionHash:
359+
'0x205120808686f9164ca306404e6221cd0fda524002587a410bebdff3f7d3858c',
360+
price: 0,
361+
asset: '',
362+
side: '',
363+
outcomeIndex: 999,
364+
title: 'Blue Jays vs. Mariners',
365+
slug: 'mlb-tor-sea-2025-10-17',
366+
icon: 'https://polymarket-upload.s3.us-east-2.amazonaws.com/Repetitive-markets/MLB.jpg',
367+
eventSlug: 'mlb-tor-sea-2025-10-17',
368+
outcome: '',
369+
name: 'cropMaster',
370+
pseudonym: 'Nonstop-Suitcase',
371+
bio: '',
372+
profileImage: '',
373+
profileImageOptimized: '',
374+
},
375+
{
376+
proxyWallet: PROXY_WALLET_ADDRESS,
377+
timestamp: 1762189060,
378+
conditionId:
379+
'0xa13312b2cc64532aed2a446b66e5a2d8d8b440b24d7213d33b6dae6a58c33223',
380+
type: 'REDEEM',
381+
size: 5,
382+
usdcSize: 5,
383+
transactionHash:
384+
'0x205120808686f9164ca306404e6221cd0fda524002587a410bebdff3f7d3858d',
385+
price: 0,
386+
asset: '',
387+
side: '',
388+
outcomeIndex: 999,
389+
title: 'Steelers vs. Bengals',
390+
slug: 'nfl-pit-cin-2025-10-16',
391+
icon: 'https://polymarket-upload.s3.us-east-2.amazonaws.com/nfl.png',
392+
eventSlug: 'nfl-pit-cin-2025-10-16',
393+
outcome: '',
394+
name: 'cropMaster',
395+
pseudonym: 'Nonstop-Suitcase',
396+
bio: '',
397+
profileImage: '',
398+
profileImageOptimized: '',
399+
},
400+
];

e2e/api-mocking/mock-responses/polymarket/polymarket-mocks.ts

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ import {
1414
POLYMARKET_EVENT_DETAILS_SPURS_PELICANS_RESPONSE,
1515
} from './polymarket-event-details-response';
1616
import { POLYMARKET_UPNL_RESPONSE } from './polymarket-upnl-response';
17-
import { POLYMARKET_ACTIVITY_RESPONSE } from './polymarket-activity-response';
17+
import {
18+
POLYMARKET_ACTIVITY_RESPONSE,
19+
POLYMARKET_CLAIMED_POSITIONS_ACTIVITY_RESPONSE,
20+
} from './polymarket-activity-response';
1821
import {
1922
POLYMARKET_ORDER_BOOK_RESPONSE,
2023
POLYMARKET_ZOHRAN_ORDER_BOOK_RESPONSE,
@@ -985,6 +988,60 @@ export const POLYMARKET_REMOVE_CLAIMED_POSITIONS_MOCKS = async (
985988
}));
986989
};
987990

991+
/**
992+
* Post-claim mock that adds REDEEM transactions to the activity endpoint
993+
* After claiming, REDEEM type transactions should appear in the activity feed
994+
* @param mockServer - The mockttp server instance
995+
*/
996+
export const POLYMARKET_ADD_CLAIMED_POSITIONS_TO_ACTIVITY_MOCKS = async (
997+
mockServer: Mockttp,
998+
) => {
999+
// Override the activity mock to include REDEEM transactions for claimed positions
1000+
await mockServer
1001+
.forGet('/proxy')
1002+
.matching((request) => {
1003+
const url = new URL(request.url).searchParams.get('url');
1004+
return Boolean(
1005+
url &&
1006+
/^https:\/\/data-api\.polymarket\.com\/activity\?user=0x[a-fA-F0-9]{40}$/.test(
1007+
url,
1008+
),
1009+
);
1010+
})
1011+
.asPriority(PRIORITY.API_OVERRIDE) // Higher priority to override the original activity mock
1012+
.thenCallback((request) => {
1013+
const url = new URL(request.url).searchParams.get('url');
1014+
const userMatch = url?.match(/user=(0x[a-fA-F0-9]{40})/);
1015+
const userAddress = userMatch ? userMatch[1] : USER_WALLET_ADDRESS;
1016+
1017+
// Map claimed positions to use the actual user address
1018+
const claimedPositionsWithUserAddress =
1019+
POLYMARKET_CLAIMED_POSITIONS_ACTIVITY_RESPONSE.map((activity) => ({
1020+
...activity,
1021+
proxyWallet: userAddress,
1022+
}));
1023+
1024+
// Map existing activity to use the actual user address
1025+
const existingActivityWithUserAddress = POLYMARKET_ACTIVITY_RESPONSE.map(
1026+
(activity) => ({
1027+
...activity,
1028+
proxyWallet: userAddress,
1029+
}),
1030+
);
1031+
1032+
// Add the REDEEM transactions at the beginning of the activity array (most recent first)
1033+
const activityWithClaims = [
1034+
...claimedPositionsWithUserAddress,
1035+
...existingActivityWithUserAddress,
1036+
];
1037+
1038+
return {
1039+
statusCode: 200,
1040+
json: activityWithClaims,
1041+
};
1042+
});
1043+
};
1044+
9881045
/**
9891046
* Post-cash-out mock that removes the cashed out position from positions endpoint
9901047
* and adds a SELL transaction to the activity endpoint

e2e/pages/Transactions/predictionsActivityDetails.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ class PredictActivityDetails {
1515
);
1616
}
1717

18+
get amountDisplay(): DetoxElement {
19+
return Matchers.getElementByID(
20+
PredictActivityDetailsSelectorsIDs.AMOUNT_DISPLAY,
21+
);
22+
}
23+
1824
async tapBackButton(): Promise<void> {
1925
await Gestures.waitAndTap(this.backButton);
2026
}

e2e/specs/predict/predict-claim-positions.spec.ts

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,20 @@ import {
1414
POLYMARKET_REMOVE_CLAIMED_POSITIONS_MOCKS,
1515
POLYMARKET_TRANSACTION_SENTINEL_MOCKS,
1616
POLYMARKET_UPDATE_USDC_BALANCE_MOCKS,
17+
POLYMARKET_ADD_CLAIMED_POSITIONS_TO_ACTIVITY_MOCKS,
1718
} from '../../api-mocking/mock-responses/polymarket/polymarket-mocks';
1819
import { Mockttp } from 'mockttp';
1920
import { setupRemoteFeatureFlagsMock } from '../../api-mocking/helpers/remoteFeatureFlagsHelper';
2021
import PredictClaimPage from '../../pages/Predict/PredictClaimPage';
21-
22+
import TabBarComponent from '../../pages/wallet/TabBarComponent';
23+
import ActivitiesView from '../../pages/Transactions/ActivitiesView';
24+
import PredictActivityDetails from '../../pages/Transactions/predictionsActivityDetails';
2225
import {
2326
POLYMARKET_RESOLVED_LOST_POSITIONS_RESPONSE,
2427
POLYMARKET_WINNING_POSITIONS_RESPONSE,
2528
} from '../../api-mocking/mock-responses/polymarket/polymarket-positions-response';
2629
import { PredictHelpers } from './helpers/predict-helpers';
30+
import { POLYMARKET_CLAIMED_POSITIONS_ACTIVITY_RESPONSE } from '../../api-mocking/mock-responses/polymarket/polymarket-activity-response';
2731

2832
/*
2933
Test Scenario: Claim positions
@@ -56,7 +60,7 @@ describe(SmokePredictions('Predictions'), () => {
5660
await PredictHelpers.setPortugalLocation();
5761
await loginToApp();
5862

59-
// Claim button is animated - disabling sync to prevent test hang
63+
// Claim button is animated - disabling sync on iOS to prevent test hang
6064
await device.disableSynchronization();
6165

6266
await WalletView.tapOnPredictionsTab();
@@ -68,15 +72,18 @@ describe(SmokePredictions('Predictions'), () => {
6872
await WalletView.tapClaimButton();
6973
await Assertions.expectElementToBeVisible(PredictClaimPage.container);
7074

71-
// Set up mocks to remove claimed positions after tapping claim button
72-
await POLYMARKET_REMOVE_CLAIMED_POSITIONS_MOCKS(mockServer);
73-
await POLYMARKET_UPDATE_USDC_BALANCE_MOCKS(mockServer, 'claim');
74-
7575
await PredictClaimPage.tapClaimConfirmButton();
76-
await device.enableSynchronization();
76+
77+
await POLYMARKET_UPDATE_USDC_BALANCE_MOCKS(mockServer, 'claim');
78+
await POLYMARKET_REMOVE_CLAIMED_POSITIONS_MOCKS(mockServer);
79+
await POLYMARKET_ADD_CLAIMED_POSITIONS_TO_ACTIVITY_MOCKS(mockServer);
7780

7881
await Assertions.expectElementToBeVisible(WalletView.container);
82+
await device.enableSynchronization();
7983

84+
await Assertions.expectElementToNotBeVisible(WalletView.claimButton, {
85+
description: 'Claim button should not be visible',
86+
});
8087
/*
8188
Verify that all resolved positions (lost positions + winning positions) are removed after claiming
8289
Resolved positions include both:
@@ -94,13 +101,32 @@ describe(SmokePredictions('Predictions'), () => {
94101
});
95102
}
96103

97-
await Assertions.expectElementToNotBeVisible(WalletView.claimButton, {
98-
description: 'Claim button should not be visible',
99-
});
100-
/* there is a bug where balances are not updating quick enough.
101-
Leaving this commented for now. Once the bug is fixed we shoudl uncomment.
102-
*/
103-
// await Assertions.expectTextDisplayed('$48.16');
104+
await TabBarComponent.tapActivity();
105+
106+
await ActivitiesView.tapOnPredictionsTab();
107+
108+
for (const position of POLYMARKET_CLAIMED_POSITIONS_ACTIVITY_RESPONSE) {
109+
await ActivitiesView.tapPredictPosition(position.title);
110+
await Assertions.expectElementToBeVisible(
111+
PredictActivityDetails.container,
112+
{
113+
description: `Activity details should be visible for "${position.title}"`,
114+
},
115+
);
116+
// Verify the balance is displayed correctly (formatted as $XX.XX)
117+
const expectedBalance = `$${position.usdcSize.toFixed(2)}`;
118+
await Assertions.expectTextDisplayed(expectedBalance, {
119+
description: `Balance should be displayed as "${expectedBalance}" for "${position.title}"`,
120+
});
121+
await PredictActivityDetails.tapBackButton();
122+
}
123+
124+
await TabBarComponent.tapWallet();
125+
126+
// Verify balance on iOS only. Android balances take a while to refresh.
127+
if (device.getPlatform() === 'ios') {
128+
await Assertions.expectTextDisplayed('$48.16');
129+
}
104130
},
105131
);
106132
});

0 commit comments

Comments
 (0)