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 f563454ad1e6..68cdcd82caf5 100644 --- a/test/e2e/flask/btc/create-btc-account.spec.ts +++ b/test/e2e/flask/btc/create-btc-account.spec.ts @@ -1,13 +1,14 @@ 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'; 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) { @@ -82,9 +83,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,14 +100,15 @@ 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(); 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); }, @@ -123,9 +127,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,14 +156,16 @@ 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(); 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 f25f38f0b2ce..5cfca1dda5ef 100644 --- a/test/e2e/flask/create-watch-account.spec.ts +++ b/test/e2e/flask/create-watch-account.spec.ts @@ -1,70 +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 () { @@ -76,22 +28,17 @@ 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 loginWithBalanceValidation(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); }, ); }); @@ -105,40 +52,29 @@ 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 loginWithBalanceValidation(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.', ); }, ); @@ -182,20 +118,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); }, ); }); @@ -216,30 +151,23 @@ 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 loginWithBalanceValidation(driver); + 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', - }); }, ); }); @@ -253,62 +181,27 @@ 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); - - // 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, - }); + await loginWithBalanceValidation(driver); + await watchEoaAddress(driver, EOA_ADDRESS); + + // open account details modal in header navbar + const headerNavbar = new HeaderNavbar(driver); + await headerNavbar.check_accountLabel(DEFAULT_WATCHED_ACCOUNT_NAME); + await 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('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() @@ -317,113 +210,83 @@ 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 loginWithBalanceValidation(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); + 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( - '.settings-page__header__title-container__close-button', - ); - }; - - 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('header 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); }, ); }); @@ -432,27 +295,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/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/flows/watch-account.flow.ts b/test/e2e/page-objects/flows/watch-account.flow.ts new file mode 100644 index 000000000000..8481c71599a6 --- /dev/null +++ b/test/e2e/page-objects/flows/watch-account.flow.ts @@ -0,0 +1,22 @@ +import { Driver } from '../../webdriver/driver'; +import HomePage from '../pages/home/homepage'; +import AccountListPage from '../pages/account-list-page'; + +/** + * Initiates the flow of watching an EOA address. + * + * @param driver - The WebDriver instance. + * @param address - The EOA address that is to be watched. + */ +export async function watchEoaAddress( + driver: Driver, + address: string, +): Promise { + // 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 628d758e7e71..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"]'; @@ -28,10 +26,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"]'; @@ -48,6 +42,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 addHardwareWalletButton = { text: 'Add hardware wallet', tag: 'button', @@ -70,11 +67,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"]'; @@ -124,8 +116,18 @@ class AccountListPage { tag: 'button', }; - private readonly saveAccountLabelButton = - '[data-testid="save-account-label-input"]'; + private readonly watchAccountAddressInput = + 'input#address-input[type="text"]'; + + private readonly watchAccountConfirmButton = { + text: 'Watch account', + tag: 'button', + }; + + private readonly watchAccountModalTitle = { + text: 'Watch any Ethereum account', + tag: 'h4', + }; constructor(driver: Driver) { this.driver = driver; @@ -145,34 +147,36 @@ class AccountListPage { } /** - * Adds a new account with an optional custom label. + * Watch an EOA (external owned account). * - * @param customLabel - The custom label for the new account. If not provided, a default name will be used. + * @param address - The address to watch. + * @param expectedErrorMessage - Optional error message to display if the address is invalid. */ - 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`); - } + 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.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.clickElement(this.addEoaAccountButton); + await this.driver.waitForSelector(this.watchAccountModalTitle); + await this.driver.fill(this.watchAccountAddressInput, address); await this.driver.clickElementAndWaitToDisappear( - this.addAccountConfirmButton, + this.watchAccountConfirmButton, ); - } - - async isBtcAccountCreationButtonEnabled() { - const createButton = await this.driver.findElement( - this.addBtcAccountButton, - ); - return await createButton.isEnabled(); + 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, + ); + } } /** @@ -205,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; @@ -235,56 +246,20 @@ 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, ); } - /** - * 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( @@ -292,23 +267,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); @@ -340,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. * @@ -556,21 +521,24 @@ class AccountListPage { } /** - * Check that the correct address is displayed in the account details modal. + * Checks that the add watch account button is displayed in the create account modal. * - * @param expectedAddress - The expected address to check. + * @param expectedAvailability - Whether the add watch account button is expected to be displayed. */ - async check_addressInAccountDetailsModal( - expectedAddress: string, + async check_addWatchAccountAvailable( + expectedAvailability: boolean, ): Promise { console.log( - `Check that address ${expectedAddress} is displayed in account details modal`, + `Check add watch account button is ${ + expectedAvailability ? 'displayed ' : 'not displayed' + }`, ); - await this.driver.waitForSelector(this.accountQrCodeImage); - await this.driver.waitForSelector({ - css: this.accountQrCodeAddress, - text: expectedAddress, - }); + await this.openAddAccountModal(); + if (expectedAvailability) { + await this.driver.waitForSelector(this.addEoaAccountButton); + } else { + await this.driver.assertElementNotPresent(this.addEoaAccountButton); + } } /** 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..0dbb2e0f87d7 --- /dev/null +++ b/test/e2e/page-objects/pages/dialog/account-details-modal.ts @@ -0,0 +1,106 @@ +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 = + 'header 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(); + } + + 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_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 57e02e864624..e64fdc5a4cd7 100644 --- a/test/e2e/page-objects/pages/header-navbar.ts +++ b/test/e2e/page-objects/pages/header-navbar.ts @@ -9,6 +9,8 @@ class HeaderNavbar { private readonly allPermissionsButton = '[data-testid="global-menu-connected-sites"]'; + private readonly copyAddressButton = '[data-testid="app-header-copy-button"]'; + private readonly threeDotMenuButton = '[data-testid="account-options-menu-button"]'; @@ -19,6 +21,9 @@ 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"]'; @@ -51,6 +56,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); @@ -98,6 +109,21 @@ class HeaderNavbar { ); } + /** + * 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, + }); + } + /** * Verifies that the displayed account label in header matches the expected label. * 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 b4b79846fb06..708ae5ac0277 100644 --- a/test/e2e/page-objects/pages/home/homepage.ts +++ b/test/e2e/page-objects/pages/home/homepage.ts @@ -20,6 +20,9 @@ class HomePage { css: '.mm-banner-alert', }; + protected readonly bridgeButton: string = + '[data-testid="eth-overview-bridge"]'; + private readonly closeUseNetworkNotificationModalButton = { text: 'Got it', tag: 'h6', @@ -45,12 +48,15 @@ class HomePage { testId: 'sensitive-toggle', }; + protected readonly sendButton: string = '[data-testid="eth-overview-send"]'; + + 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', }; @@ -142,6 +148,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. * @@ -197,6 +210,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/page-objects/pages/settings/experimental-settings.ts b/test/e2e/page-objects/pages/settings/experimental-settings.ts index f551db6d47c5..69df0525093d 100644 --- a/test/e2e/page-objects/pages/settings/experimental-settings.ts +++ b/test/e2e/page-objects/pages/settings/experimental-settings.ts @@ -22,6 +22,12 @@ class ExperimentalSettings { private readonly requestQueueToggle = '[data-testid="experimental-setting-toggle-request-queue"] label'; + private readonly watchAccountToggleState = + '[data-testid="watch-account-toggle"]'; + + private readonly watchAccountToggle = + '[data-testid="watch-account-toggle-div"]'; + constructor(driver: Driver) { this.driver = driver; } @@ -39,6 +45,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({ @@ -62,6 +77,11 @@ class ExperimentalSettings { console.log('Toggle Request Queue on experimental setting page'); await this.driver.clickElement(this.requestQueueToggle); } + + 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/account/account-custom-name.spec.ts b/test/e2e/tests/account/account-custom-name.spec.ts index 4c0ecbe196f9..92302e032224 100644 --- a/test/e2e/tests/account/account-custom-name.spec.ts +++ b/test/e2e/tests/account/account-custom-name.spec.ts @@ -1,8 +1,10 @@ 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'; import AccountListPage from '../../page-objects/pages/account-list-page'; import HeaderNavbar from '../../page-objects/pages/header-navbar'; @@ -25,14 +27,20 @@ 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 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/account/import-flow.spec.ts b/test/e2e/tests/account/import-flow.spec.ts index dbb7b2f85d49..c8ffcc334e49 100644 --- a/test/e2e/tests/account/import-flow.spec.ts +++ b/test/e2e/tests/account/import-flow.spec.ts @@ -3,6 +3,7 @@ import { DEFAULT_FIXTURE_ACCOUNT } from '../../constants'; 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( DEFAULT_FIXTURE_ACCOUNT.toLowerCase(), ); }, 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-after-modifying-account-name.spec.ts b/test/e2e/tests/identity/account-syncing/sync-after-modifying-account-name.spec.ts index 07f6e4848aba..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 @@ -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,14 @@ 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..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,8 +6,10 @@ 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'; 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'; @@ -108,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]; }, ); @@ -158,11 +162,13 @@ 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'); - await accountListPage.changeLabelFromAccountDetailsModal( - 'My Renamed Account 6', - ); + const accountDetailsModal = new AccountDetailsModal(driver); + await accountDetailsModal.check_pageIsLoaded(); + await accountDetailsModal.changeAccountLabel('My Renamed Account 6'); }, ); 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();