From d8f60f8af2a02cc4cc3aeab046b8faa86eaeb947 Mon Sep 17 00:00:00 2001 From: eunjisong Date: Fri, 18 Oct 2024 10:57:14 -0400 Subject: [PATCH 1/2] QA - new: Test StakeCard and StakeDetail screens with data --- .../EarnScreenStack/EarnScreenStack.tsx | 2 + .../app/screens/earn/StakeDetails.tsx | 6 +- .../app/screens/earn/components/StakeCard.tsx | 27 ++-- .../screens/earn/components/StatusChip.tsx | 8 +- .../core-mobile/e2e/helpers/assertions.ts | 5 +- .../e2e/locators/Stake/stakeScreen.loc.ts | 13 +- .../core-mobile/e2e/pages/Stake/stake.page.ts | 127 +++++++++++++++++- .../tests/browser/suggestedBrowsers.e2e.ts | 51 ++++++- .../notification/sendNotification.e2e.ts | 36 ----- .../e2e/tests/stake/stakingMainnet.e2e.ts | 33 ++++- 10 files changed, 250 insertions(+), 58 deletions(-) delete mode 100644 packages/core-mobile/e2e/tests/notification/sendNotification.e2e.ts diff --git a/packages/core-mobile/app/navigation/wallet/EarnScreenStack/EarnScreenStack.tsx b/packages/core-mobile/app/navigation/wallet/EarnScreenStack/EarnScreenStack.tsx index 095004ce8b..5281579794 100644 --- a/packages/core-mobile/app/navigation/wallet/EarnScreenStack/EarnScreenStack.tsx +++ b/packages/core-mobile/app/navigation/wallet/EarnScreenStack/EarnScreenStack.tsx @@ -10,6 +10,7 @@ import { FeeUnavailableModal } from 'screens/earn/FeeUnavailableModal' import * as Navigation from 'utils/Navigation' import { noop } from '@avalabs/core-utils-sdk' import { FundsStuckModal } from 'screens/earn/FundsStuckModal' +import { MainHeaderOptions } from 'navigation/NavUtils' import StakeSetupScreenStack, { StakeSetupStackParamList } from './StakeSetupScreenStack' @@ -58,6 +59,7 @@ function EarnScreenStack(): JSX.Element { { // eslint-disable-next-line react/no-unstable-nested-components headerRight: () => ( - + ) }) @@ -67,7 +67,9 @@ const StakeDetails = (): JSX.Element | null => { - Stake #{stakeTitle} + + Stake #{stakeTitle} + { fromUnixTime(props.endTimestamp || 0) ) return ( - + {remainingTime} remaining ) } case StakeStatus.Completed: - return + return ( + + ) } } @@ -117,7 +122,7 @@ export const StakeCard = (props: Props): JSX.Element => { Staked Amount - + {stakeAmountInAvax?.toDisplay() ?? '-'} AVAX {stakeAmountInCurrency} @@ -132,7 +137,9 @@ export const StakeCard = (props: Props): JSX.Element => { Estimated Rewards - + {estimatedRewardInAvax?.toDisplay() ?? '-'} AVAX {estimatedRewardInCurrency} @@ -168,7 +175,7 @@ export const StakeCard = (props: Props): JSX.Element => { Amount Staked - + {stakeAmountInAvax?.toDisplay() ?? '-'} AVAX {stakeAmountInCurrency} @@ -185,7 +192,9 @@ export const StakeCard = (props: Props): JSX.Element => { Earned Rewards - + {rewardAmountInAvax?.toDisplay() ?? '-'} AVAX {rewardAmountInCurrency} @@ -201,7 +210,7 @@ export const StakeCard = (props: Props): JSX.Element => { textStyle={{ lineHeight: 20 }}> End Date - {endDate} + {endDate} ) @@ -220,7 +229,9 @@ export const StakeCard = (props: Props): JSX.Element => { - {'Stake #' + title} + + {'Stake #' + title} + {renderStatus()} diff --git a/packages/core-mobile/app/screens/earn/components/StatusChip.tsx b/packages/core-mobile/app/screens/earn/components/StatusChip.tsx index 693e30cb4c..fd6df025f7 100644 --- a/packages/core-mobile/app/screens/earn/components/StatusChip.tsx +++ b/packages/core-mobile/app/screens/earn/components/StatusChip.tsx @@ -9,22 +9,24 @@ import { StakeStatus } from 'types/earn' type Props = { status: StakeStatus + testID?: string } -export const StatusChip = ({ status }: Props) => { +export const StatusChip: React.FC = ({ status, testID }) => { const { theme } = useApplicationContext() - const renderLabel = (label: string) => ( + const renderLabel = (label: string): JSX.Element => ( <> {label} ) - const renderContent = () => { + const renderContent = (): JSX.Element => { if (status === StakeStatus.Completed) return ( <> diff --git a/packages/core-mobile/e2e/helpers/assertions.ts b/packages/core-mobile/e2e/helpers/assertions.ts index 38f71f8b6a..761f2bf639 100644 --- a/packages/core-mobile/e2e/helpers/assertions.ts +++ b/packages/core-mobile/e2e/helpers/assertions.ts @@ -50,9 +50,10 @@ const count = async (item: Detox.NativeMatcher, value: number) => { const hasPartialText = async ( item: Detox.NativeMatcher, - expectedText: string + expectedText: string, + index = 0 ) => { - const attri = await element(item).getAttributes() + const attri = await element(item).atIndex(index).getAttributes() if (!('elements' in attri)) { assert( attri.text?.toString().includes(expectedText), diff --git a/packages/core-mobile/e2e/locators/Stake/stakeScreen.loc.ts b/packages/core-mobile/e2e/locators/Stake/stakeScreen.loc.ts index 62c0ce9822..edbb56a9ae 100644 --- a/packages/core-mobile/e2e/locators/Stake/stakeScreen.loc.ts +++ b/packages/core-mobile/e2e/locators/Stake/stakeScreen.loc.ts @@ -50,5 +50,16 @@ export default { twentyFivePercentText: '25%', fiftyPercentText: '50%', maxText: 'Max', - stakeClaimButton: 'stake_claim_btn' + stakeClaimButton: 'stake_claim_btn', + stakeCardTitle: 'stake_card_title', + stakeDetailsTitle: 'stake_details_title', + completedStatusChip: 'Completed_status_chip', + activeStatusChip: 'Ongoing_status_chip', + timeRemaining: 'Time Remaining', + transactionIdText: 'Transaction ID', + estimatedRewardsId: 'estimated_rewards', + timeRemainingId: 'time_remaining', + stakedAmountId: 'staked_amount', + endDateId: 'end_date', + earnedRewardsId: 'earned_rewards' } diff --git a/packages/core-mobile/e2e/pages/Stake/stake.page.ts b/packages/core-mobile/e2e/pages/Stake/stake.page.ts index 69fffe5742..c44232d1f5 100644 --- a/packages/core-mobile/e2e/pages/Stake/stake.page.ts +++ b/packages/core-mobile/e2e/pages/Stake/stake.page.ts @@ -3,6 +3,13 @@ import Assert from '../../helpers/assertions' import Actions from '../../helpers/actions' import { Platform } from '../../helpers/constants' +type StakeCard = { + title: string + rewards: string + amount: string + time: string +} + class StakePage { get activeTab() { return by.text(stakeScreenLoc.activeTab) @@ -152,6 +159,10 @@ class StakePage { return by.text(stakeScreenLoc.newStakeTimeRemaining) } + get timeRemaining() { + return by.text(stakeScreenLoc.timeRemaining) + } + get nextButton() { return by.id(stakeScreenLoc.nextButton) } @@ -208,6 +219,46 @@ class StakePage { return by.text(stakeScreenLoc.maxText) } + get stakeCardTitle() { + return by.id(stakeScreenLoc.stakeCardTitle) + } + + get stakeDetailsTitle() { + return by.id(stakeScreenLoc.stakeDetailsTitle) + } + + get completedStatusChip() { + return by.id(stakeScreenLoc.completedStatusChip) + } + + get activeStatusChip() { + return by.id(stakeScreenLoc.activeStatusChip) + } + + get transactionIdText() { + return by.text(stakeScreenLoc.transactionIdText) + } + + get estimatedRewardsId() { + return by.id(stakeScreenLoc.estimatedRewardsId) + } + + get timeRemainingId() { + return by.id(stakeScreenLoc.timeRemainingId) + } + + get stakedAmountId() { + return by.id(stakeScreenLoc.stakedAmountId) + } + + get endDateId() { + return by.id(stakeScreenLoc.endDateId) + } + + get earnedRewardsId() { + return by.id(stakeScreenLoc.earnedRewardsId) + } + async tapActiveTab() { await Actions.tap(this.activeTab) } @@ -333,20 +384,65 @@ class StakePage { return availableBalance } + async tapStakeCard() { + await Actions.tapElementAtIndex(this.stakeCardTitle, 0) + } + async verifyHistoryTabItems() { + await Actions.waitForElement(this.stakeCardTitle, 10000) await Assert.isVisible(this.amountStakedText) await Assert.isVisible(this.earnedRewardsText) await Assert.isVisible(this.endDateText) - await Assert.isVisible(this.firstStakeText) - //Add more items with testID's (date, amount, rewards, icons) + await Assert.isVisible(this.completedStatusChip) + await Assert.hasPartialText(this.stakeCardTitle, 'Stake #') + await Assert.isVisible(this.endDateId) + await Assert.isVisible(this.earnedRewardsId) + await Assert.isVisible(this.stakedAmountId) + } + + async verifyActiveStakeDetails(stakeCardInfo: StakeCard) { + // Verify the stake detail static text + await Actions.waitForElement(this.stakeDetailsTitle, 10000) + await Assert.isVisible(this.stakedAmountText) + await Assert.isVisible(this.estimatedRewardsText) + await Assert.isVisible(this.estimatedRewardsTooltip) + await Assert.isVisible(this.activeStatusChip) + // Verify the active stake detail data + const { title, rewards, amount, time } = stakeCardInfo + await Assert.isVisible(by.text(title)) + await Assert.isVisible(by.text(rewards)) + await Assert.isVisible(by.text(amount)) + await Assert.isVisible(by.text(time)) + } + + async verifyCompletedStakeDetails(stakeCardInfo: StakeCard) { + // Verify the stake detail static text + await Actions.waitForElement(this.stakeDetailsTitle, 10000) + await Assert.isVisible(this.stakedAmountText) + await Assert.isVisible(this.earnedRewardsText) + await Assert.isVisible(this.transactionIdText) + await Assert.isVisible(this.endDateText) + await Assert.isVisible(this.completedStatusChip) + + // Verify the completed stake detail data + const { title, rewards, amount, time } = stakeCardInfo + await Assert.isVisible(by.text(title)) + await Assert.isVisible(by.text(rewards)) + await Assert.isVisible(by.text(amount)) + await Assert.isVisible(by.text(time)) } async verifyActiveTabItems() { + await Actions.waitForElement(this.stakeCardTitle, 10000) await Assert.isVisible(this.stakedAmountText) await Assert.isVisible(this.estimatedRewardsText) await Assert.isVisible(this.estimatedRewardsTooltip) - await Assert.isVisible(this.firstStakeText) - //Add more items with testID's (date, amount, rewards) + await Assert.hasPartialText(this.stakeCardTitle, 'Stake #') + await Assert.isNotVisible(this.completedStatusChip) + await Assert.isNotVisible(this.activeStatusChip) + await Assert.isVisible(this.timeRemainingId) + await Assert.isVisible(this.estimatedRewardsId) + await Assert.isVisible(this.stakedAmountId) } async verifyNoActiveStakesScreenItems() { @@ -354,6 +450,29 @@ class StakePage { await Assert.isVisible(this.noActiveStakesDescription) await Assert.isVisible(this.earnSvg) } + + async getStakeCardInfo(isActive = true): Promise { + const rewardsId = isActive ? this.estimatedRewardsId : this.earnedRewardsId + const title = await Actions.getElementText(this.stakeCardTitle) + const timeId = isActive ? this.timeRemainingId : this.endDateId + const rewards = await Actions.getElementText(rewardsId) + const stakedAmount = await Actions.getElementText(this.stakedAmountId) + let time = await Actions.getElementText(timeId) + if (isActive) { + // We need to adjust the text a little bit + time = time?.replace(' remaining', '') // remove `remaining` from `1 day remaining` + time = time?.replace(/\b\w/g, char => char.toUpperCase()) // make it TitleCase `2 months 1 day` -> `2 Months 1 Day` + } + console.log( + `Title: ${title}, Time: ${time}, Rewards: ${rewards}, Staked Amount: ${stakedAmount}` + ) + return { + title: title ?? '', + rewards: rewards ?? '', + amount: stakedAmount ?? '', + time: time ?? '' + } + } } export default new StakePage() diff --git a/packages/core-mobile/e2e/tests/browser/suggestedBrowsers.e2e.ts b/packages/core-mobile/e2e/tests/browser/suggestedBrowsers.e2e.ts index 0fa4c2718f..3d27c5fd89 100644 --- a/packages/core-mobile/e2e/tests/browser/suggestedBrowsers.e2e.ts +++ b/packages/core-mobile/e2e/tests/browser/suggestedBrowsers.e2e.ts @@ -1,4 +1,3 @@ -import { SUGGESTED_ITEMS } from 'store/browser/const' import actions from '../../helpers/actions' import { warmup } from '../../helpers/warmup' import bottomTabsPage from '../../pages/bottomTabs.page' @@ -12,6 +11,56 @@ describe('Suggested Browsers', () => { await warmup() }) + const SUGGESTED_ITEMS = [ + { + name: 'LFJ', + siteUrl: 'https://lfj.gg/' + }, + { + name: 'Yield Yak', + siteUrl: 'https://yieldyak.com/avalanche/' + }, + { + name: 'GMX', + siteUrl: 'https://app.gmx.io/#/trade' + }, + { + name: 'Aave', + siteUrl: 'https://app.aave.com/' + }, + { + name: 'GoGoPool', + siteUrl: 'https://www.gogopool.com/' + }, + { + name: 'Salvor', + siteUrl: 'https://salvor.io/' + }, + { + name: 'Delta Prime', + siteUrl: 'https://app.deltaprime.io/#/pools' + }, + { + name: 'The Arena', + siteUrl: 'https://arena.social/' + }, + { + name: 'SteakHut', + siteUrl: 'https://app.steakhut.finance/liquidity' + }, + { + name: 'Pharaoh', + siteUrl: 'https://pharaoh.exchange/swap' + }, + { + name: 'Pangolin', + siteUrl: 'https://app.pangolin.exchange/' + }, + { + name: 'Benqi', + siteUrl: 'https://benqi.fi/' + } + ] const names: string[] = SUGGESTED_ITEMS.map(item => item.name) const urls: string[] = SUGGESTED_ITEMS.map(item => item.siteUrl) diff --git a/packages/core-mobile/e2e/tests/notification/sendNotification.e2e.ts b/packages/core-mobile/e2e/tests/notification/sendNotification.e2e.ts deleted file mode 100644 index f935f5abb0..0000000000 --- a/packages/core-mobile/e2e/tests/notification/sendNotification.e2e.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { warmup } from '../../helpers/warmup' -import sendLoc from '../../locators/send.loc' -import accountManagePage from '../../pages/accountManage.page' -import notificationsPage from '../../pages/burgerMenu/notifications.page' -import portfolioPage from '../../pages/portfolio.page' -import sendPage from '../../pages/send.page' - -describe('Send Notification', () => { - beforeAll(async () => { - await warmup(false, true) - await accountManagePage.createSecondAccount() - }) - - it('should receive send notification', async () => { - await sendPage.sendTokenTo2ndAccount( - sendLoc.avaxToken, - sendLoc.sendingAmount - ) - await device.sendToHome() - await notificationsPage.verifyPushNotification() - await notificationsPage.tapPushNotification() - await portfolioPage.verifyPorfolioScreen() - }) - - it('should not receive send notification', async () => { - await notificationsPage.switchBalanceNotification(false) - await sendPage.sendTokenTo2ndAccount( - sendLoc.avaxToken, - sendLoc.sendingAmount - ) - await device.sendToHome() - await notificationsPage.verifyNoPushNotification() - await device.launchApp() - await portfolioPage.verifyPorfolioScreen() - }) -}) diff --git a/packages/core-mobile/e2e/tests/stake/stakingMainnet.e2e.ts b/packages/core-mobile/e2e/tests/stake/stakingMainnet.e2e.ts index 2916d4f0bf..3862975cb0 100644 --- a/packages/core-mobile/e2e/tests/stake/stakingMainnet.e2e.ts +++ b/packages/core-mobile/e2e/tests/stake/stakingMainnet.e2e.ts @@ -15,8 +15,39 @@ describe('Stake on Mainnet', () => { await advancedPage.switchToMainnet() }) - it('should test a staking flow on mainnet for an existing account', async () => { + it('should verify stake tabs', async () => { await BottomTabsPage.tapStakeTab() + try { + await StakePage.verifyNoActiveStakesScreenItems() + } catch (e) { + await StakePage.verifyActiveTabItems() + } + await StakePage.tapHistoryTab() + await StakePage.verifyHistoryTabItems() + }) + + it('should verify active stake details', async () => { + await StakePage.tapActiveTab() + if (await Actions.isVisible(StakePage.stakeCardTitle, 0)) { + // Verify active stake details if there is one active stake card + const stakeCardInfo = await StakePage.getStakeCardInfo() + await StakePage.tapStakeCard() + await StakePage.verifyActiveStakeDetails(stakeCardInfo) + await commonElsPage.goBack() + } else { + console.log('There is no active stake card') + } + }) + + it('should verify completed stake details', async () => { + await StakePage.tapHistoryTab() + const stakeCardInfo = await StakePage.getStakeCardInfo(false) + await StakePage.tapStakeCard() + await StakePage.verifyCompletedStakeDetails(stakeCardInfo) + await commonElsPage.goBack() + }) + + it('should test a staking flow on mainnet for an existing account', async () => { await StakePage.tapStakeButton() await GetStartedScreenPage.tapNextButton() if (await Actions.isVisible(StakePage.notEnoughAvaxTitle, 0)) { From 0b04824be68d5cb28cb31784f884761819a12a04 Mon Sep 17 00:00:00 2001 From: eunjisong Date: Fri, 18 Oct 2024 11:01:31 -0400 Subject: [PATCH 2/2] cleanup --- .../e2e/pages/burgerMenu/notifications.page.ts | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/packages/core-mobile/e2e/pages/burgerMenu/notifications.page.ts b/packages/core-mobile/e2e/pages/burgerMenu/notifications.page.ts index 39379a68cc..eeec092bd6 100644 --- a/packages/core-mobile/e2e/pages/burgerMenu/notifications.page.ts +++ b/packages/core-mobile/e2e/pages/burgerMenu/notifications.page.ts @@ -62,22 +62,6 @@ class Notifications { await actions.waitForElement(this.balanceDisabledSwitch) } } - - async verifyPushNotification() { - // TODO: currently push notification is broken on internal build. We can update the methods once it's fixed - console.log('verify push notification is received') - } - - async tapPushNotification() { - // TODO: currently push notification is broken on internal build. We can update the methods once it's fixed - console.log('verify the deeplink works properly') - await device.launchApp() // temporary solution - } - - async verifyNoPushNotification() { - // TODO: currently push notification is broken on internal build. We can update the methods once it's fixed - console.log('verify the push notification is NOT received') - } } export default new Notifications()