Skip to content

Commit

Permalink
test: Add Stake e2e automation (#13180)
Browse files Browse the repository at this point in the history
<!--
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**

These are the Stake flows this PR will automate:

- Stake
- Unstake
- Stake more
- Claim
- Making sure staking balance, banners, and actions are hidden for ETH
assets that aren't on mainnet or holesky

To run  them locally  follow these steps:
- Build the app locally and make sure you set the following ENV
variables:
          `export MM_MULTICHAIN_V1_ENABLED="true"`
          `export MM_CHAIN_PERMISSIONS="true"`
          `export MM_PERMISSIONS_SETTINGS_V1_ENABLED="false"`
          `export PORTFOLIO_VIEW="true"`
          `export MM_SECURITY_ALERTS_API_ENABLED="true"`
          `export MM_NETWORK_UI_REDESIGN_ENABLED= "false"`
          
    and run `yarn test:e2e:android:debug:build`

- Run the following command ` yarn test:e2e:android:debug:run
e2e/specs/stake/stake-action-smoke.spec.js`
## **Related issues**

Fixes:

## **Manual testing steps**

1. Go to this page...
2.
3.

## **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.
  • Loading branch information
davibroc authored Feb 6, 2025
1 parent 1937f9a commit 832a4f9
Show file tree
Hide file tree
Showing 23 changed files with 519 additions and 50 deletions.
32 changes: 22 additions & 10 deletions app/components/Base/StatusText.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { StyleSheet } from 'react-native';
import { FIAT_ORDER_STATES } from '../../constants/on-ramp';
import { strings } from '../../../locales/i18n';
import { useTheme } from '../../util/theme';
import { CommonSelectorsIDs } from '../../../e2e/selectors/Common.selectors';

const styles = StyleSheet.create({
status: {
Expand All @@ -15,43 +14,55 @@ const styles = StyleSheet.create({
},
});

export const ConfirmedText = (props) => (
export const ConfirmedText = ({testID, ...props}) => (
<Text
testID={CommonSelectorsIDs.TRANSACTION_STATUS}
testID={testID}
bold
green
style={styles.status}
{...props}
/>
);
export const PendingText = (props) => {
ConfirmedText.propTypes = {
testID: PropTypes.string,
};

export const PendingText = ({testID, ...props}) => {
const { colors } = useTheme();
return (
<Text
testID={testID}
bold
style={[styles.status, { color: colors.warning.default }]}
{...props}
/>
);
};
export const FailedText = (props) => {
PendingText.propTypes = {
testID: PropTypes.string,
};

export const FailedText = ({testID, ...props} ) => {
const { colors } = useTheme();
return (
<Text
testID={CommonSelectorsIDs.TRANSACTION_STATUS}
testID={testID}
bold
style={[styles.status, { color: colors.error.default }]}
{...props}
/>
);
};
FailedText.propTypes = {
testID: PropTypes.string,
};

function StatusText({ status, context, ...props }) {
function StatusText({ status, context, testID, ...props }) {
switch (status) {
case 'Confirmed':
case 'confirmed':
return (
<ConfirmedText {...props}>
<ConfirmedText testID={testID} {...props}>
{strings(`${context}.${status}`)}
</ConfirmedText>
);
Expand All @@ -60,14 +71,14 @@ function StatusText({ status, context, ...props }) {
case 'Submitted':
case 'submitted':
return (
<PendingText {...props}>{strings(`${context}.${status}`)}</PendingText>
<PendingText testID={testID} {...props}>{strings(`${context}.${status}`)}</PendingText>
);
case 'Failed':
case 'Cancelled':
case 'failed':
case 'cancelled':
return (
<FailedText {...props}>{strings(`${context}.${status}`)}</FailedText>
<FailedText testID={testID} {...props}>{strings(`${context}.${status}`)}</FailedText>
);

case FIAT_ORDER_STATES.COMPLETED:
Expand Down Expand Up @@ -103,6 +114,7 @@ StatusText.defaultProps = {
StatusText.propTypes = {
status: PropTypes.string.isRequired,
context: PropTypes.string,
testID: PropTypes.string,
};

export default StatusText;
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ const StakingBalanceContent = ({ asset }: StakingBalanceProps) => {
<NetworkMainAssetLogo style={styles.ethLogo} />
)}
</BadgeWrapper>
<Text style={styles.balances} variant={TextVariant.BodyLGMedium}>
<Text style={styles.balances} variant={TextVariant.BodyLGMedium} testID="staked-ethereum-label">
{strings('stake.staked_ethereum')}
</Text>
</AssetElement>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ const UnstakingBanner = ({
variant={BannerVariant.Alert}
style={style}
description={
<Text>{renderUnstakingTimeRemaining(timeRemaining, amountEth)}</Text>
<Text testID="unstaking-banner">
{renderUnstakingTimeRemaining(timeRemaining, amountEth)}
</Text>
}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,15 @@ const StakingButtons = ({
<View style={[styles.balanceButtonsContainer, style]}>
{hasEthToUnstake && (
<Button
testID={'unstake-button'}
style={styles.balanceActionButton}
variant={ButtonVariants.Secondary}
label={strings('stake.unstake')}
onPress={onUnstakePress}
/>
)}
<Button
testID={'stake-more-button'}
style={styles.balanceActionButton}
variant={ButtonVariants.Secondary}
label={
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ exports[`StakingBalance render matches snapshot 1`] = `
"marginLeft": 20,
}
}
testID="staked-ethereum-label"
>
Staked Ethereum
</Text>
Expand Down Expand Up @@ -263,6 +264,7 @@ exports[`StakingBalance render matches snapshot 1`] = `
"lineHeight": 22,
}
}
testID="unstaking-banner"
>
Unstaking 0.0010 ETH in progress. Come back in a few days to claim it.
</Text>
Expand Down Expand Up @@ -404,6 +406,7 @@ exports[`StakingBalance render matches snapshot 1`] = `
"paddingHorizontal": 16,
}
}
testID="unstake-button"
>
<Text
accessibilityRole="text"
Expand Down Expand Up @@ -443,6 +446,7 @@ exports[`StakingBalance render matches snapshot 1`] = `
"paddingHorizontal": 16,
}
}
testID="stake-more-button"
>
<Text
accessibilityRole="text"
Expand Down Expand Up @@ -653,6 +657,7 @@ exports[`StakingBalance should match the snapshot when portfolio view is enabled
"marginLeft": 20,
}
}
testID="staked-ethereum-label"
>
Staked Ethereum
</Text>
Expand Down Expand Up @@ -728,6 +733,7 @@ exports[`StakingBalance should match the snapshot when portfolio view is enabled
"lineHeight": 22,
}
}
testID="unstaking-banner"
>
Unstaking 0.0010 ETH in progress. Come back in a few days to claim it.
</Text>
Expand Down Expand Up @@ -869,6 +875,7 @@ exports[`StakingBalance should match the snapshot when portfolio view is enabled
"paddingHorizontal": 16,
}
}
testID="unstake-button"
>
<Text
accessibilityRole="text"
Expand Down Expand Up @@ -908,6 +915,7 @@ exports[`StakingBalance should match the snapshot when portfolio view is enabled
"paddingHorizontal": 16,
}
}
testID="stake-more-button"
>
<Text
accessibilityRole="text"
Expand Down
3 changes: 2 additions & 1 deletion app/components/UI/TransactionElement/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@ class TransactionElement extends PureComponent {
chainId,
isQRHardwareAccount,
isLedgerAccount,
i,
tx: { time, status, isSmartTransaction },
} = this.props;
const { colors, typography } = this.context || mockTheme;
Expand Down Expand Up @@ -344,7 +345,7 @@ class TransactionElement extends PureComponent {
<ListItem.Title numberOfLines={1} style={styles.listItemTitle}>
{actionKey}
</ListItem.Title>
<StatusText status={status} style={styles.listItemStatus} />
<StatusText testID={`transaction-status-${i}`} status={status} style={styles.listItemStatus} />
</ListItem.Body>
{Boolean(value) && (
<ListItem.Amounts>
Expand Down
18 changes: 18 additions & 0 deletions bitrise.yml
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ stages:
- run_tag_smoke_ramps_android: {}
- run_tag_smoke_swaps_ios: {}
- run_tag_smoke_swaps_android: {}
- run_tag_smoke_stake_ios: {}
- run_tag_smoke_stake_android: {}
- run_tag_smoke_core_ios: {}
- run_tag_smoke_core_android: {}
- run_tag_multichain_permissions_ios: {}
Expand Down Expand Up @@ -674,6 +676,22 @@ workflows:
- TEST_SUITE_TAG: '.*SmokeSwaps.*'
after_run:
- android_e2e_test
run_tag_smoke_stake_ios:
envs:
- TEST_SUITE_FOLDER: './e2e/specs/stake/*'
- TEST_SUITE_TAG: '.*SmokeStake.*'
after_run:
- ios_e2e_test
run_tag_smoke_stake_android:
meta:
bitrise.io:
stack: linux-docker-android-22.04
machine_type_id: elite-xl
envs:
- TEST_SUITE_FOLDER: './e2e/specs/stake/*'
- TEST_SUITE_TAG: '.*SmokeStake.*'
after_run:
- android_e2e_test
run_ios_api_specs:
after_run:
- ios_api_specs
Expand Down
15 changes: 15 additions & 0 deletions e2e/pages/Stake/StakeConfirmView.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Gestures from '../../utils/Gestures.js';
import Matchers from '../../utils/Matchers.js';
import { StakeConfirmViewSelectors } from '../../selectors/Stake/StakeConfirmView.selectors.js';

class StakeConfirmationView {
get confirmButton() {
return Matchers.getElementByText(StakeConfirmViewSelectors.CONFIRM);
}

async tapConfirmButton() {
await Gestures.waitAndTap(this.confirmButton);
}
}

export default new StakeConfirmationView();
45 changes: 45 additions & 0 deletions e2e/pages/Stake/StakeView.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { StakeViewSelectors } from '../../selectors/Stake/StakeView.selectors.js';

import Matchers from '../../utils/Matchers';
import Gestures from '../../utils/Gestures';

class StakeView {
get stakeContainer() {
return Matchers.getElementByText(StakeViewSelectors.STAKE_CONTAINER);
}

get unstakeContainer() {
return Matchers.getElementByText(StakeViewSelectors.UNSTAKE_CONTAINER);
}

get reviewButton() {
return Matchers.getElementByText(StakeViewSelectors.REVIEW_BUTTON);
}

get continueButton() {
return Matchers.getElementByText(StakeViewSelectors.CONTINUE);
}

async selectAmount(amount) {
const amountButton = await Matchers.getElementByText(amount);
await Gestures.waitAndTap(amountButton);
}

async enterAmount(amount) {
for (let idx = 0; idx < amount.length; idx++) {
const element = Matchers.getElementByText(amount[idx]);
await Gestures.waitAndTap(element);
}
}

async tapReview() {
await Gestures.waitAndTap(this.reviewButton);
}

async tapContinue() {
await Gestures.waitAndTap(this.continueButton);
}

}

export default new StakeView();
30 changes: 17 additions & 13 deletions e2e/pages/Transactions/ActivitiesView.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,8 @@ import {
} from '../../selectors/Transactions/ActivitiesView.selectors';
import Matchers from '../../utils/Matchers';
import Gestures from '../../utils/Gestures';
import { CommonSelectorsIDs } from '../../selectors/Common.selectors';

class ActivitiesView {
static FIRST_ROW = 0;
static SECOND_ROW = 1;

get title() {
return Matchers.getElementByText(ActivitiesViewSelectorsText.TITLE);
Expand All @@ -22,18 +19,25 @@ class ActivitiesView {
return Matchers.getElementByText(ActivitiesViewSelectorsText.CONFIRM_TEXT);
}

get firstTransactionStatus() {
return Matchers.getElementByID(
CommonSelectorsIDs.TRANSACTION_STATUS,
ActivitiesView.FIRST_ROW,
);
get stakeDepositedLabel() {
return Matchers.getElementByText(ActivitiesViewSelectorsText.STAKE_DEPOSIT);
}

get secondTransactionStatus() {
return Matchers.getElementByID(
CommonSelectorsIDs.TRANSACTION_STATUS,
ActivitiesView.SECOND_ROW,
);
get stakeMoreDepositedLabel() {
return Matchers.getElementByText(ActivitiesViewSelectorsText.STAKE_DEPOSIT, 0);
}

get unstakeLabel() {
return Matchers.getElementByText(ActivitiesViewSelectorsText.UNSTAKE);
}

get stackingClaimLabel() {
return Matchers.getElementByText(ActivitiesViewSelectorsText.STAKING_CLAIM);
}


transactionStatus(row) {
return Matchers.getElementByID(`transaction-status-${row}`);
}

generateSwapActivityLabel(sourceToken, destinationToken) {
Expand Down
Loading

0 comments on commit 832a4f9

Please sign in to comment.