From f20a1ce21dbec5df420811c138e619d5f8e20ea9 Mon Sep 17 00:00:00 2001 From: Eunji Song <32075932+eunjisong@users.noreply.github.com> Date: Mon, 14 Oct 2024 19:26:56 -0400 Subject: [PATCH] QA - New: Manage accounts (#1953) --- .../app/components/svg/ReloadSVG.tsx | 5 +- .../screens/portfolio/account/AccountItem.tsx | 21 ++++-- packages/core-mobile/e2e/helpers/actions.ts | 7 +- .../core-mobile/e2e/helpers/assertions.ts | 4 +- .../e2e/locators/accountManage.loc.ts | 5 +- .../core-mobile/e2e/locators/commonEls.loc.ts | 5 +- .../e2e/pages/accountManage.page.ts | 26 ++++++- .../core-mobile/e2e/pages/commonEls.page.ts | 30 ++++++++- .../core-mobile/e2e/pages/portfolio.page.ts | 5 ++ .../tests/portfolioTab/manageAccounts.e2e.ts | 67 +++++++++++++++++++ packages/core-mobile/package.json | 2 +- yarn.lock | 22 +++--- 12 files changed, 172 insertions(+), 27 deletions(-) create mode 100644 packages/core-mobile/e2e/tests/portfolioTab/manageAccounts.e2e.ts diff --git a/packages/core-mobile/app/components/svg/ReloadSVG.tsx b/packages/core-mobile/app/components/svg/ReloadSVG.tsx index 3381b4b9ce..b7f08e900f 100644 --- a/packages/core-mobile/app/components/svg/ReloadSVG.tsx +++ b/packages/core-mobile/app/components/svg/ReloadSVG.tsx @@ -4,14 +4,15 @@ import { useApplicationContext } from 'contexts/ApplicationContext' interface Prop { color?: string + testID?: string } -function ReloadSVG({ color }: Prop) { +function ReloadSVG({ color, testID = 'reload_svg' }: Prop): JSX.Element { const context = useApplicationContext() const iconColor = color ?? context.theme.colorIcon1 return ( - + saveAccountTitle(editedAccountTitle)} /> ) : ( - + )} {showLoader && ( @@ -135,7 +135,9 @@ function AccountItem({ )} {!showLoader && isBalanceLoaded && ( - {accountBalance} + + {accountBalance} + @@ -237,6 +239,7 @@ const EditTitle = ({ return ( { - return {title} +const Title = ({ + title, + testID +}: { + title: string + testID?: string +}): JSX.Element => { + return ( + + {title} + + ) } export default AccountItem diff --git a/packages/core-mobile/e2e/helpers/actions.ts b/packages/core-mobile/e2e/helpers/actions.ts index d5d25ded5d..397de5ad52 100644 --- a/packages/core-mobile/e2e/helpers/actions.ts +++ b/packages/core-mobile/e2e/helpers/actions.ts @@ -281,6 +281,10 @@ async function writeQrCodeToFile(clipboardValue: string) { ) } +const clearTextInput = async (item: Detox.NativeMatcher, index = 0) => { + await element(item).atIndex(index).clearText() +} + async function waitForCondition(func: any, condition: any, timeout = 5000) { let isFulfilled = false @@ -327,5 +331,6 @@ export default { getElementsByTestId, getElementsTextByTestId, dismissKeyboard, - getElementText + getElementText, + clearTextInput } diff --git a/packages/core-mobile/e2e/helpers/assertions.ts b/packages/core-mobile/e2e/helpers/assertions.ts index 2e26242b68..38f71f8b6a 100644 --- a/packages/core-mobile/e2e/helpers/assertions.ts +++ b/packages/core-mobile/e2e/helpers/assertions.ts @@ -31,8 +31,8 @@ const isNotVisible = async (item: Detox.NativeMatcher, index = 0) => { await expect(element(item).atIndex(index)).not.toBeVisible() } -const hasText = async (item: Detox.NativeMatcher, text: string) => { - await expect(element(item)).toHaveText(text) +const hasText = async (item: Detox.NativeMatcher, text: string, index = 0) => { + await expect(element(item).atIndex(index)).toHaveText(text) } const hasValue = async (item: Detox.NativeMatcher, value: string) => { diff --git a/packages/core-mobile/e2e/locators/accountManage.loc.ts b/packages/core-mobile/e2e/locators/accountManage.loc.ts index 2d152d5dba..fd5add8ce3 100644 --- a/packages/core-mobile/e2e/locators/accountManage.loc.ts +++ b/packages/core-mobile/e2e/locators/accountManage.loc.ts @@ -12,5 +12,8 @@ export default { secondAccount: 'Account 2', fourthaccount: 'Account 4', accountDropdownTitle: 'account_dropdown_title', - accountsDropdown: 'accounts_dropdown' + accountsDropdown: 'accounts_dropdown', + editedAccountName: 'Edited Account 2', + accountBalance: 'account_balance', + accountTitle: 'account_title' } diff --git a/packages/core-mobile/e2e/locators/commonEls.loc.ts b/packages/core-mobile/e2e/locators/commonEls.loc.ts index fcef39511f..d7cf099244 100644 --- a/packages/core-mobile/e2e/locators/commonEls.loc.ts +++ b/packages/core-mobile/e2e/locators/commonEls.loc.ts @@ -9,5 +9,8 @@ export default { testnetBanner: 'testnet_banner', notNow: 'Not Now', turnOnNotifications: 'Turn on Notifications', - searchBar: 'search_bar__search' + searchBar: 'search_bar__search', + bitcoinSVG: 'bitcoin_svg', + avaSVG: 'ava_logo', + reloadSVG: 'reload_svg' } diff --git a/packages/core-mobile/e2e/pages/accountManage.page.ts b/packages/core-mobile/e2e/pages/accountManage.page.ts index a77525d8f8..8857fa4877 100644 --- a/packages/core-mobile/e2e/pages/accountManage.page.ts +++ b/packages/core-mobile/e2e/pages/accountManage.page.ts @@ -3,6 +3,7 @@ import Action from '../helpers/actions' import accountManage from '../locators/accountManage.loc' import { Platform } from '../helpers/constants' import Assert from '../helpers/assertions' +import commonElsLoc from '../locators/commonEls.loc' class AccountManagePage { get account() { @@ -61,6 +62,18 @@ class AccountManagePage { return by.text(accountManage.fourthaccount) } + get editedAccountName() { + return by.text(accountManage.editedAccountName) + } + + get accountBalance() { + return by.id(accountManage.accountBalance) + } + + get accountTitle() { + return by.id(accountManage.accountTitle) + } + async tapAccountDropdownTitle(index = 0) { await Action.tapElementAtIndex(this.accountDropdownTitle, index) } @@ -195,12 +208,15 @@ class AccountManagePage { await Action.tapElementAtIndex(this.doneButton, 0) } - async tapEditAccount() { - await Action.tapElementAtIndex(this.editAccount, 0) + async tapEditAccount(index = 0) { + await Action.tapElementAtIndex(this.editAccount, index) } async tapSaveNewAccountName() { - await Action.tapElementAtIndex(this.saveNewAccountName, 0) + await Action.dismissKeyboard(commonElsLoc.inputTextField) + if (Action.platform() === 'android') { + await Action.tapElementAtIndex(this.saveNewAccountName, 0) + } } async tapFirstAccount() { @@ -250,6 +266,10 @@ class AccountManagePage { } } } + + async verifyAccountNameOnMyAccounts(name: string, index = 0) { + await Assert.hasText(this.accountTitle, name, index) + } } export default new AccountManagePage() diff --git a/packages/core-mobile/e2e/pages/commonEls.page.ts b/packages/core-mobile/e2e/pages/commonEls.page.ts index abef362432..8f5babf325 100644 --- a/packages/core-mobile/e2e/pages/commonEls.page.ts +++ b/packages/core-mobile/e2e/pages/commonEls.page.ts @@ -50,6 +50,18 @@ class CommonElsPage { return by.id(commonEls.searchBar) } + get bitcoinSVG() { + return by.id(commonEls.bitcoinSVG) + } + + get avaSVG() { + return by.id(commonEls.avaSVG) + } + + get reloadSVG() { + return by.id(commonEls.reloadSVG) + } + async typeSearchBar(text: string) { await Actions.waitForElement(this.searchBar) await Actions.setInputText(this.searchBar, text) @@ -63,7 +75,11 @@ class CommonElsPage { await Actions.tap(this.getStartedButton) } - async enterTextInput(index: number, inputText: string) { + async enterTextInput(inputText: string, index = 0) { + await Actions.setInputText(this.inputTextField, inputText, index) + } + + async clearTextInput(inputText: string, index = 0) { await Actions.setInputText(this.inputTextField, inputText, index) } @@ -135,6 +151,18 @@ class CommonElsPage { async tapTurnOnNotifications() { await Actions.tapElementAtIndex(this.turnOnNotifications, 0) } + + async tapAvaSVG(index = 0) { + await Actions.tapElementAtIndex(this.avaSVG, index) + } + + async tapBitcoinSVG(index = 0) { + await Actions.tapElementAtIndex(this.bitcoinSVG, index) + } + + async tapReloadSVG(index = 0) { + await Actions.tapElementAtIndex(this.reloadSVG, index) + } } export default new CommonElsPage() diff --git a/packages/core-mobile/e2e/pages/portfolio.page.ts b/packages/core-mobile/e2e/pages/portfolio.page.ts index 9191db77e9..16fa4aa5c8 100644 --- a/packages/core-mobile/e2e/pages/portfolio.page.ts +++ b/packages/core-mobile/e2e/pages/portfolio.page.ts @@ -5,6 +5,7 @@ import { Platform } from '../helpers/constants' import networksManagePage from './networksManage.page' import ActivityTabPage from './activityTab.page' import collectiblesPage from './collectibles.page' +import accountManagePage from './accountManage.page' const platformIndex = Action.platform() === Platform.iOS ? 1 : 0 class PortfolioPage { @@ -347,6 +348,10 @@ class PortfolioPage { console.log('nothing?') return output } + + async verifyAccountName(name: string) { + await Assert.hasText(accountManagePage.accountDropdownTitle, name) + } } export default new PortfolioPage() diff --git a/packages/core-mobile/e2e/tests/portfolioTab/manageAccounts.e2e.ts b/packages/core-mobile/e2e/tests/portfolioTab/manageAccounts.e2e.ts new file mode 100644 index 0000000000..534ace3051 --- /dev/null +++ b/packages/core-mobile/e2e/tests/portfolioTab/manageAccounts.e2e.ts @@ -0,0 +1,67 @@ +/* eslint-env detox/detox, jest */ +/** + * @jest-environment ./environment.ts + */ +import actions from '../../helpers/actions' +import assertions from '../../helpers/assertions' +import { warmup } from '../../helpers/warmup' +import accountManageLoc from '../../locators/accountManage.loc' +import accountManagePage from '../../pages/accountManage.page' +import commonElsPage from '../../pages/commonEls.page' +import portfolioPage from '../../pages/portfolio.page' +import receivePage from '../../pages/receive.page' + +describe('Manage Account', () => { + beforeAll(async () => { + await warmup() + await accountManagePage.createNthAccountAndSwitchToNth(2) + }) + + it('should not edit with the invalid account name', async () => { + // Check account name before editing + await accountManagePage.tapAccountDropdownTitle() + await accountManagePage.tapAddEditAccounts() + // Try to save name without any string + await accountManagePage.tapEditAccount(1) + await actions.clearTextInput(commonElsPage.inputTextField) + await accountManagePage.tapSaveNewAccountName() + // Verify you can't save the empty string + await assertions.isVisible(commonElsPage.inputTextField) + await assertions.isVisible(accountManagePage.saveNewAccountName) + await accountManagePage.tapDoneButton() + }) + + it('should edit with the valid account name', async () => { + // Check account name before editing + await accountManagePage.tapAccountDropdownTitle() + await accountManagePage.tapAddEditAccounts() + await accountManagePage.verifyAccountNameOnMyAccounts('Account 2', 1) + // Edit account name + await accountManagePage.tapEditAccount(1) + await commonElsPage.enterTextInput(accountManageLoc.editedAccountName) + await accountManagePage.tapSaveNewAccountName() + + // Verify the name is edited on `My Accounts` screen + await accountManagePage.verifyAccountNameOnMyAccounts( + accountManageLoc.editedAccountName, + 1 + ) + await accountManagePage.tapDoneButton() + + // Verify the edited name is displayed on Portfolio screen + await portfolioPage.verifyAccountName(accountManageLoc.editedAccountName) + }) + + it('should copy the wallet address', async () => { + // Hit AvaLogo to copy address + await accountManagePage.tapAccountDropdownTitle() + await commonElsPage.tapAvaSVG() + await assertions.isVisible(receivePage.copiedToastMsg) + await actions.waitForElementNotVisible(receivePage.copiedToastMsg) + + // Hit Bitcoin Logo to copy address + await commonElsPage.tapBitcoinSVG() + await assertions.isVisible(receivePage.copiedToastMsg) + await actions.waitForElementNotVisible(receivePage.copiedToastMsg) + }) +}) diff --git a/packages/core-mobile/package.json b/packages/core-mobile/package.json index d5d0b249bf..3f720322d8 100644 --- a/packages/core-mobile/package.json +++ b/packages/core-mobile/package.json @@ -225,7 +225,7 @@ "babel-plugin-inline-dotenv": "1.7.0", "babel-plugin-module-resolver": "5.0.2", "babel-plugin-react-require": "4.0.3", - "detox": "20.27.3", + "detox": "20.27.2", "eslint": "8.50.0", "eslint-plugin-avalabs-mobile": "workspace:*", "jest": "29.7.0", diff --git a/yarn.lock b/yarn.lock index b5ea00e3d1..02784e1759 100644 --- a/yarn.lock +++ b/yarn.lock @@ -277,7 +277,7 @@ __metadata: crypto-browserify: 3.12.0 date-fns: 4.1.0 deprecated-react-native-prop-types: 5.0.0 - detox: 20.27.3 + detox: 20.27.2 es6-promise: 4.2.8 eslint: 8.50.0 eslint-plugin-avalabs-mobile: "workspace:*" @@ -15817,16 +15817,16 @@ __metadata: languageName: node linkType: hard -"detox-copilot@npm:^0.0.14": - version: 0.0.14 - resolution: "detox-copilot@npm:0.0.14" - checksum: 79b81f61d98ee1dd586823e3f6f93c186127f83298d85492e02b397f31cb9d96e76ee8073bd02a09b04e7f6e1b8bf08ffbd6819da06665c56ecd625efb31505b +"detox-copilot@npm:^0.0.9": + version: 0.0.9 + resolution: "detox-copilot@npm:0.0.9" + checksum: ba7a82191ccc0c642d54adbc601415283205885f444e91daca6b658a50392cdee0090fc95f876bef650f6e16be49f4a5ed89ad064dab405f45ba64d479a6d97c languageName: node linkType: hard -"detox@npm:20.27.3": - version: 20.27.3 - resolution: "detox@npm:20.27.3" +"detox@npm:20.27.2": + version: 20.27.2 + resolution: "detox@npm:20.27.2" dependencies: ajv: ^8.6.3 bunyan: ^1.8.12 @@ -15834,7 +15834,7 @@ __metadata: caf: ^15.0.1 chalk: ^4.0.0 child-process-promise: ^2.2.0 - detox-copilot: ^0.0.14 + detox-copilot: ^0.0.9 execa: ^5.1.1 find-up: ^5.0.0 fs-extra: ^11.0.0 @@ -15871,7 +15871,7 @@ __metadata: optional: true bin: detox: local-cli/cli.js - checksum: fc37750edfbaac59a8d892a9b055a2941e84e2c7d082910f7336feaf139cc528cc6e62a6874b1ab8ab9192e5430a66231d809b5deff8dcae711f6cea8e4d37a6 + checksum: a7bb8997c591b827c31176ba107b1ec23f7bb8b78ce08c781343937637439771a1cc8f1086844301fbbf0f34ada2e889827821adf5245aa8f4c5b4f5cad23248 languageName: node linkType: hard @@ -26073,7 +26073,7 @@ react-native-webview@ava-labs/react-native-webview: peerDependencies: react: "*" react-native: "*" - checksum: a187edd718e1ea3a6b1e5da167744e6ee324bc3c3e492bcb0a9d028ab68a82907f053f37c23aa4229d6a9091541cee3c73549c3c850056e4cf5eb5b3cb2c9ffc + checksum: 871333b155b3899238428ee071c7cce31f668ba2e4ef70f08c14432c76fad42f0a2d460ca278d6d5149e632e83f544c77555937a0d6cf7e9d726f7d6b06c1d0b languageName: node linkType: hard