From 6c944752ed3edabcd913b0e5eab0e96eeb5ddfad Mon Sep 17 00:00:00 2001 From: Chloe Gao Date: Fri, 6 Dec 2024 16:13:09 +0100 Subject: [PATCH 01/10] migrate tests --- .../flask/btc/btc-account-overview.spec.ts | 56 ++------- test/e2e/page-objects/pages/header-navbar.ts | 2 +- .../pages/home/bitcoin-homepage.ts | 113 ++++++++++++++++++ test/e2e/page-objects/pages/home/homepage.ts | 6 +- test/e2e/webdriver/driver.js | 14 ++- 5 files changed, 138 insertions(+), 53 deletions(-) create mode 100644 test/e2e/page-objects/pages/home/bitcoin-homepage.ts diff --git a/test/e2e/flask/btc/btc-account-overview.spec.ts b/test/e2e/flask/btc/btc-account-overview.spec.ts index 418c9d736078..ad0743f2f240 100644 --- a/test/e2e/flask/btc/btc-account-overview.spec.ts +++ b/test/e2e/flask/btc/btc-account-overview.spec.ts @@ -1,42 +1,22 @@ +import { strict as assert } from 'assert'; import { Suite } from 'mocha'; import { DEFAULT_BTC_BALANCE } from '../../constants'; import { withBtcAccountSnap } from './common-btc'; +import BitcoinHomepage from '../../page-objects/pages/home/bitcoin-homepage'; describe('BTC Account - Overview', function (this: Suite) { it('has portfolio button enabled for BTC accounts', async function () { await withBtcAccountSnap( { title: this.test?.fullTitle() }, async (driver) => { - await driver.findElement({ - css: '[data-testid="account-menu-icon"]', - text: 'Bitcoin Account', - }); - - await driver.waitForSelector({ - text: 'Send', - tag: 'button', - css: '[data-testid="coin-overview-send"]', - }); - - await driver.waitForSelector({ - text: 'Swap', - tag: 'button', - css: '[disabled]', - }); - - await driver.waitForSelector({ - text: 'Bridge', - tag: 'button', - css: '[disabled]', - }); - - // buy sell button - await driver.findClickableElement('[data-testid="coin-overview-buy"]'); - - // receive button - await driver.findClickableElement( - '[data-testid="coin-overview-receive"]', - ); + const homePage = new BitcoinHomepage(driver); + await homePage.check_pageIsLoaded(); + await homePage.headerNavbar.check_accountLabel('Bitcoin Account'); + + assert.equal(await homePage.check_ifBridgeButtonIsDisabled(), false); + assert.equal(await homePage.check_ifSwapButtonIsClickable(), false); + assert.equal(await homePage.check_ifBuySellButtonIsClickable(), true); + assert.equal(await homePage.check_ifReceiveButtonIsClickable(), true); }, ); }); @@ -45,19 +25,9 @@ describe('BTC Account - Overview', function (this: Suite) { await withBtcAccountSnap( { title: this.test?.fullTitle() }, async (driver) => { - await driver.waitForSelector({ - testId: 'account-value-and-suffix', - text: `${DEFAULT_BTC_BALANCE}`, - }); - await driver.waitForSelector({ - css: '.currency-display-component__suffix', - text: 'BTC', - }); - - await driver.waitForSelector({ - tag: 'p', - text: `${DEFAULT_BTC_BALANCE} BTC`, - }); + const homePage = new BitcoinHomepage(driver); + await homePage.check_pageIsLoaded(); + await homePage.check_expectedBitcoinBalanceIsDisplayed(DEFAULT_BTC_BALANCE); }, ); }); diff --git a/test/e2e/page-objects/pages/header-navbar.ts b/test/e2e/page-objects/pages/header-navbar.ts index 100c23b851e4..5ef28e25b90a 100644 --- a/test/e2e/page-objects/pages/header-navbar.ts +++ b/test/e2e/page-objects/pages/header-navbar.ts @@ -1,7 +1,7 @@ import { Driver } from '../../webdriver/driver'; class HeaderNavbar { - private driver: Driver; + protected driver: Driver; private readonly accountMenuButton = '[data-testid="account-menu-icon"]'; diff --git a/test/e2e/page-objects/pages/home/bitcoin-homepage.ts b/test/e2e/page-objects/pages/home/bitcoin-homepage.ts new file mode 100644 index 000000000000..5c5061f3b888 --- /dev/null +++ b/test/e2e/page-objects/pages/home/bitcoin-homepage.ts @@ -0,0 +1,113 @@ +import { Driver } from '../../../webdriver/driver'; +import HomePage from '../home/homepage'; + +class BitcoinHomepage extends HomePage { + + protected readonly balance = '[data-testid="coin-overview__primary-currency"]'; + + private readonly bridgeButton = { + text: 'Bridge', + tag: 'button', + } + + private readonly buySellButton = '[data-testid="coin-overview-buy"]'; + + private readonly receiveButton = '[data-testid="coin-overview-receive"]'; + + protected readonly sendButton = '[data-testid="coin-overview-send"]'; + + private readonly swapButton = { + text: 'Swap', + tag: 'button', + } + + constructor(driver: Driver) { + super(driver); + } + + async check_pageIsLoaded(): Promise { + try { + await this.driver.waitForMultipleSelectors([ + this.sendButton, + this.buySellButton, + this.receiveButton, + ]); + } catch (e) { + console.log('Timeout while waiting for bitcoin homepage to be loaded', e); + throw e; + } + console.log('Bitcoin homepage is loaded'); + } + + async check_ifBridgeButtonIsDisabled(): Promise { + try { + await this.driver.findClickableElement(this.bridgeButton, 1000); + } catch (e) { + console.log('Bridge button not clickable', e); + return false; + } + console.log('Bridge button is clickable'); + return true; + } + + /** + * Checks if the expected bitcoin balance is displayed on homepage. + * + * @param expectedBalance - The expected bitcoin balance to be displayed. Defaults to '0'. + */ + async check_expectedBitcoinBalanceIsDisplayed( + expectedBalance: number = 0, + ): Promise { + console.log(`Check if expected bitcoin balance is displayed: ${expectedBalance} BTC`); + await this.driver.waitForSelector({ + css: this.balance, + text: expectedBalance + 'BTC', + }); + } + + async check_ifBuySellButtonIsClickable(): Promise { + try { + await this.driver.findClickableElement(this.buySellButton, 1000); + } catch (e) { + console.log('Buy/Sell button not clickable', e); + return false; + } + console.log('Buy/Sell button is clickable'); + return true; + } + + async check_ifReceiveButtonIsClickable(): Promise { + try { + await this.driver.findClickableElement(this.receiveButton, 1000); + } catch (e) { + console.log('Receive button not clickable', e); + return false; + } + console.log('Receive button is clickable'); + return true; + } + + async check_ifSendButtonIsClickable(): Promise { + try { + await this.driver.findClickableElement(this.sendButton, 1000); + } catch (e) { + console.log('Send button not clickable', e); + return false; + } + console.log('Send button is clickable'); + return true; + } + + async check_ifSwapButtonIsClickable(): Promise { + try { + await this.driver.findClickableElement(this.swapButton, 1000); + } catch (e) { + console.log('Swap button not clickable', e); + return false; + } + console.log('Swap button is clickable'); + return true; + } +} + +export default BitcoinHomepage; diff --git a/test/e2e/page-objects/pages/home/homepage.ts b/test/e2e/page-objects/pages/home/homepage.ts index 6b6197eed797..3e8e3a387587 100644 --- a/test/e2e/page-objects/pages/home/homepage.ts +++ b/test/e2e/page-objects/pages/home/homepage.ts @@ -4,14 +4,14 @@ import { getCleanAppState } from '../../../helpers'; import HeaderNavbar from '../header-navbar'; class HomePage { - private driver: Driver; + protected driver: Driver; public headerNavbar: HeaderNavbar; private readonly activityTab = '[data-testid="account-overview__activity-tab"]'; - private readonly balance = '[data-testid="eth-overview__primary-currency"]'; + protected readonly balance: string = '[data-testid="eth-overview__primary-currency"]'; private readonly basicFunctionalityOffWarningMessage = { text: 'Basic functionality is off', @@ -29,7 +29,7 @@ class HomePage { private readonly popoverCloseButton = '[data-testid="popover-close"]'; - private readonly sendButton = '[data-testid="eth-overview-send"]'; + protected readonly sendButton: string = '[data-testid="eth-overview-send"]'; private readonly tokensTab = '[data-testid="account-overview__asset-tab"]'; diff --git a/test/e2e/webdriver/driver.js b/test/e2e/webdriver/driver.js index b0a335eb0d64..c16ef3999490 100644 --- a/test/e2e/webdriver/driver.js +++ b/test/e2e/webdriver/driver.js @@ -499,13 +499,14 @@ class Driver { * and returns a reference to the first matching element. * * @param {string | object} rawLocator - Element locator + * @param {number} timeout - Timeout in milliseconds * @returns {Promise} A promise that resolves to the found element. */ - async findElement(rawLocator) { + async findElement(rawLocator, timeout = this.timeout) { const locator = this.buildLocator(rawLocator); const element = await this.driver.wait( until.elementLocated(locator), - this.timeout, + timeout, ); return wrapElementWithAPI(element, this); } @@ -540,13 +541,14 @@ class Driver { * Finds a clickable element on the page using the given locator. * * @param {string | object} rawLocator - Element locator + * @param {number} timeout - Timeout in milliseconds * @returns {Promise} A promise that resolves to the found clickable element. */ - async findClickableElement(rawLocator) { - const element = await this.findElement(rawLocator); + async findClickableElement(rawLocator, timeout = this.timeout) { + const element = await this.findElement(rawLocator, timeout); await Promise.all([ - this.driver.wait(until.elementIsVisible(element), this.timeout), - this.driver.wait(until.elementIsEnabled(element), this.timeout), + this.driver.wait(until.elementIsVisible(element), timeout), + this.driver.wait(until.elementIsEnabled(element), timeout), ]); return wrapElementWithAPI(element, this); } From f03db397951393fe4317c447ef9d95cde5188f03 Mon Sep 17 00:00:00 2001 From: Chloe Gao Date: Mon, 9 Dec 2024 14:03:34 +0100 Subject: [PATCH 02/10] migrate tests --- .../flask/btc/btc-account-overview.spec.ts | 6 ++- .../e2e/flask/btc/btc-dapp-connection.spec.ts | 19 ++++--- .../btc/btc-experimental-settings.spec.ts | 54 +++++++++---------- .../page-objects/pages/account-list-page.ts | 16 ++++++ .../pages/home/bitcoin-homepage.ts | 29 +++++----- test/e2e/page-objects/pages/home/homepage.ts | 3 +- .../pages/settings/experimental-settings.ts | 13 +++++ test/e2e/page-objects/pages/test-dapp.ts | 44 +++++++++------ ...account-signatures-and-disconnects.spec.ts | 4 +- 9 files changed, 116 insertions(+), 72 deletions(-) diff --git a/test/e2e/flask/btc/btc-account-overview.spec.ts b/test/e2e/flask/btc/btc-account-overview.spec.ts index ad0743f2f240..39ee125b70b1 100644 --- a/test/e2e/flask/btc/btc-account-overview.spec.ts +++ b/test/e2e/flask/btc/btc-account-overview.spec.ts @@ -1,8 +1,8 @@ import { strict as assert } from 'assert'; import { Suite } from 'mocha'; import { DEFAULT_BTC_BALANCE } from '../../constants'; -import { withBtcAccountSnap } from './common-btc'; import BitcoinHomepage from '../../page-objects/pages/home/bitcoin-homepage'; +import { withBtcAccountSnap } from './common-btc'; describe('BTC Account - Overview', function (this: Suite) { it('has portfolio button enabled for BTC accounts', async function () { @@ -27,7 +27,9 @@ describe('BTC Account - Overview', function (this: Suite) { async (driver) => { const homePage = new BitcoinHomepage(driver); await homePage.check_pageIsLoaded(); - await homePage.check_expectedBitcoinBalanceIsDisplayed(DEFAULT_BTC_BALANCE); + await homePage.check_expectedBitcoinBalanceIsDisplayed( + DEFAULT_BTC_BALANCE, + ); }, ); }); diff --git a/test/e2e/flask/btc/btc-dapp-connection.spec.ts b/test/e2e/flask/btc/btc-dapp-connection.spec.ts index 2eb33a4b7d74..2f5aef6fc1a7 100644 --- a/test/e2e/flask/btc/btc-dapp-connection.spec.ts +++ b/test/e2e/flask/btc/btc-dapp-connection.spec.ts @@ -1,20 +1,23 @@ import { Suite } from 'mocha'; -import { openDapp, WINDOW_TITLES } from '../../helpers'; import { withBtcAccountSnap } from './common-btc'; +import BitcoinHomepage from '../../page-objects/pages/home/bitcoin-homepage'; +import TestDapp from '../../page-objects/pages/test-dapp'; describe('BTC Account - Dapp Connection', function (this: Suite) { it('cannot connect to dapps', async function () { await withBtcAccountSnap( { title: this.test?.fullTitle() }, async (driver) => { - await openDapp(driver); - await driver.clickElement('#connectButton'); - await driver.waitUntilXWindowHandles(3); - await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + const homePage = new BitcoinHomepage(driver); + await homePage.check_pageIsLoaded(); + await homePage.headerNavbar.check_accountLabel('Bitcoin Account'); - await driver.assertElementNotPresent( - '[data-testid="choose-account-list-1"]', - ); + const testDapp = new TestDapp(driver); + await testDapp.openTestDappPage(); + await testDapp.check_pageIsLoaded(); + await testDapp.connectAccount({ + connectAccountButtonEnabled: false, + }); }, ); }); diff --git a/test/e2e/flask/btc/btc-experimental-settings.spec.ts b/test/e2e/flask/btc/btc-experimental-settings.spec.ts index 45bc7d0d1701..10a183bf87bb 100644 --- a/test/e2e/flask/btc/btc-experimental-settings.spec.ts +++ b/test/e2e/flask/btc/btc-experimental-settings.spec.ts @@ -1,47 +1,45 @@ import { Suite } from 'mocha'; - -import messages from '../../../../app/_locales/en/messages.json'; import FixtureBuilder from '../../fixture-builder'; -import { - defaultGanacheOptions, - unlockWallet, - withFixtures, -} from '../../helpers'; +import { withFixtures } from '../../helpers'; import { Driver } from '../../webdriver/driver'; +import AccountListPage from '../../page-objects/pages/account-list-page'; +import ExperimentalSettings from '../../page-objects/pages/settings/experimental-settings'; +import HomePage from '../../page-objects/pages/home/homepage'; +import HeaderNavbar from '../../page-objects/pages/header-navbar'; +import SettingsPage from '../../page-objects/pages/settings/settings-page'; +import { loginWithBalanceValidation } from '../../page-objects/flows/login.flow'; describe('BTC Experimental Settings', function (this: Suite) { it('will show `Add a new Bitcoin account (Beta)` option when setting is enabled', async function () { await withFixtures( { fixtures: new FixtureBuilder().build(), - ganacheOptions: defaultGanacheOptions, title: this.test?.fullTitle(), }, async ({ driver }: { driver: Driver }) => { - await unlockWallet(driver); - await driver.clickElement( - '[data-testid="account-options-menu-button"]', - ); - await driver.clickElement({ text: 'Settings', tag: 'div' }); - await driver.clickElement({ text: 'Experimental', tag: 'div' }); + await loginWithBalanceValidation(driver); - await driver.waitForSelector({ - text: messages.bitcoinSupportToggleTitle.message, - tag: 'span', - }); + // go to experimental settings page and enable add new Bitcoin account toggle + const homePage = new HomePage(driver); + await homePage.check_pageIsLoaded(); + await homePage.check_expectedBalanceIsDisplayed(); - await driver.clickElement('[data-testid="bitcoin-support-toggle-div"]'); + await new HeaderNavbar(driver).openSettingsPage(); + const settingsPage = new SettingsPage(driver); + await settingsPage.check_pageIsLoaded(); + await settingsPage.goToExperimentalSettings(); - await driver.clickElement('button[aria-label="Close"]'); + const experimentalSettings = new ExperimentalSettings(driver); + await experimentalSettings.check_pageIsLoaded(); + await experimentalSettings.toggleBitcoinAccount(); + await settingsPage.closeSettingsPage(); - await driver.clickElement('[data-testid="account-menu-icon"]'); - await driver.clickElement( - '[data-testid="multichain-account-menu-popover-action-button"]', - ); - await driver.waitForSelector({ - text: messages.addNewBitcoinAccount.message, - tag: 'button', - }); + // check add new Bitcoin account button is displayed + await homePage.check_pageIsLoaded(); + await new HeaderNavbar(driver).openAccountMenu(); + const accountListPage = new AccountListPage(driver); + await accountListPage.check_pageIsLoaded(); + await accountListPage.check_addBitcoinAccountAvailable(true); }, ); }); diff --git a/test/e2e/page-objects/pages/account-list-page.ts b/test/e2e/page-objects/pages/account-list-page.ts index 5660dc616279..706f83a83865 100644 --- a/test/e2e/page-objects/pages/account-list-page.ts +++ b/test/e2e/page-objects/pages/account-list-page.ts @@ -365,6 +365,22 @@ class AccountListPage { }); } + async check_addBitcoinAccountAvailable( + expectedAvailability: boolean, + ): Promise { + console.log( + `Check add bitcoin account button is ${ + expectedAvailability ? 'displayed ' : 'not displayed' + }`, + ); + await this.openAddAccountModal(); + if (expectedAvailability) { + await this.driver.waitForSelector(this.addBtcAccountButton); + } else { + await this.driver.assertElementNotPresent(this.addBtcAccountButton); + } + } + async openAccountOptionsMenu(): Promise { console.log(`Open account option menu`); await this.driver.waitForSelector(this.accountListItem); diff --git a/test/e2e/page-objects/pages/home/bitcoin-homepage.ts b/test/e2e/page-objects/pages/home/bitcoin-homepage.ts index 5c5061f3b888..e3dff770b224 100644 --- a/test/e2e/page-objects/pages/home/bitcoin-homepage.ts +++ b/test/e2e/page-objects/pages/home/bitcoin-homepage.ts @@ -1,14 +1,13 @@ -import { Driver } from '../../../webdriver/driver'; -import HomePage from '../home/homepage'; +import HomePage from './homepage'; class BitcoinHomepage extends HomePage { - - protected readonly balance = '[data-testid="coin-overview__primary-currency"]'; + protected readonly balance = + '[data-testid="coin-overview__primary-currency"]'; private readonly bridgeButton = { text: 'Bridge', tag: 'button', - } + }; private readonly buySellButton = '[data-testid="coin-overview-buy"]'; @@ -19,11 +18,7 @@ class BitcoinHomepage extends HomePage { private readonly swapButton = { text: 'Swap', tag: 'button', - } - - constructor(driver: Driver) { - super(driver); - } + }; async check_pageIsLoaded(): Promise { try { @@ -55,13 +50,15 @@ class BitcoinHomepage extends HomePage { * * @param expectedBalance - The expected bitcoin balance to be displayed. Defaults to '0'. */ - async check_expectedBitcoinBalanceIsDisplayed( - expectedBalance: number = 0, - ): Promise { - console.log(`Check if expected bitcoin balance is displayed: ${expectedBalance} BTC`); - await this.driver.waitForSelector({ + async check_expectedBitcoinBalanceIsDisplayed( + expectedBalance: number = 0, + ): Promise { + console.log( + `Check if expected bitcoin balance is displayed: ${expectedBalance} BTC`, + ); + await this.driver.waitForSelector({ css: this.balance, - text: expectedBalance + 'BTC', + text: `${expectedBalance}BTC`, }); } diff --git a/test/e2e/page-objects/pages/home/homepage.ts b/test/e2e/page-objects/pages/home/homepage.ts index 3e8e3a387587..1bc7741f0cda 100644 --- a/test/e2e/page-objects/pages/home/homepage.ts +++ b/test/e2e/page-objects/pages/home/homepage.ts @@ -11,7 +11,8 @@ class HomePage { private readonly activityTab = '[data-testid="account-overview__activity-tab"]'; - protected readonly balance: string = '[data-testid="eth-overview__primary-currency"]'; + protected readonly balance: string = + '[data-testid="eth-overview__primary-currency"]'; private readonly basicFunctionalityOffWarningMessage = { text: 'Basic functionality is off', diff --git a/test/e2e/page-objects/pages/settings/experimental-settings.ts b/test/e2e/page-objects/pages/settings/experimental-settings.ts index 3af5c8a538e4..84de34c85172 100644 --- a/test/e2e/page-objects/pages/settings/experimental-settings.ts +++ b/test/e2e/page-objects/pages/settings/experimental-settings.ts @@ -1,4 +1,5 @@ import { Driver } from '../../../webdriver/driver'; +import messages from '../../../../../app/_locales/en/messages.json'; class ExperimentalSettings { private readonly driver: Driver; @@ -7,6 +8,9 @@ class ExperimentalSettings { private readonly addAccountSnapToggle = '[data-testid="add-account-snap-toggle-div"]'; + private readonly addBitcoinAccountToggle = + '[data-testid="bitcoin-support-toggle-div"]'; + private readonly experimentalPageTitle = { text: 'Experimental', tag: 'h4', @@ -32,6 +36,15 @@ class ExperimentalSettings { console.log('Experimental Settings page is loaded'); } + async toggleBitcoinAccount(): Promise { + console.log('Toggle Add new Bitcoin account on experimental setting page'); + await this.driver.waitForSelector({ + text: messages.bitcoinSupportToggleTitle.message, + tag: 'span', + }); + await this.driver.clickElement(this.addBitcoinAccountToggle); + } + async toggleAddAccountSnap(): Promise { console.log('Toggle Add Account Snap on experimental setting page'); await this.driver.clickElement(this.addAccountSnapToggle); diff --git a/test/e2e/page-objects/pages/test-dapp.ts b/test/e2e/page-objects/pages/test-dapp.ts index c31ee497152e..6898a5cec671 100644 --- a/test/e2e/page-objects/pages/test-dapp.ts +++ b/test/e2e/page-objects/pages/test-dapp.ts @@ -159,11 +159,6 @@ class TestDapp { tag: 'h2', }; - private readonly updateNetworkButton = { - text: 'Update', - tag: 'button', - }; - private readonly userRejectedRequestMessage = { tag: 'span', text: 'Error: User rejected the request.', @@ -270,23 +265,40 @@ class TestDapp { /** * Connect account to test dapp. * - * @param publicAddress - The public address to connect to test dapp. + * @param options - Options for connecting account to test dapp. + * @param [options.connectAccountButtonEnabled] - Indicates if the connect account button should be enabled. + * @param options.publicAddress - The public address to connect to test dapp. */ - async connectAccount(publicAddress: string) { + async connectAccount({ + connectAccountButtonEnabled = true, + publicAddress, + }: { + connectAccountButtonEnabled?: boolean; + publicAddress?: string; + }) { console.log('Connect account to test dapp'); await this.driver.clickElement(this.connectAccountButton); await this.driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); await this.driver.waitForSelector(this.connectMetaMaskMessage); + if (connectAccountButtonEnabled) { + await this.driver.clickElementAndWaitForWindowToClose( + this.confirmDialogButton, + ); + } else { + const confirmConnectDialogButton = await this.driver.findElement( + this.confirmDialogButton, + ); + assert.equal(await confirmConnectDialogButton.isEnabled(), false); + } - await this.driver.clickElementAndWaitForWindowToClose( - this.confirmDialogButton, - ); - await this.driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); - await this.driver.waitForSelector({ - css: this.connectedAccount, - text: publicAddress.toLowerCase(), - }); - await this.driver.waitForSelector(this.localhostNetworkMessage); + if (publicAddress) { + await this.driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + await this.driver.waitForSelector({ + css: this.connectedAccount, + text: publicAddress.toLowerCase(), + }); + await this.driver.waitForSelector(this.localhostNetworkMessage); + } } async createDepositTransaction() { diff --git a/test/e2e/tests/account/snap-account-signatures-and-disconnects.spec.ts b/test/e2e/tests/account/snap-account-signatures-and-disconnects.spec.ts index 7e355302212a..d3c177ff7fdd 100644 --- a/test/e2e/tests/account/snap-account-signatures-and-disconnects.spec.ts +++ b/test/e2e/tests/account/snap-account-signatures-and-disconnects.spec.ts @@ -56,7 +56,9 @@ describe('Snap Account Signatures and Disconnects @no-mmi', function (this: Suit // Disconnect from Test Dapp and reconnect to Test Dapp await testDapp.disconnectAccount(newPublicKey); - await testDapp.connectAccount(newPublicKey); + await testDapp.connectAccount({ + publicAddress: newPublicKey, + }); // SignTypedDataV4 with Test Dapp await signTypedDataV4WithSnapAccount(driver, newPublicKey, false, true); From 3faafa656c0c0a2dac3eb9570f48bcca2b48c6fa Mon Sep 17 00:00:00 2001 From: Chloe Gao Date: Mon, 9 Dec 2024 18:53:42 +0100 Subject: [PATCH 03/10] migrate tests --- .../flask/btc/btc-account-overview.spec.ts | 2 +- test/e2e/flask/btc/create-btc-account.spec.ts | 31 +- test/e2e/flask/create-watch-account.spec.ts | 1 + .../e2e/flask/create-watch-accountxxx.spec.ts | 463 ++++++++++++++++++ .../page-objects/pages/account-list-page.ts | 128 ++--- .../pages/dialog/account-details-modal.ts | 100 ++++ test/e2e/page-objects/pages/header-navbar.ts | 34 +- .../pages/home/bitcoin-homepage.ts | 2 +- test/e2e/page-objects/pages/home/homepage.ts | 44 ++ .../tests/account/account-custom-name.spec.ts | 8 +- test/e2e/tests/account/import-flow.spec.ts | 5 +- .../sync-after-modifying-account-name.spec.ts | 7 +- .../sync-with-account-balances.spec.ts | 8 +- 13 files changed, 717 insertions(+), 116 deletions(-) create mode 100644 test/e2e/flask/create-watch-accountxxx.spec.ts create mode 100644 test/e2e/page-objects/pages/dialog/account-details-modal.ts diff --git a/test/e2e/flask/btc/btc-account-overview.spec.ts b/test/e2e/flask/btc/btc-account-overview.spec.ts index 39ee125b70b1..c180b0b02c3d 100644 --- a/test/e2e/flask/btc/btc-account-overview.spec.ts +++ b/test/e2e/flask/btc/btc-account-overview.spec.ts @@ -13,7 +13,7 @@ describe('BTC Account - Overview', function (this: Suite) { await homePage.check_pageIsLoaded(); await homePage.headerNavbar.check_accountLabel('Bitcoin Account'); - assert.equal(await homePage.check_ifBridgeButtonIsDisabled(), false); + assert.equal(await homePage.check_ifBridgeButtonIsClickable(), false); assert.equal(await homePage.check_ifSwapButtonIsClickable(), false); assert.equal(await homePage.check_ifBuySellButtonIsClickable(), true); assert.equal(await homePage.check_ifReceiveButtonIsClickable(), true); diff --git a/test/e2e/flask/btc/create-btc-account.spec.ts b/test/e2e/flask/btc/create-btc-account.spec.ts index 0dfb24a8a931..6cb62c3a5e1d 100644 --- a/test/e2e/flask/btc/create-btc-account.spec.ts +++ b/test/e2e/flask/btc/create-btc-account.spec.ts @@ -1,6 +1,7 @@ import { strict as assert } from 'assert'; import { Suite } from 'mocha'; import { WALLET_PASSWORD } from '../../helpers'; +import AccountDetailsModal from '../../page-objects/pages/dialog/account-details-modal'; import AccountListPage from '../../page-objects/pages/account-list-page'; import HeaderNavbar from '../../page-objects/pages/header-navbar'; import LoginPage from '../../page-objects/pages/login-page'; @@ -83,9 +84,11 @@ describe('Create BTC Account', function (this: Suite) { await headerNavbar.openAccountMenu(); const accountListPage = new AccountListPage(driver); await accountListPage.check_pageIsLoaded(); - const accountAddress = await accountListPage.getAccountAddress( - 'Bitcoin Account', - ); + await accountListPage.openAccountDetailsModal('Bitcoin Account'); + + const accountDetailsModal = new AccountDetailsModal(driver); + await accountDetailsModal.check_pageIsLoaded(); + const accountAddress = await accountDetailsModal.getAccountAddress(); await headerNavbar.openAccountMenu(); await accountListPage.removeAccount('Bitcoin Account'); @@ -97,16 +100,16 @@ describe('Create BTC Account', function (this: Suite) { await headerNavbar.openAccountMenu(); await accountListPage.check_pageIsLoaded(); - const recreatedAccountAddress = await accountListPage.getAccountAddress( - 'Bitcoin Account', - ); + await accountListPage.openAccountDetailsModal('Bitcoin Account'); + await accountDetailsModal.check_pageIsLoaded(); + const recreatedAccountAddress = await accountDetailsModal.getAccountAddress(); assert(accountAddress === recreatedAccountAddress); }, ); }); - it('can recreate BTC account after restoring wallet with SRP', async function () { + it.only('can recreate BTC account after restoring wallet with SRP', async function () { await withBtcAccountSnap( { title: this.test?.fullTitle() }, async (driver) => { @@ -118,9 +121,10 @@ describe('Create BTC Account', function (this: Suite) { await headerNavbar.openAccountMenu(); const accountListPage = new AccountListPage(driver); await accountListPage.check_pageIsLoaded(); - const accountAddress = await accountListPage.getAccountAddress( - 'Bitcoin Account', - ); + await accountListPage.openAccountDetailsModal('Bitcoin Account'); + const accountDetailsModal = new AccountDetailsModal(driver); + await accountDetailsModal.check_pageIsLoaded(); + const accountAddress = await accountDetailsModal.getAccountAddress(); // go to privacy settings page and get the SRP await headerNavbar.openSettingsPage(); @@ -151,9 +155,10 @@ describe('Create BTC Account', function (this: Suite) { await headerNavbar.openAccountMenu(); await accountListPage.check_pageIsLoaded(); - const recreatedAccountAddress = await accountListPage.getAccountAddress( - 'Bitcoin Account', - ); + await accountListPage.openAccountDetailsModal('Bitcoin Account'); + await accountDetailsModal.check_pageIsLoaded(); + const recreatedAccountAddress = await accountDetailsModal.getAccountAddress(); + assert(accountAddress === recreatedAccountAddress); }, ); diff --git a/test/e2e/flask/create-watch-account.spec.ts b/test/e2e/flask/create-watch-account.spec.ts index 71d47327536c..7202d948a233 100644 --- a/test/e2e/flask/create-watch-account.spec.ts +++ b/test/e2e/flask/create-watch-account.spec.ts @@ -24,6 +24,7 @@ async function startCreateWatchAccountFlow( await unlockWallet(driver); } + await driver.clickElement('[data-testid="account-menu-icon"]'); await driver.clickElement( '[data-testid="multichain-account-menu-popover-action-button"]', diff --git a/test/e2e/flask/create-watch-accountxxx.spec.ts b/test/e2e/flask/create-watch-accountxxx.spec.ts new file mode 100644 index 000000000000..05500e8abc77 --- /dev/null +++ b/test/e2e/flask/create-watch-accountxxx.spec.ts @@ -0,0 +1,463 @@ +import { strict as assert } from 'assert'; +import { Suite } from 'mocha'; +import messages from '../../../app/_locales/en/messages.json'; +import FixtureBuilder from '../fixture-builder'; +import { defaultGanacheOptions, unlockWallet, withFixtures } from '../helpers'; +import { Driver } from '../webdriver/driver'; + +import AccountDetailsModal from '../page-objects/pages/dialog/account-details-modal'; +import AccountListPage from '../page-objects/pages/account-list-page'; +import HomePage from '../page-objects/pages/home/homepage'; +import { loginWithBalanceValidation } from '../page-objects/flows/login.flow'; + +const ACCOUNT_1 = '0x5CfE73b6021E818B776b421B1c4Db2474086a7e1'; +const EOA_ADDRESS = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'; +const SHORTENED_EOA_ADDRESS = '0xd8dA6...96045'; +const DEFAULT_WATCHED_ACCOUNT_NAME = 'Watched Account 1'; + +/** + * Start the flow to create a watch account by clicking the account menu and selecting the option to add a watch account. + * + * @param driver - The WebDriver instance used to control the browser. + * @param unlockWalletFirst - Whether to unlock the wallet before starting the flow. + */ +async function startCreateWatchAccountFlow( + driver: Driver, + unlockWalletFirst: boolean = true, +): Promise { + if (unlockWalletFirst) { + await loginWithBalanceValidation(driver); + } + + const homePage = new HomePage(driver); + await homePage.check_pageIsLoaded(); + + await homePage.headerNavbar.openAccountMenu(); + const accountListPage = new AccountListPage(driver); + await accountListPage.check_pageIsLoaded(); + + + await driver.clickElement( + '[data-testid="multichain-account-menu-popover-add-watch-only-account"]', + ); +} + +/** + * Watches an EOA address. + * + * @param driver - The WebDriver instance used to control the browser. + * @param unlockWalletFirst - Whether to unlock the wallet before watching the address. + * @param address - The EOA address to watch. + */ +async function watchEoaAddress( + driver: Driver, + unlockWalletFirst: boolean = true, + address: string = EOA_ADDRESS, +): Promise { + await startCreateWatchAccountFlow(driver, unlockWalletFirst); + await driver.fill('input#address-input[type="text"]', address); + await driver.clickElement({ text: 'Watch account', tag: 'button' }); + await driver.clickElement('[data-testid="submit-add-account-with-name"]'); +} + +/** + * Removes the selected account. + * + * @param driver - The WebDriver instance used to control the browser. + */ +async function removeSelectedAccount(driver: Driver): Promise { + await driver.clickElement('[data-testid="account-menu-icon"]'); + await driver.clickElement( + '.multichain-account-list-item--selected [data-testid="account-list-item-menu-button"]', + ); + await driver.clickElement('[data-testid="account-list-menu-remove"]'); + await driver.clickElement({ text: 'Remove', tag: 'button' }); +} + +describe('Account-watcher snap', function (this: Suite) { + describe('Adding watched accounts', function () { + it('adds watch account with valid EOA address', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder() + .withPreferencesControllerAndFeatureFlag({ + watchEthereumAccountEnabled: true, + }) + .withNetworkControllerOnMainnet() + .build(), + title: this.test?.fullTitle(), + }, + async ({ driver }: { driver: Driver }) => { + await loginWithBalanceValidation(driver); + const homePage = new HomePage(driver); + await homePage.check_pageIsLoaded(); + await homePage.check_expectedBalanceIsDisplayed(); + + // watch an EOA address + await homePage.headerNavbar.openAccountMenu(); + const accountListPage = new AccountListPage(driver); + await accountListPage.check_pageIsLoaded(); + await accountListPage.addEoaAccount(EOA_ADDRESS); + + // new account should be displayed in the account list + await homePage.check_pageIsLoaded(); + await homePage.headerNavbar.check_accountLabel(DEFAULT_WATCHED_ACCOUNT_NAME); + await homePage.headerNavbar.check_accountAddress(SHORTENED_EOA_ADDRESS); + }, + ); + }); + + it("disables 'Send' 'Swap' and 'Bridge' buttons for watch accounts", async function () { + await withFixtures( + { + fixtures: new FixtureBuilder() + .withPreferencesControllerAndFeatureFlag({ + watchEthereumAccountEnabled: true, + }) + .withNetworkControllerOnMainnet() + .build(), + title: this.test?.fullTitle(), + }, + async ({ driver }: { driver: Driver }) => { + await loginWithBalanceValidation(driver); + const homePage = new HomePage(driver); + await homePage.check_pageIsLoaded(); + await homePage.check_expectedBalanceIsDisplayed(); + + // watch an EOA address + await homePage.headerNavbar.openAccountMenu(); + const accountListPage = new AccountListPage(driver); + await accountListPage.check_pageIsLoaded(); + await accountListPage.addEoaAccount(EOA_ADDRESS); + await homePage.check_pageIsLoaded(); + await homePage.headerNavbar.check_accountLabel(DEFAULT_WATCHED_ACCOUNT_NAME); + + // 'Send' button should be disabled + assert.equal(await homePage.check_ifSendButtonIsClickable(), false); + + // 'Swap' button should be disabled + assert.equal(await homePage.check_ifSwapButtonIsClickable(), false); + + // 'Bridge' button should be disabled + assert.equal(await homePage.check_ifBridgeButtonIsClickable(), false); + + // check tooltips for disabled buttons + await homePage.check_disabledButtonTooltip("Not supported with this account."); + }, + ); + }); + }); + + describe('Invalid input handling', function () { + const invalidInputTests = [ + { + input: 'd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', + message: 'Invalid input', + description: 'address missing 0x prefix', + }, + { + input: '0x123ABC', + message: 'Invalid address', + description: 'invalid address', + }, + { + input: 'invalid.eth', + message: 'Invalid ENS name', + description: 'invalid ENS name', + }, + { + input: ACCOUNT_1, + // FIXME: Watchout, the Snap bridge will lower-case EVM addresses, even in some error messages, this is + // a mistake, and we might wanna re-change that later, see: + // - https://github.com/MetaMask/accounts/pull/90/files#r1848713364 + message: `Unknown snap error: Account address '${ACCOUNT_1.toLowerCase()}' already exists`, + description: 'existing address', + }, + ]; + + invalidInputTests.forEach(({ input, message, description }) => { + it(`handles invalid input: ${description}`, async function () { + await withFixtures( + { + fixtures: new FixtureBuilder() + .withPreferencesControllerAndFeatureFlag({ + watchEthereumAccountEnabled: true, + }) + .withNetworkControllerOnMainnet() + .build(), + title: this.test?.fullTitle(), + }, + async ({ driver }: { driver: Driver }) => { + await loginWithBalanceValidation(driver); + const homePage = new HomePage(driver); + await homePage.check_pageIsLoaded(); + await homePage.check_expectedBalanceIsDisplayed(); + + // error message should be displayed by snap when try to watch an EOA with invalid input + await homePage.headerNavbar.openAccountMenu(); + const accountListPage = new AccountListPage(driver); + await accountListPage.check_pageIsLoaded(); + await accountListPage.addEoaAccount(input, message); + }, + ); + }); + }); + }); + + describe('Account management', function () { + it('does not allow user to import private key of watched address', async function () { + const PRIVATE_KEY_TWO = + '0xf444f52ea41e3a39586d7069cb8e8233e9f6b9dea9cbb700cce69ae860661cc8'; + const ACCOUNT_2 = '0x09781764c08de8ca82e156bbf156a3ca217c7950'; + + await withFixtures( + { + fixtures: new FixtureBuilder() + .withPreferencesControllerAndFeatureFlag({ + watchEthereumAccountEnabled: true, + }) + .withNetworkControllerOnMainnet() + .build(), + title: this.test?.fullTitle(), + }, + async ({ driver }: { driver: Driver }) => { + await loginWithBalanceValidation(driver); + const homePage = new HomePage(driver); + await homePage.check_pageIsLoaded(); + await homePage.check_expectedBalanceIsDisplayed(); + + // watch an EOA address for ACCOUNT_2 + await homePage.headerNavbar.openAccountMenu(); + const accountListPage = new AccountListPage(driver); + await accountListPage.check_pageIsLoaded(); + await accountListPage.addEoaAccount(ACCOUNT_2); + await homePage.check_pageIsLoaded(); + await homePage.headerNavbar.check_accountLabel(DEFAULT_WATCHED_ACCOUNT_NAME); + + // try to import private key of watched ACCOUNT_2 address and check error message + await homePage.headerNavbar.openAccountMenu(); + await accountListPage.check_pageIsLoaded(); + await accountListPage.addNewImportedAccount( + PRIVATE_KEY_TWO, + 'KeyringController - The account you are trying to import is a duplicate', + ); + }, + ); + }); + + it("does not display 'Show private key' button for watch accounts", async function () { + await withFixtures( + { + fixtures: new FixtureBuilder() + .withPreferencesControllerAndFeatureFlag({ + watchEthereumAccountEnabled: true, + }) + .withNetworkControllerOnMainnet() + .build(), + title: this.test?.fullTitle(), + }, + async ({ driver }: { driver: Driver }) => { + await loginWithBalanceValidation(driver); + const homePage = new HomePage(driver); + await homePage.check_pageIsLoaded(); + await homePage.check_expectedBalanceIsDisplayed(); + + // watch an EOA address for ACCOUNT_2 + await homePage.headerNavbar.openAccountMenu(); + const accountListPage = new AccountListPage(driver); + await accountListPage.check_pageIsLoaded(); + await accountListPage.addEoaAccount(EOA_ADDRESS); + await homePage.check_pageIsLoaded(); + + // open account details modal in header navbar + await homePage.headerNavbar.check_accountLabel(DEFAULT_WATCHED_ACCOUNT_NAME); + await homePage.headerNavbar.openAccountDetailsModal(); + + // check 'Show private key' button should not be displayed + const accountDetailsModal = new AccountDetailsModal(driver); + await accountDetailsModal.check_pageIsLoaded(); + await accountDetailsModal.check_showPrivateKeyButtonIsNotDisplayed(); + }, + ); + }); + + it.only('removes a watched account', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder() + .withPreferencesControllerAndFeatureFlag({ + watchEthereumAccountEnabled: true, + }) + .withNetworkControllerOnMainnet() + .build(), + ganacheOptions: defaultGanacheOptions, + title: this.test?.fullTitle(), + }, + async ({ driver }: { driver: Driver }) => { + // watch an EOA address + await watchEoaAddress(driver); + throw new Error('Not implemented'); + // remove the selected watched account + await removeSelectedAccount(driver); + + // account should be removed from the account list + await driver.assertElementNotPresent({ + css: '[data-testid="account-menu-icon"]', + text: DEFAULT_WATCHED_ACCOUNT_NAME, + }); + await driver.assertElementNotPresent({ + css: '.mm-text--ellipsis', + text: SHORTENED_EOA_ADDRESS, + }); + }, + ); + }); + + it('can remove and recreate a watched account', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder() + .withPreferencesControllerAndFeatureFlag({ + watchEthereumAccountEnabled: true, + }) + .withNetworkControllerOnMainnet() + .build(), + ganacheOptions: defaultGanacheOptions, + title: this.test?.fullTitle(), + }, + async ({ driver }: { driver: Driver }) => { + // watch an EOA address + await watchEoaAddress(driver); + + // remove the selected watched account + await removeSelectedAccount(driver); + + // account should be removed from the account list + await driver.assertElementNotPresent({ + css: '[data-testid="account-menu-icon"]', + text: DEFAULT_WATCHED_ACCOUNT_NAME, + }); + await driver.assertElementNotPresent({ + css: '.mm-text--ellipsis', + text: SHORTENED_EOA_ADDRESS, + }); + + // watch the same EOA address again + await watchEoaAddress(driver, false); + + // same account should be displayed in the account list + await driver.findElement({ + css: '[data-testid="account-menu-icon"]', + text: DEFAULT_WATCHED_ACCOUNT_NAME, + }); + await driver.findElement({ + css: '.mm-text--ellipsis', + text: SHORTENED_EOA_ADDRESS, + }); + }, + ); + }); + }); + + describe('Experimental toggle', function () { + const navigateToExperimentalSettings = async (driver: Driver) => { + await driver.clickElement('[data-testid="account-options-menu-button"]'); + await driver.clickElement({ text: 'Settings', tag: 'div' }); + await driver.clickElement({ text: 'Experimental', tag: 'div' }); + await driver.waitForSelector({ + text: messages.watchEthereumAccountsToggle.message, + tag: 'span', + }); + }; + + const getToggleState = async (driver: Driver): Promise => { + const toggleInput = await driver.findElement( + '[data-testid="watch-account-toggle"]', + ); + return toggleInput.isSelected(); + }; + + const toggleWatchAccountOptionAndCloseSettings = async (driver: Driver) => { + await driver.clickElement('[data-testid="watch-account-toggle-div"]'); + await driver.clickElement('button[aria-label="Close"]'); + }; + + const verifyWatchAccountOptionAndCloseMenu = async ( + driver: Driver, + shouldBePresent: boolean, + ) => { + await driver.clickElement('[data-testid="account-menu-icon"]'); + await driver.clickElement( + '[data-testid="multichain-account-menu-popover-action-button"]', + ); + if (shouldBePresent) { + await driver.waitForSelector({ + text: messages.addEthereumWatchOnlyAccount.message, + tag: 'button', + }); + } else { + await driver.assertElementNotPresent({ + text: messages.addEthereumWatchOnlyAccount.message, + tag: 'button', + }); + } + await driver.clickElement('button[aria-label="Close"]'); + }; + + it("will show the 'Watch an Ethereum account (Beta)' option when setting is enabled", async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions: defaultGanacheOptions, + title: this.test?.fullTitle(), + }, + async ({ driver }) => { + await unlockWallet(driver); + await navigateToExperimentalSettings(driver); + + // verify toggle is off by default + assert.equal( + await getToggleState(driver), + false, + 'Toggle should be off by default', + ); + + // enable the toggle + await toggleWatchAccountOptionAndCloseSettings(driver); + + // verify the 'Watch and Ethereum account (Beta)' option is available + await verifyWatchAccountOptionAndCloseMenu(driver, true); + }, + ); + }); + + it('enables and then disables the toggle and the option to add a watch-only account behaves as expected', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions: defaultGanacheOptions, + title: this.test?.fullTitle(), + }, + async ({ driver }) => { + await unlockWallet(driver); + await navigateToExperimentalSettings(driver); + + // enable the toggle + await toggleWatchAccountOptionAndCloseSettings(driver); + + // verify the 'Watch and Ethereum account (Beta)' option is available + await verifyWatchAccountOptionAndCloseMenu(driver, true); + + // navigate back to experimental settings + await navigateToExperimentalSettings(driver); + + // disable the toggle + await toggleWatchAccountOptionAndCloseSettings(driver); + + // verify the 'Watch and Ethereum account (Beta)' option is not available + await verifyWatchAccountOptionAndCloseMenu(driver, false); + }, + ); + }); + }); +}); diff --git a/test/e2e/page-objects/pages/account-list-page.ts b/test/e2e/page-objects/pages/account-list-page.ts index 706f83a83865..bf5493998ac6 100644 --- a/test/e2e/page-objects/pages/account-list-page.ts +++ b/test/e2e/page-objects/pages/account-list-page.ts @@ -6,8 +6,6 @@ import messages from '../../../../app/_locales/en/messages.json'; class AccountListPage { private readonly driver: Driver; - private readonly accountAddressText = '.qr-code__address-segments'; - private readonly accountListBalance = '[data-testid="second-currency-display"]'; @@ -25,10 +23,6 @@ class AccountListPage { private readonly accountOptionsMenuButton = '[data-testid="account-list-item-menu-button"]'; - private readonly accountQrCodeImage = '.qr-code__wrapper'; - - private readonly accountQrCodeAddress = '.qr-code__address-segments'; - private readonly addAccountConfirmButton = '[data-testid="submit-add-account-with-name"]'; @@ -40,6 +34,9 @@ class AccountListPage { private readonly addEthereumAccountButton = '[data-testid="multichain-account-menu-popover-add-account"]'; + private readonly addEoaAccountButton = + '[data-testid="multichain-account-menu-popover-add-watch-only-account"]'; + private readonly addImportedAccountButton = '[data-testid="multichain-account-menu-popover-add-imported-account"]'; @@ -56,11 +53,6 @@ class AccountListPage { private readonly currentSelectedAccount = '.multichain-account-list-item--selected'; - private readonly editableLabelButton = - '[data-testid="editable-label-button"]'; - - private readonly editableLabelInput = '[data-testid="editable-input"] input'; - private readonly hiddenAccountOptionsMenuButton = '.multichain-account-menu-popover__list--menu-item-hidden-account [data-testid="account-list-item-menu-button"]'; @@ -110,8 +102,17 @@ class AccountListPage { tag: 'button', }; - private readonly saveAccountLabelButton = - '[data-testid="save-account-label-input"]'; + private readonly watchAccountModalTitle = { + text: 'Watch any Ethereum account', + tag: 'h4', + }; + + private readonly watchAccountAddressInput = 'input#address-input[type="text"]'; + + private readonly watchAccountConfirmButton = { + text: 'Watch account', + tag: 'button', + }; constructor(driver: Driver) { this.driver = driver; @@ -130,6 +131,32 @@ class AccountListPage { console.log('Account list is loaded'); } + /** + * Watch an EOA (external owned account). + * + * @param address - The address to watch. + * @param expectedErrorMessage - Optional error message to display if the address is invalid. + */ + async addEoaAccount(address: string, expectedErrorMessage: string = ''): Promise { + console.log(`Watch EOA account with address ${address}`); + await this.driver.clickElement(this.createAccountButton); + await this.driver.clickElement(this.addEoaAccountButton); + await this.driver.waitForSelector(this.watchAccountModalTitle); + await this.driver.fill(this.watchAccountAddressInput, address); + await this.driver.clickElement(this.watchAccountConfirmButton); + if (expectedErrorMessage) { + console.log( + `Check if error message is displayed: ${expectedErrorMessage}`, + ); + await this.driver.waitForSelector({ + css: '.snap-ui-renderer__text', + text: expectedErrorMessage, + }); + } else { + await this.driver.clickElement(this.addAccountConfirmButton); + } + } + /** * Adds a new account with an optional custom label. * @@ -225,47 +252,6 @@ class AccountListPage { } } - /** - * Changes the label of the current account. - * - * @param newLabel - The new label to set for the account. - */ - async changeAccountLabel(newLabel: string): Promise { - console.log(`Changing account label to: ${newLabel}`); - await this.driver.clickElement(this.accountMenuButton); - await this.changeLabelFromAccountDetailsModal(newLabel); - } - - /** - * Changes the account label from within an already opened account details modal. - * Note: This method assumes the account details modal is already open. - * - * Recommended usage: - * ```typescript - * await accountListPage.openAccountDetailsModal('Current Account Name'); - * await accountListPage.changeLabelFromAccountDetailsModal('New Account Name'); - * ``` - * - * @param newLabel - The new label to set for the account - * @throws Will throw an error if the modal is not open when method is called - * @example - * // To rename a specific account, first open its details modal: - * await accountListPage.openAccountDetailsModal('Current Account Name'); - * await accountListPage.changeLabelFromAccountDetailsModal('New Account Name'); - * - * // Note: Using changeAccountLabel() alone will only work for the first account - */ - async changeLabelFromAccountDetailsModal(newLabel: string): Promise { - await this.driver.waitForSelector(this.editableLabelButton); - console.log( - `Account details modal opened, changing account label to: ${newLabel}`, - ); - await this.driver.clickElement(this.editableLabelButton); - await this.driver.fill(this.editableLabelInput, newLabel); - await this.driver.clickElement(this.saveAccountLabelButton); - await this.driver.clickElement(this.closeAccountModalButton); - } - async closeAccountModal(): Promise { console.log(`Close account modal in account list`); await this.driver.clickElementAndWaitToDisappear( @@ -273,23 +259,6 @@ class AccountListPage { ); } - /** - * Get the address of the specified account. - * - * @param accountLabel - The label of the account to get the address. - */ - async getAccountAddress(accountLabel: string): Promise { - console.log(`Get account address in account list`); - await this.openAccountOptionsInAccountList(accountLabel); - await this.driver.clickElement(this.accountMenuButton); - await this.driver.waitForSelector(this.accountAddressText); - const accountAddress = await ( - await this.driver.findElement(this.accountAddressText) - ).getText(); - await this.driver.clickElement(this.closeAccountModalButton); - return accountAddress; - } - async hideAccount(): Promise { console.log(`Hide account in account list`); await this.driver.clickElement(this.hideUnhideAccountButton); @@ -515,23 +484,6 @@ class AccountListPage { await this.driver.assertElementNotPresent(this.addSnapAccountButton); } - /** - * Check that the correct address is displayed in the account details modal. - * - * @param expectedAddress - The expected address to check. - */ - async check_addressInAccountDetailsModal( - expectedAddress: string, - ): Promise { - console.log( - `Check that address ${expectedAddress} is displayed in account details modal`, - ); - await this.driver.waitForSelector(this.accountQrCodeImage); - await this.driver.waitForSelector({ - css: this.accountQrCodeAddress, - text: expectedAddress, - }); - } async check_currentAccountIsImported(): Promise { console.log(`Check that current account is an imported account`); diff --git a/test/e2e/page-objects/pages/dialog/account-details-modal.ts b/test/e2e/page-objects/pages/dialog/account-details-modal.ts new file mode 100644 index 000000000000..65c59b127316 --- /dev/null +++ b/test/e2e/page-objects/pages/dialog/account-details-modal.ts @@ -0,0 +1,100 @@ +import { Driver } from '../../../webdriver/driver'; + +class AccountDetailsModal { + private driver: Driver; + private readonly accountAddressText = '.qr-code__address-segments'; + private readonly accountQrCodeAddress = '.qr-code__address-segments'; + private readonly accountQrCodeImage = '.qr-code__wrapper'; + private readonly closeAccountModalButton = 'button[aria-label="Close"]'; + private readonly copyAddressButton = '[data-testid="address-copy-button-text"]'; + private readonly editableLabelButton = '[data-testid="editable-label-button"]'; + private readonly editableLabelInput = '[data-testid="editable-input"] input'; + private readonly saveAccountLabelButton = + '[data-testid="save-account-label-input"]'; + + private readonly showPrivateKeyButton = { + css: 'button', + text: 'Show private key', + } + + constructor(driver: Driver) { + this.driver = driver; + } + + async check_pageIsLoaded(): Promise { + try { + await this.driver.waitForMultipleSelectors([ + this.editableLabelButton, + this.copyAddressButton, + ]); + } catch (e) { + console.log( + 'Timeout while waiting for account details modal to be loaded', + e, + ); + throw e; + } + console.log('Account details modal is loaded'); + } + + async closeAccountDetailsModal(): Promise { + await this.driver.clickElementAndWaitToDisappear(this.closeAccountModalButton); + } + + /** + * Change the label of the account in the account details modal. + * + * @param newLabel - The new label to set for the account. + */ + async changeAccountLabel(newLabel: string): Promise { + console.log( + `Account details modal opened, changing account label to: ${newLabel}`, + ); + await this.driver.clickElement(this.editableLabelButton); + await this.driver.fill(this.editableLabelInput, newLabel); + await this.driver.clickElement(this.saveAccountLabelButton); + await this.closeAccountDetailsModal(); + } + + /** + * Get the address of the specified account. + * + * @param accountLabel - The label of the account to get the address. + */ + async getAccountAddress(): Promise { + console.log(`Get account address in account list`); + await this.driver.waitForSelector(this.accountAddressText); + const accountAddress = await ( + await this.driver.findElement(this.accountAddressText) + ).getText(); + await this.closeAccountDetailsModal(); + return accountAddress; + } + + /** + * Check that the correct address is displayed in the account details modal. + * + * @param expectedAddress - The expected address to check. + */ + async check_addressInAccountDetailsModal( + expectedAddress: string, + ): Promise { + console.log( + `Check that address ${expectedAddress} is displayed in account details modal`, + ); + await this.driver.waitForSelector(this.accountQrCodeImage); + await this.driver.waitForSelector({ + css: this.accountQrCodeAddress, + text: expectedAddress, + }); + } + + async check_showPrivateKeyButtonIsNotDisplayed(): Promise { + console.log('Check that show private key button is not displayed'); + await this.driver.assertElementNotPresent(this.showPrivateKeyButton); + } + + +} + +export default AccountDetailsModal; diff --git a/test/e2e/page-objects/pages/header-navbar.ts b/test/e2e/page-objects/pages/header-navbar.ts index 5ef28e25b90a..848d144ee5c2 100644 --- a/test/e2e/page-objects/pages/header-navbar.ts +++ b/test/e2e/page-objects/pages/header-navbar.ts @@ -5,6 +5,8 @@ class HeaderNavbar { private readonly accountMenuButton = '[data-testid="account-menu-icon"]'; + private readonly copyAddressButton = '[data-testid="app-header-copy-button"]'; + private readonly threeDotMenuButton = '[data-testid="account-options-menu-button"]'; @@ -15,6 +17,8 @@ class HeaderNavbar { private readonly mmiPortfolioButton = '[data-testid="global-menu-mmi-portfolio"]'; + private readonly openAccountDetailsButton = '[data-testid="account-list-menu-details"]'; + private readonly settingsButton = '[data-testid="global-menu-settings"]'; private readonly switchNetworkDropDown = '[data-testid="network-display"]'; @@ -45,6 +49,12 @@ class HeaderNavbar { await this.driver.clickElement(this.accountMenuButton); } + async openAccountDetailsModal(): Promise { + console.log('Open account details modal'); + await this.openThreeDotMenu(); + await this.driver.clickElement(this.openAccountDetailsButton); + } + async openThreeDotMenu(): Promise { console.log('Open account options menu'); await this.driver.clickElement(this.threeDotMenuButton); @@ -71,11 +81,19 @@ class HeaderNavbar { await this.driver.clickElement(this.switchNetworkDropDown); } - async check_currentSelectedNetwork(networkName: string): Promise { - console.log(`Validate the Switch network to ${networkName}`); - await this.driver.waitForSelector( - `button[data-testid="network-display"][aria-label="Network Menu ${networkName}"]`, + /** + * Verifies that the displayed account address in header matches the expected address. + * + * @param expectedAddress - The expected address of the account. + */ + async check_accountAddress(expectedAddress: string): Promise { + console.log( + `Verify the displayed account address in header is: ${expectedAddress}`, ); + await this.driver.waitForSelector({ + css: this.copyAddressButton, + text: expectedAddress, + }); } /** @@ -92,6 +110,14 @@ class HeaderNavbar { text: expectedLabel, }); } + + async check_currentSelectedNetwork(networkName: string): Promise { + console.log(`Validate the Switch network to ${networkName}`); + await this.driver.waitForSelector( + `button[data-testid="network-display"][aria-label="Network Menu ${networkName}"]`, + ); + } + } export default HeaderNavbar; diff --git a/test/e2e/page-objects/pages/home/bitcoin-homepage.ts b/test/e2e/page-objects/pages/home/bitcoin-homepage.ts index e3dff770b224..0ffb8406bf14 100644 --- a/test/e2e/page-objects/pages/home/bitcoin-homepage.ts +++ b/test/e2e/page-objects/pages/home/bitcoin-homepage.ts @@ -34,7 +34,7 @@ class BitcoinHomepage extends HomePage { console.log('Bitcoin homepage is loaded'); } - async check_ifBridgeButtonIsDisabled(): Promise { + async check_ifBridgeButtonIsClickable(): Promise { try { await this.driver.findClickableElement(this.bridgeButton, 1000); } catch (e) { diff --git a/test/e2e/page-objects/pages/home/homepage.ts b/test/e2e/page-objects/pages/home/homepage.ts index 1bc7741f0cda..48d9e02636ed 100644 --- a/test/e2e/page-objects/pages/home/homepage.ts +++ b/test/e2e/page-objects/pages/home/homepage.ts @@ -19,6 +19,8 @@ class HomePage { css: '.mm-banner-alert', }; + protected readonly bridgeButton = '[data-testid="eth-overview-bridge"]'; + private readonly closeUseNetworkNotificationModalButton = { text: 'Got it', tag: 'h6', @@ -32,6 +34,8 @@ class HomePage { protected readonly sendButton: string = '[data-testid="eth-overview-send"]'; + protected readonly swapButton = '[data-testid="token-overview-button-swap"]'; + private readonly tokensTab = '[data-testid="account-overview__asset-tab"]'; constructor(driver: Driver) { @@ -106,6 +110,13 @@ class HomePage { await this.driver.waitForSelector(this.basicFunctionalityOffWarningMessage); } + async check_disabledButtonTooltip(tooltipText: string): Promise { + console.log(`Check if disabled button tooltip is displayed on homepage`); + await this.driver.waitForSelector( + `.icon-button--disabled [data-tooltipped][data-original-title="${tooltipText}"]`, + ); + } + /** * Checks if the toaster message for editing a network is displayed on the homepage. * @@ -161,6 +172,39 @@ class HomePage { }, 10000); } + async check_ifBridgeButtonIsClickable(): Promise { + try { + await this.driver.findClickableElement(this.bridgeButton, 1000); + } catch (e) { + console.log('Bridge button not clickable', e); + return false; + } + console.log('Bridge button is clickable'); + return true; + } + + async check_ifSendButtonIsClickable(): Promise { + try { + await this.driver.findClickableElement(this.sendButton, 1000); + } catch (e) { + console.log('Send button not clickable', e); + return false; + } + console.log('Send button is clickable'); + return true; + } + + async check_ifSwapButtonIsClickable(): Promise { + try { + await this.driver.findClickableElement(this.swapButton, 1000); + } catch (e) { + console.log('Swap button not clickable', e); + return false; + } + console.log('Swap button is clickable'); + return true; + } + async check_localBlockchainBalanceIsDisplayed( localBlockchainServer?: Ganache, address = null, diff --git a/test/e2e/tests/account/account-custom-name.spec.ts b/test/e2e/tests/account/account-custom-name.spec.ts index 4c0ecbe196f9..776b182f7956 100644 --- a/test/e2e/tests/account/account-custom-name.spec.ts +++ b/test/e2e/tests/account/account-custom-name.spec.ts @@ -3,6 +3,7 @@ import { Driver } from '../../webdriver/driver'; import { withFixtures } from '../../helpers'; import FixtureBuilder from '../../fixture-builder'; import { loginWithBalanceValidation } from '../../page-objects/flows/login.flow'; +import AccountDetailsModal from '../../page-objects/pages/dialog/account-details-modal'; import AccountListPage from '../../page-objects/pages/account-list-page'; import HeaderNavbar from '../../page-objects/pages/header-navbar'; @@ -25,8 +26,11 @@ describe('Account Custom Name Persistence', function (this: Suite) { // Change account label for existing account and verify edited account label const accountListPage = new AccountListPage(driver); await accountListPage.check_pageIsLoaded(); - await accountListPage.openAccountOptionsMenu(); - await accountListPage.changeAccountLabel(newAccountLabel); + await accountListPage.openAccountDetailsModal('Account 1'); + + const accountDetailsModal = new AccountDetailsModal(driver); + await accountDetailsModal.check_pageIsLoaded(); + await accountDetailsModal.changeAccountLabel(newAccountLabel); await headerNavbar.check_accountLabel(newAccountLabel); // Add new account with custom label and verify new added account label diff --git a/test/e2e/tests/account/import-flow.spec.ts b/test/e2e/tests/account/import-flow.spec.ts index 2a8bd0256999..f19312bee828 100644 --- a/test/e2e/tests/account/import-flow.spec.ts +++ b/test/e2e/tests/account/import-flow.spec.ts @@ -2,6 +2,7 @@ import path from 'path'; import { withFixtures } from '../../helpers'; import FixtureBuilder from '../../fixture-builder'; import AccountListPage from '../../page-objects/pages/account-list-page'; +import AccountDetailsModal from '../../page-objects/pages/dialog/account-details-modal'; import HeaderNavbar from '../../page-objects/pages/header-navbar'; import HomePage from '../../page-objects/pages/home/homepage'; import { loginWithBalanceValidation } from '../../page-objects/flows/login.flow'; @@ -32,7 +33,9 @@ describe('Import flow @no-mmi', function () { const accountListPage = new AccountListPage(driver); await accountListPage.check_pageIsLoaded(); await accountListPage.openAccountDetailsModal('Account 1'); - await accountListPage.check_addressInAccountDetailsModal( + const accountDetailsModal = new AccountDetailsModal(driver); + await accountDetailsModal.check_pageIsLoaded(); + await accountDetailsModal.check_addressInAccountDetailsModal( testAddress.toLowerCase(), ); }, diff --git a/test/e2e/tests/identity/account-syncing/sync-after-modifying-account-name.spec.ts b/test/e2e/tests/identity/account-syncing/sync-after-modifying-account-name.spec.ts index 07f6e4848aba..9a4b02c4f2b9 100644 --- a/test/e2e/tests/identity/account-syncing/sync-after-modifying-account-name.spec.ts +++ b/test/e2e/tests/identity/account-syncing/sync-after-modifying-account-name.spec.ts @@ -9,6 +9,7 @@ import { } from '../constants'; import { UserStorageMockttpController } from '../../../helpers/identity/user-storage/userStorageMockttpController'; import HeaderNavbar from '../../../page-objects/pages/header-navbar'; +import AccountDetailsModal from '../../../page-objects/pages/dialog/account-details-modal'; import AccountListPage from '../../../page-objects/pages/account-list-page'; import HomePage from '../../../page-objects/pages/home/homepage'; import { completeImportSRPOnboardingFlow } from '../../../page-objects/flows/onboarding.flow'; @@ -65,8 +66,10 @@ describe('Account syncing - Rename Accounts @no-mmi', function () { await accountListPage.check_accountDisplayedInAccountList( 'My Second Synced Account', ); - await accountListPage.openAccountOptionsMenu(); - await accountListPage.changeAccountLabel('My Renamed First Account'); + await accountListPage.openAccountDetailsModal('My First Synced Account'); + const accountDetailsModal = new AccountDetailsModal(driver); + await accountDetailsModal.check_pageIsLoaded(); + await accountDetailsModal.changeAccountLabel('My Renamed First Account'); }, ); diff --git a/test/e2e/tests/identity/account-syncing/sync-with-account-balances.spec.ts b/test/e2e/tests/identity/account-syncing/sync-with-account-balances.spec.ts index 6fcc9e9cc0d0..eed6d9fcbe75 100644 --- a/test/e2e/tests/identity/account-syncing/sync-with-account-balances.spec.ts +++ b/test/e2e/tests/identity/account-syncing/sync-with-account-balances.spec.ts @@ -8,6 +8,7 @@ import { } from '../constants'; import { UserStorageMockttpController } from '../../../helpers/identity/user-storage/userStorageMockttpController'; import HeaderNavbar from '../../../page-objects/pages/header-navbar'; +import AccountDetailsModal from '../../../page-objects/pages/dialog/account-details-modal'; import AccountListPage from '../../../page-objects/pages/account-list-page'; import HomePage from '../../../page-objects/pages/home/homepage'; import { completeImportSRPOnboardingFlow } from '../../../page-objects/flows/onboarding.flow'; @@ -158,11 +159,10 @@ describe('Account syncing - User already has balances on multple accounts @no-mm // Rename Account 6 to verify update to user storage await accountListPage.switchToAccount('Account 6'); - await header.openAccountMenu(); await accountListPage.openAccountDetailsModal('Account 6'); - await accountListPage.changeLabelFromAccountDetailsModal( - 'My Renamed Account 6', - ); + const accountDetailsModal = new AccountDetailsModal(driver); + await accountDetailsModal.check_pageIsLoaded(); + await accountDetailsModal.changeAccountLabel('My Renamed Account 6'); }, ); From a545d074a1cffc09aa56a1563895ba98d014655b Mon Sep 17 00:00:00 2001 From: Chloe Gao Date: Tue, 10 Dec 2024 14:27:28 +0100 Subject: [PATCH 04/10] migrate tests --- .../e2e/flask/btc/btc-dapp-connection.spec.ts | 2 +- test/e2e/flask/btc/create-btc-account.spec.ts | 6 +- test/e2e/flask/create-watch-account.spec.ts | 397 ++++++--------- .../e2e/flask/create-watch-accountxxx.spec.ts | 463 ------------------ .../page-objects/flows/watch-account.flow.ts | 28 ++ .../page-objects/pages/account-list-page.ts | 66 ++- .../pages/dialog/account-details-modal.ts | 75 +-- test/e2e/page-objects/pages/header-navbar.ts | 4 +- .../pages/home/bitcoin-homepage.ts | 10 +- test/e2e/page-objects/pages/home/homepage.ts | 3 +- .../pages/settings/experimental-settings.ts | 20 + .../sync-after-modifying-account-name.spec.ts | 8 +- 12 files changed, 290 insertions(+), 792 deletions(-) delete mode 100644 test/e2e/flask/create-watch-accountxxx.spec.ts create mode 100644 test/e2e/page-objects/flows/watch-account.flow.ts diff --git a/test/e2e/flask/btc/btc-dapp-connection.spec.ts b/test/e2e/flask/btc/btc-dapp-connection.spec.ts index 2f5aef6fc1a7..2a9b413f60b0 100644 --- a/test/e2e/flask/btc/btc-dapp-connection.spec.ts +++ b/test/e2e/flask/btc/btc-dapp-connection.spec.ts @@ -1,7 +1,7 @@ import { Suite } from 'mocha'; -import { withBtcAccountSnap } from './common-btc'; import BitcoinHomepage from '../../page-objects/pages/home/bitcoin-homepage'; import TestDapp from '../../page-objects/pages/test-dapp'; +import { withBtcAccountSnap } from './common-btc'; describe('BTC Account - Dapp Connection', function (this: Suite) { it('cannot connect to dapps', async function () { diff --git a/test/e2e/flask/btc/create-btc-account.spec.ts b/test/e2e/flask/btc/create-btc-account.spec.ts index 6cb62c3a5e1d..f4963c651124 100644 --- a/test/e2e/flask/btc/create-btc-account.spec.ts +++ b/test/e2e/flask/btc/create-btc-account.spec.ts @@ -102,7 +102,8 @@ describe('Create BTC Account', function (this: Suite) { await accountListPage.check_pageIsLoaded(); await accountListPage.openAccountDetailsModal('Bitcoin Account'); await accountDetailsModal.check_pageIsLoaded(); - const recreatedAccountAddress = await accountDetailsModal.getAccountAddress(); + const recreatedAccountAddress = + await accountDetailsModal.getAccountAddress(); assert(accountAddress === recreatedAccountAddress); }, @@ -157,7 +158,8 @@ describe('Create BTC Account', function (this: Suite) { await accountListPage.check_pageIsLoaded(); await accountListPage.openAccountDetailsModal('Bitcoin Account'); await accountDetailsModal.check_pageIsLoaded(); - const recreatedAccountAddress = await accountDetailsModal.getAccountAddress(); + const recreatedAccountAddress = + await accountDetailsModal.getAccountAddress(); assert(accountAddress === recreatedAccountAddress); }, diff --git a/test/e2e/flask/create-watch-account.spec.ts b/test/e2e/flask/create-watch-account.spec.ts index 7202d948a233..326571e3c534 100644 --- a/test/e2e/flask/create-watch-account.spec.ts +++ b/test/e2e/flask/create-watch-account.spec.ts @@ -1,71 +1,22 @@ import { strict as assert } from 'assert'; import { Suite } from 'mocha'; -import messages from '../../../app/_locales/en/messages.json'; import FixtureBuilder from '../fixture-builder'; -import { defaultGanacheOptions, unlockWallet, withFixtures } from '../helpers'; +import { withFixtures } from '../helpers'; import { Driver } from '../webdriver/driver'; +import AccountDetailsModal from '../page-objects/pages/dialog/account-details-modal'; +import AccountListPage from '../page-objects/pages/account-list-page'; +import ExperimentalSettings from '../page-objects/pages/settings/experimental-settings'; +import HeaderNavbar from '../page-objects/pages/header-navbar'; +import HomePage from '../page-objects/pages/home/homepage'; +import SettingsPage from '../page-objects/pages/settings/settings-page'; +import { loginWithBalanceValidation } from '../page-objects/flows/login.flow'; +import { watchEoaAddress } from '../page-objects/flows/watch-account.flow'; const ACCOUNT_1 = '0x5CfE73b6021E818B776b421B1c4Db2474086a7e1'; const EOA_ADDRESS = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'; const SHORTENED_EOA_ADDRESS = '0xd8dA6...96045'; const DEFAULT_WATCHED_ACCOUNT_NAME = 'Watched Account 1'; -/** - * Start the flow to create a watch account by clicking the account menu and selecting the option to add a watch account. - * - * @param driver - The WebDriver instance used to control the browser. - * @param unlockWalletFirst - Whether to unlock the wallet before starting the flow. - */ -async function startCreateWatchAccountFlow( - driver: Driver, - unlockWalletFirst: boolean = true, -): Promise { - if (unlockWalletFirst) { - await unlockWallet(driver); - } - - - await driver.clickElement('[data-testid="account-menu-icon"]'); - await driver.clickElement( - '[data-testid="multichain-account-menu-popover-action-button"]', - ); - await driver.clickElement( - '[data-testid="multichain-account-menu-popover-add-watch-only-account"]', - ); -} - -/** - * Watches an EOA address. - * - * @param driver - The WebDriver instance used to control the browser. - * @param unlockWalletFirst - Whether to unlock the wallet before watching the address. - * @param address - The EOA address to watch. - */ -async function watchEoaAddress( - driver: Driver, - unlockWalletFirst: boolean = true, - address: string = EOA_ADDRESS, -): Promise { - await startCreateWatchAccountFlow(driver, unlockWalletFirst); - await driver.fill('input#address-input[type="text"]', address); - await driver.clickElement({ text: 'Watch account', tag: 'button' }); - await driver.clickElement('[data-testid="submit-add-account-with-name"]'); -} - -/** - * Removes the selected account. - * - * @param driver - The WebDriver instance used to control the browser. - */ -async function removeSelectedAccount(driver: Driver): Promise { - await driver.clickElement('[data-testid="account-menu-icon"]'); - await driver.clickElement( - '.multichain-account-list-item--selected [data-testid="account-list-item-menu-button"]', - ); - await driver.clickElement('[data-testid="account-list-menu-remove"]'); - await driver.clickElement({ text: 'Remove', tag: 'button' }); -} - describe('Account-watcher snap', function (this: Suite) { describe('Adding watched accounts', function () { it('adds watch account with valid EOA address', async function () { @@ -77,22 +28,16 @@ describe('Account-watcher snap', function (this: Suite) { }) .withNetworkControllerOnMainnet() .build(), - ganacheOptions: defaultGanacheOptions, title: this.test?.fullTitle(), }, async ({ driver }: { driver: Driver }) => { // watch an EOA address - await watchEoaAddress(driver); + await watchEoaAddress(driver, EOA_ADDRESS); // new account should be displayed in the account list - await driver.findElement({ - css: '[data-testid="account-menu-icon"]', - text: DEFAULT_WATCHED_ACCOUNT_NAME, - }); - await driver.findElement({ - css: '.mm-text--ellipsis', - text: SHORTENED_EOA_ADDRESS, - }); + const headerNavbar = new HeaderNavbar(driver); + await headerNavbar.check_accountLabel(DEFAULT_WATCHED_ACCOUNT_NAME); + await headerNavbar.check_accountAddress(SHORTENED_EOA_ADDRESS); }, ); }); @@ -106,40 +51,28 @@ describe('Account-watcher snap', function (this: Suite) { }) .withNetworkControllerOnMainnet() .build(), - ganacheOptions: defaultGanacheOptions, title: this.test?.fullTitle(), }, async ({ driver }: { driver: Driver }) => { // watch an EOA address - await watchEoaAddress(driver); + await watchEoaAddress(driver, EOA_ADDRESS); + const homePage = new HomePage(driver); + await homePage.headerNavbar.check_accountLabel( + DEFAULT_WATCHED_ACCOUNT_NAME, + ); // 'Send' button should be disabled - await driver.findElement( - '[data-testid="eth-overview-send"][disabled]', - ); - await driver.findElement( - '[data-testid="eth-overview-send"].icon-button--disabled', - ); + assert.equal(await homePage.check_ifSendButtonIsClickable(), false); // 'Swap' button should be disabled - await driver.findElement( - '[data-testid="token-overview-button-swap"][disabled]', - ); - await driver.findElement( - '[data-testid="token-overview-button-swap"].icon-button--disabled', - ); + assert.equal(await homePage.check_ifSwapButtonIsClickable(), false); // 'Bridge' button should be disabled - await driver.findElement( - '[data-testid="eth-overview-bridge"][disabled]', - ); - await driver.findElement( - '[data-testid="eth-overview-bridge"].icon-button--disabled', - ); + assert.equal(await homePage.check_ifBridgeButtonIsClickable(), false); // check tooltips for disabled buttons - await driver.findElement( - '.icon-button--disabled [data-tooltipped][data-original-title="Not supported with this account."]', + await homePage.check_disabledButtonTooltip( + 'Not supported with this account.', ); }, ); @@ -183,20 +116,19 @@ describe('Account-watcher snap', function (this: Suite) { }) .withNetworkControllerOnMainnet() .build(), - ganacheOptions: defaultGanacheOptions, title: this.test?.fullTitle(), }, async ({ driver }: { driver: Driver }) => { - await startCreateWatchAccountFlow(driver); - - await driver.fill('input#address-input[type="text"]', input); - await driver.clickElement({ text: 'Watch account', tag: 'button' }); - - // error message should be displayed by the snap - await driver.findElement({ - css: '.snap-ui-renderer__text', - text: message, - }); + await loginWithBalanceValidation(driver); + const homePage = new HomePage(driver); + await homePage.check_pageIsLoaded(); + await homePage.check_expectedBalanceIsDisplayed(); + + // error message should be displayed by snap when try to watch an EOA with invalid input + await homePage.headerNavbar.openAccountMenu(); + const accountListPage = new AccountListPage(driver); + await accountListPage.check_pageIsLoaded(); + await accountListPage.addEoaAccount(input, message); }, ); }); @@ -217,30 +149,22 @@ describe('Account-watcher snap', function (this: Suite) { }) .withNetworkControllerOnMainnet() .build(), - ganacheOptions: defaultGanacheOptions, title: this.test?.fullTitle(), }, async ({ driver }: { driver: Driver }) => { // watch an EOA address for ACCOUNT_2 - await watchEoaAddress(driver, true, ACCOUNT_2); - - // try to import private key of watched ACCOUNT_2 address - await driver.clickElement('[data-testid="account-menu-icon"]'); - await driver.clickElement( - '[data-testid="multichain-account-menu-popover-action-button"]', - ); - await driver.clickElement({ text: 'Import account', tag: 'button' }); - await driver.findClickableElement('#private-key-box'); - await driver.fill('#private-key-box', PRIVATE_KEY_TWO); - await driver.clickElement( - '[data-testid="import-account-confirm-button"]', + await watchEoaAddress(driver, ACCOUNT_2); + const headerNavbar = new HeaderNavbar(driver); + await headerNavbar.check_accountLabel(DEFAULT_WATCHED_ACCOUNT_NAME); + + // try to import private key of watched ACCOUNT_2 address and check error message + await headerNavbar.openAccountMenu(); + const accountListPage = new AccountListPage(driver); + await accountListPage.check_pageIsLoaded(); + await accountListPage.addNewImportedAccount( + PRIVATE_KEY_TWO, + 'KeyringController - The account you are trying to import is a duplicate', ); - - // error message should be displayed - await driver.findElement({ - css: '.mm-box--color-error-default', - text: 'KeyringController - The account you are trying to import is a duplicate', - }); }, ); }); @@ -254,62 +178,26 @@ describe('Account-watcher snap', function (this: Suite) { }) .withNetworkControllerOnMainnet() .build(), - ganacheOptions: defaultGanacheOptions, - title: this.test?.fullTitle(), - }, - async ({ driver }: { driver: Driver }) => { - // watch an EOA address - await watchEoaAddress(driver); - - // click to view account details - await driver.clickElement( - '[data-testid="account-options-menu-button"]', - ); - await driver.clickElement( - '[data-testid="account-list-menu-details"]', - ); - // 'Show private key' button should not be displayed - await driver.assertElementNotPresent({ - css: 'button', - text: 'Show private key', - }); - }, - ); - }); - - it('removes a watched account', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder() - .withPreferencesControllerAndFeatureFlag({ - watchEthereumAccountEnabled: true, - }) - .withNetworkControllerOnMainnet() - .build(), - ganacheOptions: defaultGanacheOptions, title: this.test?.fullTitle(), }, async ({ driver }: { driver: Driver }) => { // watch an EOA address - await watchEoaAddress(driver); + await watchEoaAddress(driver, EOA_ADDRESS); - // remove the selected watched account - await removeSelectedAccount(driver); + // open account details modal in header navbar + const headerNavbar = new HeaderNavbar(driver); + await headerNavbar.check_accountLabel(DEFAULT_WATCHED_ACCOUNT_NAME); + await headerNavbar.openAccountDetailsModal(); - // account should be removed from the account list - await driver.assertElementNotPresent({ - css: '[data-testid="account-menu-icon"]', - text: DEFAULT_WATCHED_ACCOUNT_NAME, - }); - await driver.assertElementNotPresent({ - css: '.mm-text--ellipsis', - text: SHORTENED_EOA_ADDRESS, - }); + // check 'Show private key' button should not be displayed + const accountDetailsModal = new AccountDetailsModal(driver); + await accountDetailsModal.check_pageIsLoaded(); + await accountDetailsModal.check_showPrivateKeyButtonIsNotDisplayed(); }, ); }); - it('can remove and recreate a watched account', async function () { + it('removes a watched account and recreate a watched account', async function () { await withFixtures( { fixtures: new FixtureBuilder() @@ -318,111 +206,82 @@ describe('Account-watcher snap', function (this: Suite) { }) .withNetworkControllerOnMainnet() .build(), - ganacheOptions: defaultGanacheOptions, title: this.test?.fullTitle(), }, async ({ driver }: { driver: Driver }) => { // watch an EOA address - await watchEoaAddress(driver); + await watchEoaAddress(driver, EOA_ADDRESS); + const homePage = new HomePage(driver); + await homePage.headerNavbar.check_accountLabel( + DEFAULT_WATCHED_ACCOUNT_NAME, + ); // remove the selected watched account - await removeSelectedAccount(driver); + await homePage.headerNavbar.openAccountMenu(); + const accountListPage = new AccountListPage(driver); + await accountListPage.removeAccount(DEFAULT_WATCHED_ACCOUNT_NAME); + await homePage.check_pageIsLoaded(); + await homePage.check_expectedBalanceIsDisplayed(); // account should be removed from the account list - await driver.assertElementNotPresent({ - css: '[data-testid="account-menu-icon"]', - text: DEFAULT_WATCHED_ACCOUNT_NAME, - }); - await driver.assertElementNotPresent({ - css: '.mm-text--ellipsis', - text: SHORTENED_EOA_ADDRESS, - }); - - // watch the same EOA address again - await watchEoaAddress(driver, false); - - // same account should be displayed in the account list - await driver.findElement({ - css: '[data-testid="account-menu-icon"]', - text: DEFAULT_WATCHED_ACCOUNT_NAME, - }); - await driver.findElement({ - css: '.mm-text--ellipsis', - text: SHORTENED_EOA_ADDRESS, - }); + await homePage.headerNavbar.openAccountMenu(); + await accountListPage.check_accountIsNotDisplayedInAccountList( + DEFAULT_WATCHED_ACCOUNT_NAME, + ); + await accountListPage.closeAccountModal(); + await homePage.check_pageIsLoaded(); + await homePage.check_expectedBalanceIsDisplayed(); + + // watch the same EOA address again and check the account is recreated + await watchEoaAddress(driver, EOA_ADDRESS, false); + await homePage.headerNavbar.check_accountLabel( + DEFAULT_WATCHED_ACCOUNT_NAME, + ); + await homePage.headerNavbar.check_accountAddress( + SHORTENED_EOA_ADDRESS, + ); }, ); }); }); describe('Experimental toggle', function () { - const navigateToExperimentalSettings = async (driver: Driver) => { - await driver.clickElement('[data-testid="account-options-menu-button"]'); - await driver.clickElement({ text: 'Settings', tag: 'div' }); - await driver.clickElement({ text: 'Experimental', tag: 'div' }); - await driver.waitForSelector({ - text: messages.watchEthereumAccountsToggle.message, - tag: 'span', - }); - }; - - const getToggleState = async (driver: Driver): Promise => { - const toggleInput = await driver.findElement( - '[data-testid="watch-account-toggle"]', - ); - return toggleInput.isSelected(); - }; - - const toggleWatchAccountOptionAndCloseSettings = async (driver: Driver) => { - await driver.clickElement('[data-testid="watch-account-toggle-div"]'); - await driver.clickElement('button[aria-label="Close"]'); - }; - - const verifyWatchAccountOptionAndCloseMenu = async ( - driver: Driver, - shouldBePresent: boolean, - ) => { - await driver.clickElement('[data-testid="account-menu-icon"]'); - await driver.clickElement( - '[data-testid="multichain-account-menu-popover-action-button"]', - ); - if (shouldBePresent) { - await driver.waitForSelector({ - text: messages.addEthereumWatchOnlyAccount.message, - tag: 'button', - }); - } else { - await driver.assertElementNotPresent({ - text: messages.addEthereumWatchOnlyAccount.message, - tag: 'button', - }); - } - await driver.clickElement('button[aria-label="Close"]'); - }; - it("will show the 'Watch an Ethereum account (Beta)' option when setting is enabled", async function () { await withFixtures( { fixtures: new FixtureBuilder().build(), - ganacheOptions: defaultGanacheOptions, title: this.test?.fullTitle(), }, async ({ driver }) => { - await unlockWallet(driver); - await navigateToExperimentalSettings(driver); - - // verify toggle is off by default + await loginWithBalanceValidation(driver); + const homePage = new HomePage(driver); + await homePage.check_pageIsLoaded(); + await homePage.check_expectedBalanceIsDisplayed(); + + // navigate to experimental settings + await homePage.headerNavbar.openSettingsPage(); + const settingsPage = new SettingsPage(driver); + await settingsPage.check_pageIsLoaded(); + await settingsPage.goToExperimentalSettings(); + const experimentalSettings = new ExperimentalSettings(driver); + await experimentalSettings.check_pageIsLoaded(); + + // verify watch account toggle is off by default and enable the toggle assert.equal( - await getToggleState(driver), + await experimentalSettings.getWatchAccountToggleState(), false, 'Toggle should be off by default', ); - - // enable the toggle - await toggleWatchAccountOptionAndCloseSettings(driver); + await experimentalSettings.toggleWatchAccount(); + await settingsPage.closeSettingsPage(); // verify the 'Watch and Ethereum account (Beta)' option is available - await verifyWatchAccountOptionAndCloseMenu(driver, true); + await homePage.check_pageIsLoaded(); + await homePage.check_expectedBalanceIsDisplayed(); + await homePage.headerNavbar.openAccountMenu(); + const accountListPage = new AccountListPage(driver); + await accountListPage.check_pageIsLoaded(); + await accountListPage.check_addWatchAccountAvailable(true); }, ); }); @@ -431,27 +290,49 @@ describe('Account-watcher snap', function (this: Suite) { await withFixtures( { fixtures: new FixtureBuilder().build(), - ganacheOptions: defaultGanacheOptions, title: this.test?.fullTitle(), }, async ({ driver }) => { - await unlockWallet(driver); - await navigateToExperimentalSettings(driver); - - // enable the toggle - await toggleWatchAccountOptionAndCloseSettings(driver); + await loginWithBalanceValidation(driver); + const homePage = new HomePage(driver); + await homePage.check_pageIsLoaded(); + await homePage.check_expectedBalanceIsDisplayed(); + + // navigate to experimental settings and enable the toggle + await homePage.headerNavbar.openSettingsPage(); + const settingsPage = new SettingsPage(driver); + await settingsPage.check_pageIsLoaded(); + await settingsPage.goToExperimentalSettings(); + const experimentalSettings = new ExperimentalSettings(driver); + await experimentalSettings.check_pageIsLoaded(); + await experimentalSettings.toggleWatchAccount(); + await settingsPage.closeSettingsPage(); // verify the 'Watch and Ethereum account (Beta)' option is available - await verifyWatchAccountOptionAndCloseMenu(driver, true); - - // navigate back to experimental settings - await navigateToExperimentalSettings(driver); - - // disable the toggle - await toggleWatchAccountOptionAndCloseSettings(driver); + await homePage.check_pageIsLoaded(); + await homePage.check_expectedBalanceIsDisplayed(); + await homePage.headerNavbar.openAccountMenu(); + const accountListPage = new AccountListPage(driver); + await accountListPage.check_pageIsLoaded(); + await accountListPage.check_addWatchAccountAvailable(true); + await accountListPage.closeAccountModal(); + + // navigate back to experimental settings and disable the toggle + await homePage.check_pageIsLoaded(); + await homePage.check_expectedBalanceIsDisplayed(); + await homePage.headerNavbar.openSettingsPage(); + await settingsPage.check_pageIsLoaded(); + await settingsPage.goToExperimentalSettings(); + await experimentalSettings.check_pageIsLoaded(); + await experimentalSettings.toggleWatchAccount(); + await settingsPage.closeSettingsPage(); // verify the 'Watch and Ethereum account (Beta)' option is not available - await verifyWatchAccountOptionAndCloseMenu(driver, false); + await homePage.check_pageIsLoaded(); + await homePage.check_expectedBalanceIsDisplayed(); + await homePage.headerNavbar.openAccountMenu(); + await accountListPage.check_pageIsLoaded(); + await accountListPage.check_addWatchAccountAvailable(false); }, ); }); diff --git a/test/e2e/flask/create-watch-accountxxx.spec.ts b/test/e2e/flask/create-watch-accountxxx.spec.ts deleted file mode 100644 index 05500e8abc77..000000000000 --- a/test/e2e/flask/create-watch-accountxxx.spec.ts +++ /dev/null @@ -1,463 +0,0 @@ -import { strict as assert } from 'assert'; -import { Suite } from 'mocha'; -import messages from '../../../app/_locales/en/messages.json'; -import FixtureBuilder from '../fixture-builder'; -import { defaultGanacheOptions, unlockWallet, withFixtures } from '../helpers'; -import { Driver } from '../webdriver/driver'; - -import AccountDetailsModal from '../page-objects/pages/dialog/account-details-modal'; -import AccountListPage from '../page-objects/pages/account-list-page'; -import HomePage from '../page-objects/pages/home/homepage'; -import { loginWithBalanceValidation } from '../page-objects/flows/login.flow'; - -const ACCOUNT_1 = '0x5CfE73b6021E818B776b421B1c4Db2474086a7e1'; -const EOA_ADDRESS = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'; -const SHORTENED_EOA_ADDRESS = '0xd8dA6...96045'; -const DEFAULT_WATCHED_ACCOUNT_NAME = 'Watched Account 1'; - -/** - * Start the flow to create a watch account by clicking the account menu and selecting the option to add a watch account. - * - * @param driver - The WebDriver instance used to control the browser. - * @param unlockWalletFirst - Whether to unlock the wallet before starting the flow. - */ -async function startCreateWatchAccountFlow( - driver: Driver, - unlockWalletFirst: boolean = true, -): Promise { - if (unlockWalletFirst) { - await loginWithBalanceValidation(driver); - } - - const homePage = new HomePage(driver); - await homePage.check_pageIsLoaded(); - - await homePage.headerNavbar.openAccountMenu(); - const accountListPage = new AccountListPage(driver); - await accountListPage.check_pageIsLoaded(); - - - await driver.clickElement( - '[data-testid="multichain-account-menu-popover-add-watch-only-account"]', - ); -} - -/** - * Watches an EOA address. - * - * @param driver - The WebDriver instance used to control the browser. - * @param unlockWalletFirst - Whether to unlock the wallet before watching the address. - * @param address - The EOA address to watch. - */ -async function watchEoaAddress( - driver: Driver, - unlockWalletFirst: boolean = true, - address: string = EOA_ADDRESS, -): Promise { - await startCreateWatchAccountFlow(driver, unlockWalletFirst); - await driver.fill('input#address-input[type="text"]', address); - await driver.clickElement({ text: 'Watch account', tag: 'button' }); - await driver.clickElement('[data-testid="submit-add-account-with-name"]'); -} - -/** - * Removes the selected account. - * - * @param driver - The WebDriver instance used to control the browser. - */ -async function removeSelectedAccount(driver: Driver): Promise { - await driver.clickElement('[data-testid="account-menu-icon"]'); - await driver.clickElement( - '.multichain-account-list-item--selected [data-testid="account-list-item-menu-button"]', - ); - await driver.clickElement('[data-testid="account-list-menu-remove"]'); - await driver.clickElement({ text: 'Remove', tag: 'button' }); -} - -describe('Account-watcher snap', function (this: Suite) { - describe('Adding watched accounts', function () { - it('adds watch account with valid EOA address', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder() - .withPreferencesControllerAndFeatureFlag({ - watchEthereumAccountEnabled: true, - }) - .withNetworkControllerOnMainnet() - .build(), - title: this.test?.fullTitle(), - }, - async ({ driver }: { driver: Driver }) => { - await loginWithBalanceValidation(driver); - const homePage = new HomePage(driver); - await homePage.check_pageIsLoaded(); - await homePage.check_expectedBalanceIsDisplayed(); - - // watch an EOA address - await homePage.headerNavbar.openAccountMenu(); - const accountListPage = new AccountListPage(driver); - await accountListPage.check_pageIsLoaded(); - await accountListPage.addEoaAccount(EOA_ADDRESS); - - // new account should be displayed in the account list - await homePage.check_pageIsLoaded(); - await homePage.headerNavbar.check_accountLabel(DEFAULT_WATCHED_ACCOUNT_NAME); - await homePage.headerNavbar.check_accountAddress(SHORTENED_EOA_ADDRESS); - }, - ); - }); - - it("disables 'Send' 'Swap' and 'Bridge' buttons for watch accounts", async function () { - await withFixtures( - { - fixtures: new FixtureBuilder() - .withPreferencesControllerAndFeatureFlag({ - watchEthereumAccountEnabled: true, - }) - .withNetworkControllerOnMainnet() - .build(), - title: this.test?.fullTitle(), - }, - async ({ driver }: { driver: Driver }) => { - await loginWithBalanceValidation(driver); - const homePage = new HomePage(driver); - await homePage.check_pageIsLoaded(); - await homePage.check_expectedBalanceIsDisplayed(); - - // watch an EOA address - await homePage.headerNavbar.openAccountMenu(); - const accountListPage = new AccountListPage(driver); - await accountListPage.check_pageIsLoaded(); - await accountListPage.addEoaAccount(EOA_ADDRESS); - await homePage.check_pageIsLoaded(); - await homePage.headerNavbar.check_accountLabel(DEFAULT_WATCHED_ACCOUNT_NAME); - - // 'Send' button should be disabled - assert.equal(await homePage.check_ifSendButtonIsClickable(), false); - - // 'Swap' button should be disabled - assert.equal(await homePage.check_ifSwapButtonIsClickable(), false); - - // 'Bridge' button should be disabled - assert.equal(await homePage.check_ifBridgeButtonIsClickable(), false); - - // check tooltips for disabled buttons - await homePage.check_disabledButtonTooltip("Not supported with this account."); - }, - ); - }); - }); - - describe('Invalid input handling', function () { - const invalidInputTests = [ - { - input: 'd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', - message: 'Invalid input', - description: 'address missing 0x prefix', - }, - { - input: '0x123ABC', - message: 'Invalid address', - description: 'invalid address', - }, - { - input: 'invalid.eth', - message: 'Invalid ENS name', - description: 'invalid ENS name', - }, - { - input: ACCOUNT_1, - // FIXME: Watchout, the Snap bridge will lower-case EVM addresses, even in some error messages, this is - // a mistake, and we might wanna re-change that later, see: - // - https://github.com/MetaMask/accounts/pull/90/files#r1848713364 - message: `Unknown snap error: Account address '${ACCOUNT_1.toLowerCase()}' already exists`, - description: 'existing address', - }, - ]; - - invalidInputTests.forEach(({ input, message, description }) => { - it(`handles invalid input: ${description}`, async function () { - await withFixtures( - { - fixtures: new FixtureBuilder() - .withPreferencesControllerAndFeatureFlag({ - watchEthereumAccountEnabled: true, - }) - .withNetworkControllerOnMainnet() - .build(), - title: this.test?.fullTitle(), - }, - async ({ driver }: { driver: Driver }) => { - await loginWithBalanceValidation(driver); - const homePage = new HomePage(driver); - await homePage.check_pageIsLoaded(); - await homePage.check_expectedBalanceIsDisplayed(); - - // error message should be displayed by snap when try to watch an EOA with invalid input - await homePage.headerNavbar.openAccountMenu(); - const accountListPage = new AccountListPage(driver); - await accountListPage.check_pageIsLoaded(); - await accountListPage.addEoaAccount(input, message); - }, - ); - }); - }); - }); - - describe('Account management', function () { - it('does not allow user to import private key of watched address', async function () { - const PRIVATE_KEY_TWO = - '0xf444f52ea41e3a39586d7069cb8e8233e9f6b9dea9cbb700cce69ae860661cc8'; - const ACCOUNT_2 = '0x09781764c08de8ca82e156bbf156a3ca217c7950'; - - await withFixtures( - { - fixtures: new FixtureBuilder() - .withPreferencesControllerAndFeatureFlag({ - watchEthereumAccountEnabled: true, - }) - .withNetworkControllerOnMainnet() - .build(), - title: this.test?.fullTitle(), - }, - async ({ driver }: { driver: Driver }) => { - await loginWithBalanceValidation(driver); - const homePage = new HomePage(driver); - await homePage.check_pageIsLoaded(); - await homePage.check_expectedBalanceIsDisplayed(); - - // watch an EOA address for ACCOUNT_2 - await homePage.headerNavbar.openAccountMenu(); - const accountListPage = new AccountListPage(driver); - await accountListPage.check_pageIsLoaded(); - await accountListPage.addEoaAccount(ACCOUNT_2); - await homePage.check_pageIsLoaded(); - await homePage.headerNavbar.check_accountLabel(DEFAULT_WATCHED_ACCOUNT_NAME); - - // try to import private key of watched ACCOUNT_2 address and check error message - await homePage.headerNavbar.openAccountMenu(); - await accountListPage.check_pageIsLoaded(); - await accountListPage.addNewImportedAccount( - PRIVATE_KEY_TWO, - 'KeyringController - The account you are trying to import is a duplicate', - ); - }, - ); - }); - - it("does not display 'Show private key' button for watch accounts", async function () { - await withFixtures( - { - fixtures: new FixtureBuilder() - .withPreferencesControllerAndFeatureFlag({ - watchEthereumAccountEnabled: true, - }) - .withNetworkControllerOnMainnet() - .build(), - title: this.test?.fullTitle(), - }, - async ({ driver }: { driver: Driver }) => { - await loginWithBalanceValidation(driver); - const homePage = new HomePage(driver); - await homePage.check_pageIsLoaded(); - await homePage.check_expectedBalanceIsDisplayed(); - - // watch an EOA address for ACCOUNT_2 - await homePage.headerNavbar.openAccountMenu(); - const accountListPage = new AccountListPage(driver); - await accountListPage.check_pageIsLoaded(); - await accountListPage.addEoaAccount(EOA_ADDRESS); - await homePage.check_pageIsLoaded(); - - // open account details modal in header navbar - await homePage.headerNavbar.check_accountLabel(DEFAULT_WATCHED_ACCOUNT_NAME); - await homePage.headerNavbar.openAccountDetailsModal(); - - // check 'Show private key' button should not be displayed - const accountDetailsModal = new AccountDetailsModal(driver); - await accountDetailsModal.check_pageIsLoaded(); - await accountDetailsModal.check_showPrivateKeyButtonIsNotDisplayed(); - }, - ); - }); - - it.only('removes a watched account', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder() - .withPreferencesControllerAndFeatureFlag({ - watchEthereumAccountEnabled: true, - }) - .withNetworkControllerOnMainnet() - .build(), - ganacheOptions: defaultGanacheOptions, - title: this.test?.fullTitle(), - }, - async ({ driver }: { driver: Driver }) => { - // watch an EOA address - await watchEoaAddress(driver); - throw new Error('Not implemented'); - // remove the selected watched account - await removeSelectedAccount(driver); - - // account should be removed from the account list - await driver.assertElementNotPresent({ - css: '[data-testid="account-menu-icon"]', - text: DEFAULT_WATCHED_ACCOUNT_NAME, - }); - await driver.assertElementNotPresent({ - css: '.mm-text--ellipsis', - text: SHORTENED_EOA_ADDRESS, - }); - }, - ); - }); - - it('can remove and recreate a watched account', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder() - .withPreferencesControllerAndFeatureFlag({ - watchEthereumAccountEnabled: true, - }) - .withNetworkControllerOnMainnet() - .build(), - ganacheOptions: defaultGanacheOptions, - title: this.test?.fullTitle(), - }, - async ({ driver }: { driver: Driver }) => { - // watch an EOA address - await watchEoaAddress(driver); - - // remove the selected watched account - await removeSelectedAccount(driver); - - // account should be removed from the account list - await driver.assertElementNotPresent({ - css: '[data-testid="account-menu-icon"]', - text: DEFAULT_WATCHED_ACCOUNT_NAME, - }); - await driver.assertElementNotPresent({ - css: '.mm-text--ellipsis', - text: SHORTENED_EOA_ADDRESS, - }); - - // watch the same EOA address again - await watchEoaAddress(driver, false); - - // same account should be displayed in the account list - await driver.findElement({ - css: '[data-testid="account-menu-icon"]', - text: DEFAULT_WATCHED_ACCOUNT_NAME, - }); - await driver.findElement({ - css: '.mm-text--ellipsis', - text: SHORTENED_EOA_ADDRESS, - }); - }, - ); - }); - }); - - describe('Experimental toggle', function () { - const navigateToExperimentalSettings = async (driver: Driver) => { - await driver.clickElement('[data-testid="account-options-menu-button"]'); - await driver.clickElement({ text: 'Settings', tag: 'div' }); - await driver.clickElement({ text: 'Experimental', tag: 'div' }); - await driver.waitForSelector({ - text: messages.watchEthereumAccountsToggle.message, - tag: 'span', - }); - }; - - const getToggleState = async (driver: Driver): Promise => { - const toggleInput = await driver.findElement( - '[data-testid="watch-account-toggle"]', - ); - return toggleInput.isSelected(); - }; - - const toggleWatchAccountOptionAndCloseSettings = async (driver: Driver) => { - await driver.clickElement('[data-testid="watch-account-toggle-div"]'); - await driver.clickElement('button[aria-label="Close"]'); - }; - - const verifyWatchAccountOptionAndCloseMenu = async ( - driver: Driver, - shouldBePresent: boolean, - ) => { - await driver.clickElement('[data-testid="account-menu-icon"]'); - await driver.clickElement( - '[data-testid="multichain-account-menu-popover-action-button"]', - ); - if (shouldBePresent) { - await driver.waitForSelector({ - text: messages.addEthereumWatchOnlyAccount.message, - tag: 'button', - }); - } else { - await driver.assertElementNotPresent({ - text: messages.addEthereumWatchOnlyAccount.message, - tag: 'button', - }); - } - await driver.clickElement('button[aria-label="Close"]'); - }; - - it("will show the 'Watch an Ethereum account (Beta)' option when setting is enabled", async function () { - await withFixtures( - { - fixtures: new FixtureBuilder().build(), - ganacheOptions: defaultGanacheOptions, - title: this.test?.fullTitle(), - }, - async ({ driver }) => { - await unlockWallet(driver); - await navigateToExperimentalSettings(driver); - - // verify toggle is off by default - assert.equal( - await getToggleState(driver), - false, - 'Toggle should be off by default', - ); - - // enable the toggle - await toggleWatchAccountOptionAndCloseSettings(driver); - - // verify the 'Watch and Ethereum account (Beta)' option is available - await verifyWatchAccountOptionAndCloseMenu(driver, true); - }, - ); - }); - - it('enables and then disables the toggle and the option to add a watch-only account behaves as expected', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder().build(), - ganacheOptions: defaultGanacheOptions, - title: this.test?.fullTitle(), - }, - async ({ driver }) => { - await unlockWallet(driver); - await navigateToExperimentalSettings(driver); - - // enable the toggle - await toggleWatchAccountOptionAndCloseSettings(driver); - - // verify the 'Watch and Ethereum account (Beta)' option is available - await verifyWatchAccountOptionAndCloseMenu(driver, true); - - // navigate back to experimental settings - await navigateToExperimentalSettings(driver); - - // disable the toggle - await toggleWatchAccountOptionAndCloseSettings(driver); - - // verify the 'Watch and Ethereum account (Beta)' option is not available - await verifyWatchAccountOptionAndCloseMenu(driver, false); - }, - ); - }); - }); -}); diff --git a/test/e2e/page-objects/flows/watch-account.flow.ts b/test/e2e/page-objects/flows/watch-account.flow.ts new file mode 100644 index 000000000000..1a9b3f355a47 --- /dev/null +++ b/test/e2e/page-objects/flows/watch-account.flow.ts @@ -0,0 +1,28 @@ +import { Driver } from '../../webdriver/driver'; +import HomePage from '../pages/home/homepage'; +import AccountListPage from '../pages/account-list-page'; +import { loginWithBalanceValidation } from './login.flow'; + +/** + * Initiates the flow of watching an EOA address. + * + * @param driver - The WebDriver instance. + * @param address - The EOA address that is to be watched. + * @param unlockWalletFirst - A boolean indicating whether the wallet should be unlocked before attempting to watch the address. Default is true. + */ +export async function watchEoaAddress( + driver: Driver, + address: string, + unlockWalletFirst: boolean = true, +): Promise { + if (unlockWalletFirst) { + await loginWithBalanceValidation(driver); + } + // watch a new EOA + const homePage = new HomePage(driver); + await homePage.headerNavbar.openAccountMenu(); + const accountListPage = new AccountListPage(driver); + await accountListPage.check_pageIsLoaded(); + await accountListPage.addEoaAccount(address); + await homePage.check_pageIsLoaded(); +} diff --git a/test/e2e/page-objects/pages/account-list-page.ts b/test/e2e/page-objects/pages/account-list-page.ts index bf5493998ac6..669b1b43d896 100644 --- a/test/e2e/page-objects/pages/account-list-page.ts +++ b/test/e2e/page-objects/pages/account-list-page.ts @@ -107,7 +107,8 @@ class AccountListPage { tag: 'h4', }; - private readonly watchAccountAddressInput = 'input#address-input[type="text"]'; + private readonly watchAccountAddressInput = + 'input#address-input[type="text"]'; private readonly watchAccountConfirmButton = { text: 'Watch account', @@ -137,24 +138,31 @@ class AccountListPage { * @param address - The address to watch. * @param expectedErrorMessage - Optional error message to display if the address is invalid. */ - async addEoaAccount(address: string, expectedErrorMessage: string = ''): Promise { - console.log(`Watch EOA account with address ${address}`); - await this.driver.clickElement(this.createAccountButton); - await this.driver.clickElement(this.addEoaAccountButton); - await this.driver.waitForSelector(this.watchAccountModalTitle); - await this.driver.fill(this.watchAccountAddressInput, address); - await this.driver.clickElement(this.watchAccountConfirmButton); - if (expectedErrorMessage) { - console.log( - `Check if error message is displayed: ${expectedErrorMessage}`, - ); - await this.driver.waitForSelector({ - css: '.snap-ui-renderer__text', - text: expectedErrorMessage, - }); - } else { - await this.driver.clickElement(this.addAccountConfirmButton); - } + async addEoaAccount( + address: string, + expectedErrorMessage: string = '', + ): Promise { + console.log(`Watch EOA account with address ${address}`); + await this.driver.clickElement(this.createAccountButton); + await this.driver.clickElement(this.addEoaAccountButton); + await this.driver.waitForSelector(this.watchAccountModalTitle); + await this.driver.fill(this.watchAccountAddressInput, address); + await this.driver.clickElementAndWaitToDisappear( + this.watchAccountConfirmButton, + ); + if (expectedErrorMessage) { + console.log( + `Check if error message is displayed: ${expectedErrorMessage}`, + ); + await this.driver.waitForSelector({ + css: '.snap-ui-renderer__text', + text: expectedErrorMessage, + }); + } else { + await this.driver.clickElementAndWaitToDisappear( + this.addAccountConfirmButton, + ); + } } /** @@ -484,6 +492,26 @@ class AccountListPage { await this.driver.assertElementNotPresent(this.addSnapAccountButton); } + /** + * Checks that the add watch account button is displayed in the create account modal. + * + * @param expectedAvailability - Whether the add watch account button is expected to be displayed. + */ + async check_addWatchAccountAvailable( + expectedAvailability: boolean, + ): Promise { + console.log( + `Check add watch account button is ${ + expectedAvailability ? 'displayed ' : 'not displayed' + }`, + ); + await this.openAddAccountModal(); + if (expectedAvailability) { + await this.driver.waitForSelector(this.addEoaAccountButton); + } else { + await this.driver.assertElementNotPresent(this.addEoaAccountButton); + } + } async check_currentAccountIsImported(): Promise { console.log(`Check that current account is an imported account`); diff --git a/test/e2e/page-objects/pages/dialog/account-details-modal.ts b/test/e2e/page-objects/pages/dialog/account-details-modal.ts index 65c59b127316..b36b9076c8f4 100644 --- a/test/e2e/page-objects/pages/dialog/account-details-modal.ts +++ b/test/e2e/page-objects/pages/dialog/account-details-modal.ts @@ -2,20 +2,30 @@ import { Driver } from '../../../webdriver/driver'; class AccountDetailsModal { private driver: Driver; + private readonly accountAddressText = '.qr-code__address-segments'; + private readonly accountQrCodeAddress = '.qr-code__address-segments'; + private readonly accountQrCodeImage = '.qr-code__wrapper'; + private readonly closeAccountModalButton = 'button[aria-label="Close"]'; - private readonly copyAddressButton = '[data-testid="address-copy-button-text"]'; - private readonly editableLabelButton = '[data-testid="editable-label-button"]'; + + private readonly copyAddressButton = + '[data-testid="address-copy-button-text"]'; + + private readonly editableLabelButton = + '[data-testid="editable-label-button"]'; + private readonly editableLabelInput = '[data-testid="editable-input"] input'; + private readonly saveAccountLabelButton = '[data-testid="save-account-label-input"]'; private readonly showPrivateKeyButton = { css: 'button', text: 'Show private key', - } + }; constructor(driver: Driver) { this.driver = driver; @@ -38,15 +48,17 @@ class AccountDetailsModal { } async closeAccountDetailsModal(): Promise { - await this.driver.clickElementAndWaitToDisappear(this.closeAccountModalButton); + await this.driver.clickElementAndWaitToDisappear( + this.closeAccountModalButton, + ); } - /** + /** * Change the label of the account in the account details modal. * * @param newLabel - The new label to set for the account. */ - async changeAccountLabel(newLabel: string): Promise { + async changeAccountLabel(newLabel: string): Promise { console.log( `Account details modal opened, changing account label to: ${newLabel}`, ); @@ -56,45 +68,38 @@ class AccountDetailsModal { await this.closeAccountDetailsModal(); } - /** - * Get the address of the specified account. - * - * @param accountLabel - The label of the account to get the address. - */ - async getAccountAddress(): Promise { - console.log(`Get account address in account list`); - await this.driver.waitForSelector(this.accountAddressText); - const accountAddress = await ( - await this.driver.findElement(this.accountAddressText) - ).getText(); - await this.closeAccountDetailsModal(); - return accountAddress; - } + async getAccountAddress(): Promise { + console.log(`Get account address in account details modal`); + await this.driver.waitForSelector(this.accountAddressText); + const accountAddress = await ( + await this.driver.findElement(this.accountAddressText) + ).getText(); + await this.closeAccountDetailsModal(); + return accountAddress; + } - /** + /** * Check that the correct address is displayed in the account details modal. * * @param expectedAddress - The expected address to check. */ - async check_addressInAccountDetailsModal( - expectedAddress: string, - ): Promise { - console.log( - `Check that address ${expectedAddress} is displayed in account details modal`, - ); - await this.driver.waitForSelector(this.accountQrCodeImage); - await this.driver.waitForSelector({ - css: this.accountQrCodeAddress, - text: expectedAddress, - }); - } + async check_addressInAccountDetailsModal( + expectedAddress: string, + ): Promise { + console.log( + `Check that address ${expectedAddress} is displayed in account details modal`, + ); + await this.driver.waitForSelector(this.accountQrCodeImage); + await this.driver.waitForSelector({ + css: this.accountQrCodeAddress, + text: expectedAddress, + }); + } async check_showPrivateKeyButtonIsNotDisplayed(): Promise { console.log('Check that show private key button is not displayed'); await this.driver.assertElementNotPresent(this.showPrivateKeyButton); } - - } export default AccountDetailsModal; diff --git a/test/e2e/page-objects/pages/header-navbar.ts b/test/e2e/page-objects/pages/header-navbar.ts index 848d144ee5c2..6f232915404a 100644 --- a/test/e2e/page-objects/pages/header-navbar.ts +++ b/test/e2e/page-objects/pages/header-navbar.ts @@ -17,7 +17,8 @@ class HeaderNavbar { private readonly mmiPortfolioButton = '[data-testid="global-menu-mmi-portfolio"]'; - private readonly openAccountDetailsButton = '[data-testid="account-list-menu-details"]'; + private readonly openAccountDetailsButton = + '[data-testid="account-list-menu-details"]'; private readonly settingsButton = '[data-testid="global-menu-settings"]'; @@ -117,7 +118,6 @@ class HeaderNavbar { `button[data-testid="network-display"][aria-label="Network Menu ${networkName}"]`, ); } - } export default HeaderNavbar; diff --git a/test/e2e/page-objects/pages/home/bitcoin-homepage.ts b/test/e2e/page-objects/pages/home/bitcoin-homepage.ts index 0ffb8406bf14..641681434635 100644 --- a/test/e2e/page-objects/pages/home/bitcoin-homepage.ts +++ b/test/e2e/page-objects/pages/home/bitcoin-homepage.ts @@ -4,10 +4,7 @@ class BitcoinHomepage extends HomePage { protected readonly balance = '[data-testid="coin-overview__primary-currency"]'; - private readonly bridgeButton = { - text: 'Bridge', - tag: 'button', - }; + protected readonly bridgeButton = '[data-testid="coin-overview-bridge"]'; private readonly buySellButton = '[data-testid="coin-overview-buy"]'; @@ -15,11 +12,6 @@ class BitcoinHomepage extends HomePage { protected readonly sendButton = '[data-testid="coin-overview-send"]'; - private readonly swapButton = { - text: 'Swap', - tag: 'button', - }; - async check_pageIsLoaded(): Promise { try { await this.driver.waitForMultipleSelectors([ diff --git a/test/e2e/page-objects/pages/home/homepage.ts b/test/e2e/page-objects/pages/home/homepage.ts index 48d9e02636ed..bfb991a97c1a 100644 --- a/test/e2e/page-objects/pages/home/homepage.ts +++ b/test/e2e/page-objects/pages/home/homepage.ts @@ -19,7 +19,8 @@ class HomePage { css: '.mm-banner-alert', }; - protected readonly bridgeButton = '[data-testid="eth-overview-bridge"]'; + protected readonly bridgeButton: string = + '[data-testid="eth-overview-bridge"]'; private readonly closeUseNetworkNotificationModalButton = { text: 'Got it', diff --git a/test/e2e/page-objects/pages/settings/experimental-settings.ts b/test/e2e/page-objects/pages/settings/experimental-settings.ts index 84de34c85172..f3755db72947 100644 --- a/test/e2e/page-objects/pages/settings/experimental-settings.ts +++ b/test/e2e/page-objects/pages/settings/experimental-settings.ts @@ -19,6 +19,12 @@ class ExperimentalSettings { private readonly redesignedSignatureToggle = '[data-testid="toggle-redesigned-confirmations-container"]'; + private readonly watchAccountToggleState = + '[data-testid="watch-account-toggle"]'; + + private readonly watchAccountToggle = + '[data-testid="watch-account-toggle-div"]'; + constructor(driver: Driver) { this.driver = driver; } @@ -36,6 +42,15 @@ class ExperimentalSettings { console.log('Experimental Settings page is loaded'); } + // Get the state of the Watch Account Toggle, returns true if the toggle is selected + async getWatchAccountToggleState(): Promise { + console.log('Get Watch Account Toggle State'); + const toggleInput = await this.driver.findElement( + this.watchAccountToggleState, + ); + return toggleInput.isSelected(); + } + async toggleBitcoinAccount(): Promise { console.log('Toggle Add new Bitcoin account on experimental setting page'); await this.driver.waitForSelector({ @@ -54,6 +69,11 @@ class ExperimentalSettings { console.log('Toggle Redesigned Signature on experimental setting page'); await this.driver.clickElement(this.redesignedSignatureToggle); } + + async toggleWatchAccount(): Promise { + console.log('Toggle Watch Account on experimental setting page'); + await this.driver.clickElement(this.watchAccountToggle); + } } export default ExperimentalSettings; diff --git a/test/e2e/tests/identity/account-syncing/sync-after-modifying-account-name.spec.ts b/test/e2e/tests/identity/account-syncing/sync-after-modifying-account-name.spec.ts index 9a4b02c4f2b9..ce10b3129d58 100644 --- a/test/e2e/tests/identity/account-syncing/sync-after-modifying-account-name.spec.ts +++ b/test/e2e/tests/identity/account-syncing/sync-after-modifying-account-name.spec.ts @@ -66,10 +66,14 @@ describe('Account syncing - Rename Accounts @no-mmi', function () { await accountListPage.check_accountDisplayedInAccountList( 'My Second Synced Account', ); - await accountListPage.openAccountDetailsModal('My First Synced Account'); + await accountListPage.openAccountDetailsModal( + 'My First Synced Account', + ); const accountDetailsModal = new AccountDetailsModal(driver); await accountDetailsModal.check_pageIsLoaded(); - await accountDetailsModal.changeAccountLabel('My Renamed First Account'); + await accountDetailsModal.changeAccountLabel( + 'My Renamed First Account', + ); }, ); From 3fc6a8ee0e6017fb0aad18ccd6dd658988d646f7 Mon Sep 17 00:00:00 2001 From: Chloe Gao Date: Wed, 18 Dec 2024 11:41:53 +0100 Subject: [PATCH 05/10] fix lint --- test/e2e/flask/btc/create-btc-account.spec.ts | 2 +- test/e2e/page-objects/pages/home/bitcoin-homepage.ts | 10 ++-------- test/e2e/page-objects/pages/home/homepage.ts | 5 ++--- .../pages/settings/experimental-settings.ts | 1 - test/e2e/tests/account/import-flow.spec.ts | 2 +- 5 files changed, 6 insertions(+), 14 deletions(-) diff --git a/test/e2e/flask/btc/create-btc-account.spec.ts b/test/e2e/flask/btc/create-btc-account.spec.ts index f4963c651124..30c335cf9cc4 100644 --- a/test/e2e/flask/btc/create-btc-account.spec.ts +++ b/test/e2e/flask/btc/create-btc-account.spec.ts @@ -110,7 +110,7 @@ describe('Create BTC Account', function (this: Suite) { ); }); - it.only('can recreate BTC account after restoring wallet with SRP', async function () { + it('can recreate BTC account after restoring wallet with SRP', async function () { await withBtcAccountSnap( { title: this.test?.fullTitle() }, async (driver) => { diff --git a/test/e2e/page-objects/pages/home/bitcoin-homepage.ts b/test/e2e/page-objects/pages/home/bitcoin-homepage.ts index 19b235636405..691d85763b14 100644 --- a/test/e2e/page-objects/pages/home/bitcoin-homepage.ts +++ b/test/e2e/page-objects/pages/home/bitcoin-homepage.ts @@ -4,10 +4,7 @@ class BitcoinHomepage extends HomePage { protected readonly balance = '[data-testid="coin-overview__primary-currency"]'; - private readonly bridgeButton = { - text: 'Bridge', - tag: 'button', - }; + protected readonly bridgeButton = '[data-testid="coin-overview-bridge"]'; private readonly buySellButton = '[data-testid="coin-overview-buy"]'; @@ -15,10 +12,7 @@ class BitcoinHomepage extends HomePage { protected readonly sendButton = '[data-testid="coin-overview-send"]'; - private readonly swapButton = { - text: 'Swap', - tag: 'button', - }; + protected readonly swapButton = '[data-testid="coin-overview-swap"]'; async check_pageIsLoaded(): Promise { try { diff --git a/test/e2e/page-objects/pages/home/homepage.ts b/test/e2e/page-objects/pages/home/homepage.ts index 75a25de12e41..a98e59075e73 100644 --- a/test/e2e/page-objects/pages/home/homepage.ts +++ b/test/e2e/page-objects/pages/home/homepage.ts @@ -48,14 +48,13 @@ class HomePage { protected readonly sendButton: string = '[data-testid="eth-overview-send"]'; - protected readonly swapButton = '[data-testid="token-overview-button-swap"]'; + protected readonly swapButton: string = + '[data-testid="token-overview-button-swap"]'; private readonly refreshErc20Tokens = { testId: 'refreshList', }; - protected readonly sendButton: string = '[data-testid="eth-overview-send"]'; - private readonly tokensTab = { testId: 'account-overview__asset-tab', }; diff --git a/test/e2e/page-objects/pages/settings/experimental-settings.ts b/test/e2e/page-objects/pages/settings/experimental-settings.ts index 69b2bde6ec57..69df0525093d 100644 --- a/test/e2e/page-objects/pages/settings/experimental-settings.ts +++ b/test/e2e/page-objects/pages/settings/experimental-settings.ts @@ -28,7 +28,6 @@ class ExperimentalSettings { private readonly watchAccountToggle = '[data-testid="watch-account-toggle-div"]'; - constructor(driver: Driver) { this.driver = driver; } diff --git a/test/e2e/tests/account/import-flow.spec.ts b/test/e2e/tests/account/import-flow.spec.ts index 22b37cea29a5..c8ffcc334e49 100644 --- a/test/e2e/tests/account/import-flow.spec.ts +++ b/test/e2e/tests/account/import-flow.spec.ts @@ -36,7 +36,7 @@ describe('Import flow @no-mmi', function () { const accountDetailsModal = new AccountDetailsModal(driver); await accountDetailsModal.check_pageIsLoaded(); await accountDetailsModal.check_addressInAccountDetailsModal( - testAddress.toLowerCase(), + DEFAULT_FIXTURE_ACCOUNT.toLowerCase(), ); }, ); From 69e793c61598aea736a145a8727b5c5aff94a5f5 Mon Sep 17 00:00:00 2001 From: Chloe Gao Date: Wed, 18 Dec 2024 11:48:50 +0100 Subject: [PATCH 06/10] fix --- test/e2e/page-objects/pages/account-list-page.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/e2e/page-objects/pages/account-list-page.ts b/test/e2e/page-objects/pages/account-list-page.ts index f8988eaef8b4..8aa83043743e 100644 --- a/test/e2e/page-objects/pages/account-list-page.ts +++ b/test/e2e/page-objects/pages/account-list-page.ts @@ -113,11 +113,6 @@ class AccountListPage { tag: 'button', }; - private readonly watchAccountModalTitle = { - text: 'Watch any Ethereum account', - tag: 'h4', - }; - private readonly watchAccountAddressInput = 'input#address-input[type="text"]'; @@ -126,6 +121,11 @@ class AccountListPage { tag: 'button', }; + private readonly watchAccountModalTitle = { + text: 'Watch any Ethereum account', + tag: 'h4', + }; + constructor(driver: Driver) { this.driver = driver; } From 478a34d9232c3cbb45612e0996e241a0dde01425 Mon Sep 17 00:00:00 2001 From: Chloe Gao Date: Wed, 18 Dec 2024 12:33:09 +0100 Subject: [PATCH 07/10] fix test --- test/e2e/page-objects/pages/dialog/account-details-modal.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/page-objects/pages/dialog/account-details-modal.ts b/test/e2e/page-objects/pages/dialog/account-details-modal.ts index b36b9076c8f4..0e204cdb322f 100644 --- a/test/e2e/page-objects/pages/dialog/account-details-modal.ts +++ b/test/e2e/page-objects/pages/dialog/account-details-modal.ts @@ -9,7 +9,7 @@ class AccountDetailsModal { private readonly accountQrCodeImage = '.qr-code__wrapper'; - private readonly closeAccountModalButton = 'button[aria-label="Close"]'; + private readonly closeAccountModalButton = 'header button[aria-label="Close"]'; private readonly copyAddressButton = '[data-testid="address-copy-button-text"]'; From f149e45529b571f1ef660e32fb14a4c3f18b8923 Mon Sep 17 00:00:00 2001 From: Chloe Gao Date: Wed, 18 Dec 2024 14:27:06 +0100 Subject: [PATCH 08/10] fix --- test/e2e/page-objects/pages/dialog/account-details-modal.ts | 3 ++- .../account-syncing/sync-with-account-balances.spec.ts | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/test/e2e/page-objects/pages/dialog/account-details-modal.ts b/test/e2e/page-objects/pages/dialog/account-details-modal.ts index 0e204cdb322f..0dbb2e0f87d7 100644 --- a/test/e2e/page-objects/pages/dialog/account-details-modal.ts +++ b/test/e2e/page-objects/pages/dialog/account-details-modal.ts @@ -9,7 +9,8 @@ class AccountDetailsModal { private readonly accountQrCodeImage = '.qr-code__wrapper'; - private readonly closeAccountModalButton = 'header button[aria-label="Close"]'; + private readonly closeAccountModalButton = + 'header button[aria-label="Close"]'; private readonly copyAddressButton = '[data-testid="address-copy-button-text"]'; diff --git a/test/e2e/tests/identity/account-syncing/sync-with-account-balances.spec.ts b/test/e2e/tests/identity/account-syncing/sync-with-account-balances.spec.ts index eed6d9fcbe75..129567584e98 100644 --- a/test/e2e/tests/identity/account-syncing/sync-with-account-balances.spec.ts +++ b/test/e2e/tests/identity/account-syncing/sync-with-account-balances.spec.ts @@ -159,6 +159,9 @@ describe('Account syncing - User already has balances on multple accounts @no-mm // Rename Account 6 to verify update to user storage await accountListPage.switchToAccount('Account 6'); + await header.check_accountLabel('Account 6'); + await header.openAccountMenu(); + await accountListPage.check_pageIsLoaded(); await accountListPage.openAccountDetailsModal('Account 6'); const accountDetailsModal = new AccountDetailsModal(driver); await accountDetailsModal.check_pageIsLoaded(); From b7d2c81e65b64d9d94bce4192717d4d3993239d3 Mon Sep 17 00:00:00 2001 From: Chloe Gao Date: Thu, 19 Dec 2024 15:14:24 +0100 Subject: [PATCH 09/10] improve add account flow --- test/e2e/constants.ts | 7 ++ test/e2e/flask/btc/common-btc.ts | 4 +- test/e2e/flask/btc/create-btc-account.spec.ts | 6 +- test/e2e/flask/solana/common-solana.ts | 7 +- .../solana/create-solana-account.spec.ts | 7 +- test/e2e/page-objects/common.ts | 6 -- .../page-objects/pages/account-list-page.ts | 70 ++++++++----------- .../tests/account/account-custom-name.spec.ts | 6 +- test/e2e/tests/account/add-account.spec.ts | 13 +++- .../account-syncing/new-user-sync.spec.ts | 6 +- .../onboarding-with-opt-out.spec.ts | 7 +- .../sync-after-adding-account.spec.ts | 10 ++- .../sync-with-account-balances.spec.ts | 5 +- test/e2e/tests/tokens/nft/import-nft.spec.ts | 5 +- 14 files changed, 92 insertions(+), 67 deletions(-) diff --git a/test/e2e/constants.ts b/test/e2e/constants.ts index 9d4d5bbf3c8d..6af1056d7232 100644 --- a/test/e2e/constants.ts +++ b/test/e2e/constants.ts @@ -76,3 +76,10 @@ export const DEFAULT_SOLANA_BALANCE = 1; // SOL /* Title of the mocked E2E test empty HTML page */ export const EMPTY_E2E_TEST_PAGE_TITLE = 'E2E Test Page'; + +/* Account types */ +export enum ACCOUNT_TYPE { + Ethereum, + Bitcoin, + Solana, +} diff --git a/test/e2e/flask/btc/common-btc.ts b/test/e2e/flask/btc/common-btc.ts index db2db85eb554..ea9cb6b1f2e6 100644 --- a/test/e2e/flask/btc/common-btc.ts +++ b/test/e2e/flask/btc/common-btc.ts @@ -2,6 +2,7 @@ import { Mockttp } from 'mockttp'; import FixtureBuilder from '../../fixture-builder'; import { withFixtures } from '../../helpers'; import { + ACCOUNT_TYPE, DEFAULT_BTC_ACCOUNT, DEFAULT_BTC_BALANCE, DEFAULT_BTC_FEES_RATE, @@ -14,7 +15,6 @@ import { Driver } from '../../webdriver/driver'; import { loginWithBalanceValidation } from '../../page-objects/flows/login.flow'; import AccountListPage from '../../page-objects/pages/account-list-page'; import HeaderNavbar from '../../page-objects/pages/header-navbar'; -import { ACCOUNT_TYPE } from '../../page-objects/common'; const QUICKNODE_URL_REGEX = /^https:\/\/.*\.btc.*\.quiknode\.pro(\/|$)/u; @@ -218,7 +218,7 @@ export async function withBtcAccountSnap( await new HeaderNavbar(driver).openAccountMenu(); const accountListPage = new AccountListPage(driver); await accountListPage.check_pageIsLoaded(); - await accountListPage.addAccount(ACCOUNT_TYPE.Bitcoin, ''); + await accountListPage.addAccount({ accountType: ACCOUNT_TYPE.Bitcoin }); await test(driver, mockServer); }, ); diff --git a/test/e2e/flask/btc/create-btc-account.spec.ts b/test/e2e/flask/btc/create-btc-account.spec.ts index a223e503c1b2..68cdcd82caf5 100644 --- a/test/e2e/flask/btc/create-btc-account.spec.ts +++ b/test/e2e/flask/btc/create-btc-account.spec.ts @@ -8,7 +8,7 @@ import LoginPage from '../../page-objects/pages/login-page'; import PrivacySettings from '../../page-objects/pages/settings/privacy-settings'; import ResetPasswordPage from '../../page-objects/pages/reset-password-page'; import SettingsPage from '../../page-objects/pages/settings/settings-page'; -import { ACCOUNT_TYPE } from '../../page-objects/common'; +import { ACCOUNT_TYPE } from '../../constants'; import { withBtcAccountSnap } from './common-btc'; describe('Create BTC Account', function (this: Suite) { @@ -100,7 +100,7 @@ describe('Create BTC Account', function (this: Suite) { ); await accountListPage.closeAccountModal(); await headerNavbar.openAccountMenu(); - await accountListPage.addAccount(ACCOUNT_TYPE.Bitcoin, ''); + await accountListPage.addAccount({ accountType: ACCOUNT_TYPE.Bitcoin }); await headerNavbar.check_accountLabel('Bitcoin Account'); await headerNavbar.openAccountMenu(); @@ -156,7 +156,7 @@ describe('Create BTC Account', function (this: Suite) { await headerNavbar.check_pageIsLoaded(); await headerNavbar.openAccountMenu(); await accountListPage.check_pageIsLoaded(); - await accountListPage.addAccount(ACCOUNT_TYPE.Bitcoin, ''); + await accountListPage.addAccount({ accountType: ACCOUNT_TYPE.Bitcoin }); await headerNavbar.check_accountLabel('Bitcoin Account'); await headerNavbar.openAccountMenu(); diff --git a/test/e2e/flask/solana/common-solana.ts b/test/e2e/flask/solana/common-solana.ts index 2ac107bb442c..ac36d5ebed86 100644 --- a/test/e2e/flask/solana/common-solana.ts +++ b/test/e2e/flask/solana/common-solana.ts @@ -4,7 +4,7 @@ import { Driver } from '../../webdriver/driver'; import HeaderNavbar from '../../page-objects/pages/header-navbar'; import AccountListPage from '../../page-objects/pages/account-list-page'; import FixtureBuilder from '../../fixture-builder'; -import { ACCOUNT_TYPE } from '../../page-objects/common'; +import { ACCOUNT_TYPE } from '../../constants'; import { loginWithBalanceValidation } from '../../page-objects/flows/login.flow'; const SOLANA_URL_REGEX = /^https:\/\/.*\.solana.*/u; @@ -64,7 +64,10 @@ export async function withSolanaAccountSnap( const headerComponen = new HeaderNavbar(driver); await headerComponen.openAccountMenu(); const accountListPage = new AccountListPage(driver); - await accountListPage.addAccount(ACCOUNT_TYPE.Solana, 'Solana 1'); + await accountListPage.addAccount({ + accountType: ACCOUNT_TYPE.Solana, + accountName: 'Solana 1', + }); await test(driver, mockServer); }, ); diff --git a/test/e2e/flask/solana/create-solana-account.spec.ts b/test/e2e/flask/solana/create-solana-account.spec.ts index cca4f5222993..0cac9fab7375 100644 --- a/test/e2e/flask/solana/create-solana-account.spec.ts +++ b/test/e2e/flask/solana/create-solana-account.spec.ts @@ -1,7 +1,7 @@ import { Suite } from 'mocha'; import HeaderNavbar from '../../page-objects/pages/header-navbar'; import AccountListPage from '../../page-objects/pages/account-list-page'; -import { ACCOUNT_TYPE } from '../../page-objects/common'; +import { ACCOUNT_TYPE } from '../../constants'; import { withSolanaAccountSnap } from './common-solana'; // Scenarios skipped due to https://consensyssoftware.atlassian.net/browse/SOL-87 @@ -17,7 +17,10 @@ describe('Create Solana Account', function (this: Suite) { await headerNavbar.openAccountMenu(); const accountListPage = new AccountListPage(driver); await accountListPage.check_accountDisplayedInAccountList('Account 1'); - await accountListPage.addAccount(ACCOUNT_TYPE.Solana, 'Solana 2'); + await accountListPage.addAccount({ + accountType: ACCOUNT_TYPE.Solana, + accountName: 'Solana 2', + }); await headerNavbar.check_accountLabel('Solana 2'); await headerNavbar.openAccountMenu(); await accountListPage.check_numberOfAvailableAccounts(3); diff --git a/test/e2e/page-objects/common.ts b/test/e2e/page-objects/common.ts index 40eb625d94ac..5bf1a91e1859 100644 --- a/test/e2e/page-objects/common.ts +++ b/test/e2e/page-objects/common.ts @@ -2,9 +2,3 @@ export type RawLocator = | string | { css?: string; text?: string } | { tag: string; text: string }; - -export enum ACCOUNT_TYPE { - Ethereum, - Bitcoin, - Solana, -} diff --git a/test/e2e/page-objects/pages/account-list-page.ts b/test/e2e/page-objects/pages/account-list-page.ts index 21217a273e5c..92eede81652b 100644 --- a/test/e2e/page-objects/pages/account-list-page.ts +++ b/test/e2e/page-objects/pages/account-list-page.ts @@ -1,13 +1,11 @@ import { Driver } from '../../webdriver/driver'; import { largeDelayMs, regularDelayMs } from '../../helpers'; import messages from '../../../../app/_locales/en/messages.json'; -import { ACCOUNT_TYPE } from '../common'; +import { ACCOUNT_TYPE } from '../../constants'; class AccountListPage { private readonly driver: Driver; - private readonly accountAddressText = '.qr-code__address-segments'; - private readonly accountListAddressItem = '[data-testid="account-list-address"]'; @@ -181,37 +179,6 @@ class AccountListPage { } } - /** - * Adds a new account with an optional custom label. - * - * @param customLabel - The custom label for the new account. If not provided, a default name will be used. - */ - async addNewAccount(customLabel?: string): Promise { - if (customLabel) { - console.log(`Adding new account with custom label: ${customLabel}`); - } else { - console.log(`Adding new account with default name`); - } - await this.driver.clickElement(this.createAccountButton); - await this.driver.clickElement(this.addEthereumAccountButton); - if (customLabel) { - await this.driver.fill(this.accountNameInput, customLabel); - } - // needed to mitigate a race condition with the state update - // there is no condition we can wait for in the UI - await this.driver.delay(largeDelayMs); - await this.driver.clickElementAndWaitToDisappear( - this.addAccountConfirmButton, - ); - } - - async isBtcAccountCreationButtonEnabled() { - const createButton = await this.driver.findElement( - this.addBtcAccountButton, - ); - return await createButton.isEnabled(); - } - /** * Import a new account with a private key. * @@ -242,20 +209,27 @@ class AccountListPage { /** * Adds a new account of the specified type with an optional custom name. * - * @param accountType - The type of account to add (Ethereum, Bitcoin, or Solana) - * @param accountName - Optional custom name for the new account + * @param options - Options for adding a new account + * @param options.accountType - The type of account to add (Ethereum, Bitcoin, or Solana) + * @param [options.accountName] - Optional custom name for the new account * @throws {Error} If the specified account type is not supported * @example * // Add a new Ethereum account with default name - * await accountListPage.addAccount(ACCOUNT_TYPE.Ethereum); + * await accountListPage.addAccount({ accountType: ACCOUNT_TYPE.Ethereum }); * * // Add a new Bitcoin account with custom name - * await accountListPage.addAccount(ACCOUNT_TYPE.Bitcoin, 'My BTC Wallet'); + * await accountListPage.addAccount({ accountType: ACCOUNT_TYPE.Bitcoin, accountName: 'My BTC Wallet' }); */ - async addAccount(accountType: ACCOUNT_TYPE, accountName?: string) { + async addAccount({ + accountType, + accountName, + }: { + accountType: ACCOUNT_TYPE; + accountName?: string; + }) { + console.log(`Adding new account of type: ${ACCOUNT_TYPE[accountType]}`); await this.driver.clickElement(this.createAccountButton); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let addAccountButton: any; + let addAccountButton; switch (accountType) { case ACCOUNT_TYPE.Ethereum: addAccountButton = this.addEthereumAccountButton; @@ -272,9 +246,14 @@ class AccountListPage { await this.driver.clickElement(addAccountButton); if (accountName) { + console.log( + `Customize the new account with account name: ${accountName}`, + ); await this.driver.fill(this.accountNameInput, accountName); } - + // needed to mitigate a race condition with the state update + // there is no condition we can wait for in the UI + await this.driver.delay(largeDelayMs); await this.driver.clickElementAndWaitToDisappear( this.addAccountConfirmButton, 5000, @@ -319,6 +298,13 @@ class AccountListPage { ); } + async isBtcAccountCreationButtonEnabled(): Promise { + const createButton = await this.driver.findElement( + this.addBtcAccountButton, + ); + return await createButton.isEnabled(); + } + /** * Open the account details modal for the specified account in account list. * diff --git a/test/e2e/tests/account/account-custom-name.spec.ts b/test/e2e/tests/account/account-custom-name.spec.ts index 776b182f7956..92302e032224 100644 --- a/test/e2e/tests/account/account-custom-name.spec.ts +++ b/test/e2e/tests/account/account-custom-name.spec.ts @@ -1,6 +1,7 @@ import { Suite } from 'mocha'; import { Driver } from '../../webdriver/driver'; import { withFixtures } from '../../helpers'; +import { ACCOUNT_TYPE } from '../../constants'; import FixtureBuilder from '../../fixture-builder'; import { loginWithBalanceValidation } from '../../page-objects/flows/login.flow'; import AccountDetailsModal from '../../page-objects/pages/dialog/account-details-modal'; @@ -36,7 +37,10 @@ describe('Account Custom Name Persistence', function (this: Suite) { // Add new account with custom label and verify new added account label await headerNavbar.openAccountMenu(); await accountListPage.check_pageIsLoaded(); - await accountListPage.addNewAccount(anotherAccountLabel); + await accountListPage.addAccount({ + accountType: ACCOUNT_TYPE.Ethereum, + accountName: anotherAccountLabel, + }); await headerNavbar.check_accountLabel(anotherAccountLabel); // Switch back to the first account and verify first custom account persists diff --git a/test/e2e/tests/account/add-account.spec.ts b/test/e2e/tests/account/add-account.spec.ts index db62927b91d7..2df140899212 100644 --- a/test/e2e/tests/account/add-account.spec.ts +++ b/test/e2e/tests/account/add-account.spec.ts @@ -1,5 +1,6 @@ import { E2E_SRP } from '../../default-fixture'; import FixtureBuilder from '../../fixture-builder'; +import { ACCOUNT_TYPE } from '../../constants'; import { WALLET_PASSWORD, defaultGanacheOptions, @@ -43,7 +44,9 @@ describe('Add account', function () { const newAccountName = 'Account 2'; const accountListPage = new AccountListPage(driver); await accountListPage.check_pageIsLoaded(); - await accountListPage.addNewAccount(); + await accountListPage.addAccount({ + accountType: ACCOUNT_TYPE.Ethereum, + }); await headerNavbar.check_accountLabel(newAccountName); await homePage.check_expectedBalanceIsDisplayed(); @@ -112,7 +115,9 @@ describe('Add account', function () { const newAccountName = 'Account 2'; const accountListPage = new AccountListPage(driver); await accountListPage.check_pageIsLoaded(); - await accountListPage.addNewAccount(); + await accountListPage.addAccount({ + accountType: ACCOUNT_TYPE.Ethereum, + }); await headerNavbar.check_accountLabel(newAccountName); await homePage.check_expectedBalanceIsDisplayed(); @@ -177,7 +182,9 @@ describe('Add account', function () { // Create new account with default name Account 2 const accountListPage = new AccountListPage(driver); await accountListPage.check_pageIsLoaded(); - await accountListPage.addNewAccount(); + await accountListPage.addAccount({ + accountType: ACCOUNT_TYPE.Ethereum, + }); await headerNavbar.check_accountLabel('Account 2'); await homePage.check_expectedBalanceIsDisplayed(); diff --git a/test/e2e/tests/identity/account-syncing/new-user-sync.spec.ts b/test/e2e/tests/identity/account-syncing/new-user-sync.spec.ts index e9a82b128352..64a3ddbf5fd7 100644 --- a/test/e2e/tests/identity/account-syncing/new-user-sync.spec.ts +++ b/test/e2e/tests/identity/account-syncing/new-user-sync.spec.ts @@ -2,6 +2,7 @@ import { Mockttp } from 'mockttp'; import { USER_STORAGE_FEATURE_NAMES } from '@metamask/profile-sync-controller/sdk'; import { withFixtures } from '../../../helpers'; import FixtureBuilder from '../../../fixture-builder'; +import { ACCOUNT_TYPE } from '../../../constants'; import { mockIdentityServices } from '../mocks'; import { IDENTITY_TEAM_PASSWORD } from '../constants'; import { UserStorageMockttpController } from '../../../helpers/identity/user-storage/userStorageMockttpController'; @@ -64,7 +65,10 @@ describe('Account syncing - New User @no-mmi', function () { // Add a second account await accountListPage.openAccountOptionsMenu(); - await accountListPage.addNewAccount('My Second Account'); + await accountListPage.addAccount({ + accountType: ACCOUNT_TYPE.Ethereum, + accountName: 'My Second Account', + }); // Set SRP to use for retreival const headerNavbar = new HeaderNavbar(driver); diff --git a/test/e2e/tests/identity/account-syncing/onboarding-with-opt-out.spec.ts b/test/e2e/tests/identity/account-syncing/onboarding-with-opt-out.spec.ts index 19908211181b..bd063c182baf 100644 --- a/test/e2e/tests/identity/account-syncing/onboarding-with-opt-out.spec.ts +++ b/test/e2e/tests/identity/account-syncing/onboarding-with-opt-out.spec.ts @@ -7,6 +7,7 @@ import { IDENTITY_TEAM_PASSWORD, IDENTITY_TEAM_SEED_PHRASE, } from '../constants'; +import { ACCOUNT_TYPE } from '../../../constants'; import { UserStorageMockttpController } from '../../../helpers/identity/user-storage/userStorageMockttpController'; import AccountListPage from '../../../page-objects/pages/account-list-page'; import HeaderNavbar from '../../../page-objects/pages/header-navbar'; @@ -135,7 +136,11 @@ describe('Account syncing - Opt-out Profile Sync @no-mmi', function () { await accountListPage.check_accountDisplayedInAccountList( 'Account 1', ); - await accountListPage.addNewAccount('New Account'); + await accountListPage.addAccount({ + accountType: ACCOUNT_TYPE.Ethereum, + accountName: 'New Account', + }); + // Set SRP to use for retreival const headerNavbar = new HeaderNavbar(driver); await headerNavbar.check_pageIsLoaded(); diff --git a/test/e2e/tests/identity/account-syncing/sync-after-adding-account.spec.ts b/test/e2e/tests/identity/account-syncing/sync-after-adding-account.spec.ts index 9c2fdb69c7e9..e02833e7c172 100644 --- a/test/e2e/tests/identity/account-syncing/sync-after-adding-account.spec.ts +++ b/test/e2e/tests/identity/account-syncing/sync-after-adding-account.spec.ts @@ -3,6 +3,7 @@ import { USER_STORAGE_FEATURE_NAMES } from '@metamask/profile-sync-controller/sd import { withFixtures } from '../../../helpers'; import FixtureBuilder from '../../../fixture-builder'; import { mockIdentityServices } from '../mocks'; +import { ACCOUNT_TYPE } from '../../../constants'; import { IDENTITY_TEAM_PASSWORD, IDENTITY_TEAM_SEED_PHRASE, @@ -65,7 +66,10 @@ describe('Account syncing - Add Account @no-mmi', function () { await accountListPage.check_accountDisplayedInAccountList( 'My Second Synced Account', ); - await accountListPage.addNewAccount('My third account'); + await accountListPage.addAccount({ + accountType: ACCOUNT_TYPE.Ethereum, + accountName: 'My third account', + }); }, ); @@ -164,7 +168,9 @@ describe('Account syncing - Add Account @no-mmi', function () { await accountListPage.check_accountDisplayedInAccountList( 'My Second Synced Account', ); - await accountListPage.addNewAccount(); + await accountListPage.addAccount({ + accountType: ACCOUNT_TYPE.Ethereum, + }); }, ); diff --git a/test/e2e/tests/identity/account-syncing/sync-with-account-balances.spec.ts b/test/e2e/tests/identity/account-syncing/sync-with-account-balances.spec.ts index 129567584e98..ec52bb3124bd 100644 --- a/test/e2e/tests/identity/account-syncing/sync-with-account-balances.spec.ts +++ b/test/e2e/tests/identity/account-syncing/sync-with-account-balances.spec.ts @@ -6,6 +6,7 @@ import { IDENTITY_TEAM_PASSWORD, IDENTITY_TEAM_SEED_PHRASE, } from '../constants'; +import { ACCOUNT_TYPE } from '../../../constants'; import { UserStorageMockttpController } from '../../../helpers/identity/user-storage/userStorageMockttpController'; import HeaderNavbar from '../../../page-objects/pages/header-navbar'; import AccountDetailsModal from '../../../page-objects/pages/dialog/account-details-modal'; @@ -109,7 +110,9 @@ describe('Account syncing - User already has balances on multple accounts @no-mm } // Create new account and prepare for additional accounts - await accountListPage.addNewAccount(); + await accountListPage.addAccount({ + accountType: ACCOUNT_TYPE.Ethereum, + }); accountsToMock = [...INITIAL_ACCOUNTS, ...ADDITIONAL_ACCOUNTS]; }, ); diff --git a/test/e2e/tests/tokens/nft/import-nft.spec.ts b/test/e2e/tests/tokens/nft/import-nft.spec.ts index 5983d1002035..e151e83a355f 100644 --- a/test/e2e/tests/tokens/nft/import-nft.spec.ts +++ b/test/e2e/tests/tokens/nft/import-nft.spec.ts @@ -1,4 +1,5 @@ import { defaultGanacheOptions, withFixtures } from '../../../helpers'; +import { ACCOUNT_TYPE } from '../../../constants'; import { SMART_CONTRACTS } from '../../../seeder/smart-contracts'; import FixtureBuilder from '../../../fixture-builder'; import AccountListPage from '../../../page-objects/pages/account-list-page'; @@ -67,7 +68,9 @@ describe('Import NFT', function () { await headerNavbar.openAccountMenu(); const accountListPage = new AccountListPage(driver); await accountListPage.check_pageIsLoaded(); - await accountListPage.addNewAccount(); + await accountListPage.addAccount({ + accountType: ACCOUNT_TYPE.Ethereum, + }); await headerNavbar.check_accountLabel('Account 2'); await homepage.check_expectedBalanceIsDisplayed(); From ef2016bdceb5ad7df2c619a0844266e1b150f6d1 Mon Sep 17 00:00:00 2001 From: Chloe Gao Date: Fri, 20 Dec 2024 10:45:05 +0100 Subject: [PATCH 10/10] address comment --- test/e2e/flask/create-watch-account.spec.ts | 7 ++++++- test/e2e/page-objects/flows/watch-account.flow.ts | 6 ------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/test/e2e/flask/create-watch-account.spec.ts b/test/e2e/flask/create-watch-account.spec.ts index 326571e3c534..5cfca1dda5ef 100644 --- a/test/e2e/flask/create-watch-account.spec.ts +++ b/test/e2e/flask/create-watch-account.spec.ts @@ -32,6 +32,7 @@ describe('Account-watcher snap', function (this: Suite) { }, async ({ driver }: { driver: Driver }) => { // watch an EOA address + await loginWithBalanceValidation(driver); await watchEoaAddress(driver, EOA_ADDRESS); // new account should be displayed in the account list @@ -55,6 +56,7 @@ describe('Account-watcher snap', function (this: Suite) { }, async ({ driver }: { driver: Driver }) => { // watch an EOA address + await loginWithBalanceValidation(driver); await watchEoaAddress(driver, EOA_ADDRESS); const homePage = new HomePage(driver); await homePage.headerNavbar.check_accountLabel( @@ -153,6 +155,7 @@ describe('Account-watcher snap', function (this: Suite) { }, async ({ driver }: { driver: Driver }) => { // watch an EOA address for ACCOUNT_2 + await loginWithBalanceValidation(driver); await watchEoaAddress(driver, ACCOUNT_2); const headerNavbar = new HeaderNavbar(driver); await headerNavbar.check_accountLabel(DEFAULT_WATCHED_ACCOUNT_NAME); @@ -182,6 +185,7 @@ describe('Account-watcher snap', function (this: Suite) { }, async ({ driver }: { driver: Driver }) => { // watch an EOA address + await loginWithBalanceValidation(driver); await watchEoaAddress(driver, EOA_ADDRESS); // open account details modal in header navbar @@ -210,6 +214,7 @@ describe('Account-watcher snap', function (this: Suite) { }, async ({ driver }: { driver: Driver }) => { // watch an EOA address + await loginWithBalanceValidation(driver); await watchEoaAddress(driver, EOA_ADDRESS); const homePage = new HomePage(driver); await homePage.headerNavbar.check_accountLabel( @@ -233,7 +238,7 @@ describe('Account-watcher snap', function (this: Suite) { await homePage.check_expectedBalanceIsDisplayed(); // watch the same EOA address again and check the account is recreated - await watchEoaAddress(driver, EOA_ADDRESS, false); + await watchEoaAddress(driver, EOA_ADDRESS); await homePage.headerNavbar.check_accountLabel( DEFAULT_WATCHED_ACCOUNT_NAME, ); diff --git a/test/e2e/page-objects/flows/watch-account.flow.ts b/test/e2e/page-objects/flows/watch-account.flow.ts index 1a9b3f355a47..8481c71599a6 100644 --- a/test/e2e/page-objects/flows/watch-account.flow.ts +++ b/test/e2e/page-objects/flows/watch-account.flow.ts @@ -1,23 +1,17 @@ import { Driver } from '../../webdriver/driver'; import HomePage from '../pages/home/homepage'; import AccountListPage from '../pages/account-list-page'; -import { loginWithBalanceValidation } from './login.flow'; /** * Initiates the flow of watching an EOA address. * * @param driver - The WebDriver instance. * @param address - The EOA address that is to be watched. - * @param unlockWalletFirst - A boolean indicating whether the wallet should be unlocked before attempting to watch the address. Default is true. */ export async function watchEoaAddress( driver: Driver, address: string, - unlockWalletFirst: boolean = true, ): Promise { - if (unlockWalletFirst) { - await loginWithBalanceValidation(driver); - } // watch a new EOA const homePage = new HomePage(driver); await homePage.headerNavbar.openAccountMenu();