diff --git a/test/e2e/helpers.js b/test/e2e/helpers.js index c857838f0810..ab5801afa30e 100644 --- a/test/e2e/helpers.js +++ b/test/e2e/helpers.js @@ -435,6 +435,7 @@ const completeImportSRPOnboardingFlowWordByWord = async ( await driver.clickElement('[data-testid="onboarding-import-wallet"]'); // metrics + await driver.clickElement('[data-testid="metametrics-no-thanks"]'); // import with recovery phrase, word by word @@ -564,9 +565,40 @@ const onboardingPinExtension = async (driver) => { await driver.clickElement('[data-testid="pin-extension-done"]'); }; -const onboardingCompleteWalletCreationWithOptOut = async (driver) => { +/** + * Completes the onboarding flow with optional opt-out settings for wallet creation. + * + * This function navigates through the onboarding process, allowing for opt-out of certain features. + * It waits for the appropriate heading to appear, then proceeds to opt-out of third-party API + * integration for general and assets sections if specified in the optOutOptions. + * + * @param {WebDriver} driver - The Selenium WebDriver instance. + * @param {object} optOutOptions - Optional. An object specifying which features to opt-out of. + * @param {boolean} optOutOptions.basicFunctionality - Optional. Defaults to true. Opt-out of basic functionality. + * @param {boolean} optOutOptions.profileSync - Optional. Defaults to true. Opt-out of profile sync. + * @param {boolean} optOutOptions.assets - Optional. Defaults to true. Opt-out of assets options. + * @param {boolean} optOutOptions.isNewWallet - Optional. Defaults to true. Indicates if this is a new wallet creation. + */ +const onboardingCompleteWalletCreationWithOptOut = async ( + driver, + optOutOptions = {}, +) => { + const defaultOptOutOptions = { + basicFunctionality: true, + profileSync: true, + assets: true, + isNewWallet: true, + }; + + const optOutOptionsToUse = { ...defaultOptOutOptions, ...optOutOptions }; + // wait for h2 to appear - await driver.findElement({ text: 'Congratulations!', tag: 'h2' }); + await driver.findElement({ + text: optOutOptionsToUse.isNewWallet + ? 'Congratulations' + : 'Your wallet is ready', + tag: 'h2', + }); // opt-out from third party API on general section await driver.clickElementAndWaitToDisappear({ @@ -574,27 +606,44 @@ const onboardingCompleteWalletCreationWithOptOut = async (driver) => { tag: 'button', }); await driver.clickElement({ text: 'General', tag: 'p' }); - await driver.clickElement( - '[data-testid="basic-functionality-toggle"] .toggle-button', - ); - await driver.clickElement('[id="basic-configuration-checkbox"]'); - await driver.clickElementAndWaitToDisappear({ - tag: 'button', - text: 'Turn off', - }); - // opt-out from third party API on assets section - await driver.clickElement('[data-testid="category-back-button"]'); - await driver.clickElement({ text: 'Assets', tag: 'p' }); - await Promise.all( - ( - await driver.findClickableElements( - '.toggle-button.toggle-button--on:not([data-testid="basic-functionality-toggle"] .toggle-button)', - ) - ).map((toggle) => toggle.click()), - ); + if (optOutOptionsToUse.basicFunctionality) { + await driver.clickElement( + '[data-testid="basic-functionality-toggle"] .toggle-button', + ); + await driver.clickElement('[id="basic-configuration-checkbox"]'); + await driver.clickElementAndWaitToDisappear({ + tag: 'button', + text: 'Turn off', + }); + } + + if (optOutOptionsToUse.profileSync) { + await driver.clickElement( + '[data-testid="profile-sync-toggle"] .toggle-button', + ); + await driver.clickElementAndWaitToDisappear({ + tag: 'button', + text: 'Turn off', + }); + } + await driver.clickElement('[data-testid="category-back-button"]'); + if (optOutOptionsToUse.assets) { + // opt-out from third party API on assets section + await driver.clickElement({ text: 'Assets', tag: 'p' }); + await Promise.all( + ( + await driver.findClickableElements( + '.toggle-button.toggle-button--on:not([data-testid="basic-functionality-toggle"] .toggle-button)', + ) + ).map((toggle) => toggle.click()), + ); + + await driver.clickElement('[data-testid="category-back-button"]'); + } + // Wait until the onboarding carousel has stopped moving // otherwise the click has no effect. await driver.waitForElementToStopMoving( @@ -610,15 +659,30 @@ const onboardingCompleteWalletCreationWithOptOut = async (driver) => { await onboardingPinExtension(driver); }; +/** + * Completes the onboarding flow for creating a new wallet with opt-out options. + * + * This function guides the user through the onboarding process of creating a new wallet, + * including opting out of certain features as specified by the `optOutOptions` parameter. + * + * @param {object} driver - The Selenium driver instance. + * @param {string} password - The password to use for the new wallet. + * @param {object} optOutOptions - An object specifying the features to opt out of. + * @param {boolean} optOutOptions.isNewWallet - Indicates if this is a new wallet creation. + * @param {boolean} optOutOptions.basicFunctionality - Indicates if basic functionality should be opted out. + * @param {boolean} optOutOptions.profileSync - Indicates if profile sync should be opted out. + * @param {boolean} optOutOptions.assets - Indicates if assets should be opted out. + */ const completeCreateNewWalletOnboardingFlowWithOptOut = async ( driver, password, + optOutOptions, ) => { await onboardingBeginCreateNewWallet(driver); await onboardingChooseMetametricsOption(driver, false); await onboardingCreatePassword(driver, password); await onboardingRevealAndConfirmSRP(driver); - await onboardingCompleteWalletCreationWithOptOut(driver); + await onboardingCompleteWalletCreationWithOptOut(driver, optOutOptions); }; const completeCreateNewWalletOnboardingFlow = async (driver, password) => { @@ -1323,6 +1387,7 @@ module.exports = { onboardingCreatePassword, onboardingRevealAndConfirmSRP, onboardingCompleteWalletCreation, + onboardingCompleteWalletCreationWithOptOut, onboardingPinExtension, assertInAnyOrder, genRandInitBal, diff --git a/test/e2e/page-objects/pages/account-list-page.ts b/test/e2e/page-objects/pages/account-list-page.ts index 7218c727a929..ae02973b6ae5 100644 --- a/test/e2e/page-objects/pages/account-list-page.ts +++ b/test/e2e/page-objects/pages/account-list-page.ts @@ -20,9 +20,15 @@ class AccountListPage { private readonly addAccountConfirmButton = '[data-testid="submit-add-account-with-name"]'; + private readonly importAccountConfirmButton = + '[data-testid="import-account-confirm-button"]'; + private readonly addEthereumAccountButton = '[data-testid="multichain-account-menu-popover-add-account"]'; + private readonly addImportedAccountButton = + '[data-testid="multichain-account-menu-popover-add-imported-account"]'; + private readonly addSnapAccountButton = { text: 'Add account Snap', tag: 'button', @@ -54,6 +60,8 @@ class AccountListPage { private readonly saveAccountLabelButton = '[data-testid="save-account-label-input"]'; + private readonly importAccountPrivateKeyInput = '#private-key-box'; + constructor(driver: Driver) { this.driver = driver; } @@ -86,6 +94,34 @@ class AccountListPage { ); } + /** + * Adds a new account with default next available name. + * + */ + async addNewAccountWithDefaultName(): Promise { + console.log(`Adding new account with next available name`); + await this.driver.clickElement(this.createAccountButton); + await this.driver.clickElement(this.addEthereumAccountButton); + await this.driver.clickElementAndWaitToDisappear( + this.addAccountConfirmButton, + ); + } + + /** + * Adds a new account with a custom label. + * + * @param privateKey - Private key of the account + */ + async addNewImportedAccount(privateKey: string): Promise { + console.log(`Adding new imported account`); + await this.driver.clickElement(this.createAccountButton); + await this.driver.clickElement(this.addImportedAccountButton); + await this.driver.fill(this.importAccountPrivateKeyInput, privateKey); + await this.driver.clickElementAndWaitToDisappear( + this.importAccountConfirmButton, + ); + } + /** * Changes the label of the current account. * @@ -227,6 +263,25 @@ class AccountListPage { console.log(`Check that hidden accounts list is displayed in account list`); await this.driver.waitForSelector(this.hiddenAccountsList); } + + /** + * Verifies number of accounts currently showing in the accounts menu. + * + * @param expectedNumberOfAccounts - The expected number of accounts showing. + */ + async check_numberOfAvailableAccounts( + expectedNumberOfAccounts: number, + ): Promise { + console.log( + `Verify the number of accounts in the account menu is: ${expectedNumberOfAccounts}`, + ); + await this.driver.wait(async () => { + const internalAccounts = await this.driver.findElements( + this.accountListItem, + ); + return internalAccounts.length === expectedNumberOfAccounts; + }, 20000); + } } export default AccountListPage; diff --git a/test/e2e/tests/notifications/account-syncing/helpers.ts b/test/e2e/tests/notifications/account-syncing/helpers.ts index e54a5f6f96ae..5e2694067eed 100644 --- a/test/e2e/tests/notifications/account-syncing/helpers.ts +++ b/test/e2e/tests/notifications/account-syncing/helpers.ts @@ -1,3 +1,18 @@ import { isManifestV3 } from '../../../../../shared/modules/mv3.utils'; +import { + completeSRPRevealQuiz, + openSRPRevealQuiz, + tapAndHoldToRevealSRP, +} from '../../../helpers'; +import { Driver } from '../../../webdriver/driver'; export const IS_ACCOUNT_SYNCING_ENABLED = isManifestV3; + +export const getSRP = async (driver: Driver, password: string) => { + await openSRPRevealQuiz(driver); + await completeSRPRevealQuiz(driver); + await driver.fill('[data-testid="input-password"]', password); + await driver.press('[data-testid="input-password"]', driver.Key.ENTER); + await tapAndHoldToRevealSRP(driver); + return (await driver.findElement('[data-testid="srp_text"]')).getText(); +}; diff --git a/test/e2e/tests/notifications/account-syncing/sync-after-adding-custom-name-account.spec.ts b/test/e2e/tests/notifications/account-syncing/importing-private-key-account.spec.ts similarity index 57% rename from test/e2e/tests/notifications/account-syncing/sync-after-adding-custom-name-account.spec.ts rename to test/e2e/tests/notifications/account-syncing/importing-private-key-account.spec.ts index 6ca7c501fc84..1494d8b2ceb3 100644 --- a/test/e2e/tests/notifications/account-syncing/sync-after-adding-custom-name-account.spec.ts +++ b/test/e2e/tests/notifications/account-syncing/importing-private-key-account.spec.ts @@ -7,19 +7,22 @@ import { import FixtureBuilder from '../../../fixture-builder'; import { mockNotificationServices } from '../mocks'; import { + NOTIFICATIONS_TEAM_IMPORTED_PRIVATE_KEY, NOTIFICATIONS_TEAM_PASSWORD, NOTIFICATIONS_TEAM_SEED_PHRASE, } from '../constants'; import { UserStorageMockttpController } from '../../../helpers/user-storage/userStorageMockttpController'; +import HeaderNavbar from '../../../page-objects/pages/header-navbar'; +import AccountListPage from '../../../page-objects/pages/account-list-page'; import { accountsSyncMockResponse } from './mockData'; import { IS_ACCOUNT_SYNCING_ENABLED } from './helpers'; -describe('Account syncing @no-mmi', function () { +describe('Account syncing - Import With Private Key @no-mmi', function () { if (!IS_ACCOUNT_SYNCING_ENABLED) { return; } describe('from inside MetaMask', function () { - it('syncs newly added accounts', async function () { + it('does not sync accounts imported with private keys', async function () { const userStorageMockttpController = new UserStorageMockttpController(); await withFixtures( @@ -46,25 +49,24 @@ describe('Account syncing @no-mmi', function () { NOTIFICATIONS_TEAM_PASSWORD, ); - await driver.clickElement('[data-testid="account-menu-icon"]'); + const header = new HeaderNavbar(driver); + await header.check_pageIsLoaded(); + await header.openAccountMenu(); - await driver.wait(async () => { - const internalAccounts = await driver.findElements( - '.multichain-account-list-item', - ); - return internalAccounts.length === accountsSyncMockResponse.length; - }, 20000); - - await driver.clickElement( - '[data-testid="multichain-account-menu-popover-action-button"]', + const accountListPage = new AccountListPage(driver); + await accountListPage.check_pageIsLoaded(); + await accountListPage.check_numberOfAvailableAccounts( + accountsSyncMockResponse.length, ); - await driver.clickElement( - '[data-testid="multichain-account-menu-popover-add-account"]', + await accountListPage.check_accountDisplayedInAccountList( + 'My First Synced Account', ); - await driver.fill('#account-name', 'My third account'); - - await driver.clickElementAndWaitToDisappear( - '[data-testid="submit-add-account-with-name"]', + await accountListPage.check_accountDisplayedInAccountList( + 'My Second Synced Account', + ); + await accountListPage.openAccountOptionsMenu(); + await accountListPage.addNewImportedAccount( + NOTIFICATIONS_TEAM_IMPORTED_PRIVATE_KEY, ); }, ); @@ -90,29 +92,19 @@ describe('Account syncing @no-mmi', function () { NOTIFICATIONS_TEAM_PASSWORD, ); - await driver.clickElement('[data-testid="account-menu-icon"]'); + const header = new HeaderNavbar(driver); + await header.check_pageIsLoaded(); + await header.openAccountMenu(); - await driver.wait(async () => { - const internalAccounts = await driver.findElements( - '.multichain-account-list-item', - ); - return ( - internalAccounts.length === - userStorageMockttpController.paths.get('accounts')?.response - .length - ); - }, 20000); - - await driver.wait(async () => { - const internalAccounts = await driver.findElements( - '.multichain-account-list-item .multichain-account-list-item__account-name', - ); - const lastAccountName = await internalAccounts[ - internalAccounts.length - 1 - ].getText(); - - return lastAccountName === 'My third account'; - }, 20000); + const accountListPage = new AccountListPage(driver); + await accountListPage.check_pageIsLoaded(); + await accountListPage.check_numberOfAvailableAccounts(2); + await accountListPage.check_accountDisplayedInAccountList( + 'My First Synced Account', + ); + await accountListPage.check_accountDisplayedInAccountList( + 'My Second Synced Account', + ); }, ); }); diff --git a/test/e2e/tests/notifications/account-syncing/new-user-sync.spec.ts b/test/e2e/tests/notifications/account-syncing/new-user-sync.spec.ts new file mode 100644 index 000000000000..eb0c2c7b65e8 --- /dev/null +++ b/test/e2e/tests/notifications/account-syncing/new-user-sync.spec.ts @@ -0,0 +1,118 @@ +import { Mockttp } from 'mockttp'; +import { + withFixtures, + defaultGanacheOptions, + completeImportSRPOnboardingFlow, + completeCreateNewWalletOnboardingFlow, +} from '../../../helpers'; +import FixtureBuilder from '../../../fixture-builder'; +import { mockNotificationServices } from '../mocks'; +import { NOTIFICATIONS_TEAM_PASSWORD } from '../constants'; +import { UserStorageMockttpController } from '../../../helpers/user-storage/userStorageMockttpController'; +import HeaderNavbar from '../../../page-objects/pages/header-navbar'; +import AccountListPage from '../../../page-objects/pages/account-list-page'; +import { getSRP, IS_ACCOUNT_SYNCING_ENABLED } from './helpers'; + +describe('Account syncing - New User @no-mmi', function () { + if (!IS_ACCOUNT_SYNCING_ENABLED) { + return; + } + + describe('from inside MetaMask', function () { + it('syncs after new wallet creation', async function () { + const userStorageMockttpController = new UserStorageMockttpController(); + let walletSrp: string; + + await withFixtures( + { + fixtures: new FixtureBuilder({ onboarding: true }).build(), + ganacheOptions: defaultGanacheOptions, + title: this.test?.fullTitle(), + testSpecificMock: (server: Mockttp) => { + userStorageMockttpController.setupPath('accounts', server); + + return mockNotificationServices( + server, + userStorageMockttpController, + ); + }, + }, + async ({ driver }) => { + await driver.navigate(); + + // Create a new wallet + await completeCreateNewWalletOnboardingFlow( + driver, + NOTIFICATIONS_TEAM_PASSWORD, + ); + + // Open account menu and validate 1 account is shown + const header = new HeaderNavbar(driver); + await header.check_pageIsLoaded(); + await header.openAccountMenu(); + + const accountListPage = new AccountListPage(driver); + await accountListPage.check_pageIsLoaded(); + await accountListPage.check_numberOfAvailableAccounts(1); + await accountListPage.check_accountDisplayedInAccountList( + 'Account 1', + ); + + // Add a second account + await accountListPage.openAccountOptionsMenu(); + await accountListPage.addNewAccountWithCustomLabel( + 'My Second Account', + ); + + // Set SRP to use for retreival + walletSrp = await getSRP(driver, NOTIFICATIONS_TEAM_PASSWORD); + if (!walletSrp) { + throw new Error('Wallet SRP was not set'); + } + }, + ); + + await withFixtures( + { + fixtures: new FixtureBuilder({ onboarding: true }).build(), + ganacheOptions: defaultGanacheOptions, + title: this.test?.fullTitle(), + testSpecificMock: (server: Mockttp) => { + userStorageMockttpController.setupPath('accounts', server); + return mockNotificationServices( + server, + userStorageMockttpController, + ); + }, + }, + async ({ driver }) => { + await driver.navigate(); + + // Onboard with import flow using SRP from new account created above + await completeImportSRPOnboardingFlow( + driver, + walletSrp, + NOTIFICATIONS_TEAM_PASSWORD, + ); + + // Open account menu and validate the 2 accounts have been retrieved + const header = new HeaderNavbar(driver); + await header.check_pageIsLoaded(); + await header.openAccountMenu(); + + const accountListPage = new AccountListPage(driver); + await accountListPage.check_pageIsLoaded(); + + await accountListPage.check_numberOfAvailableAccounts(2); + + await accountListPage.check_accountDisplayedInAccountList( + 'Account 1', + ); + await accountListPage.check_accountDisplayedInAccountList( + 'My Second Account', + ); + }, + ); + }); + }); +}); diff --git a/test/e2e/tests/notifications/account-syncing/onboarding-with-opt-out.spec.ts b/test/e2e/tests/notifications/account-syncing/onboarding-with-opt-out.spec.ts new file mode 100644 index 000000000000..5cf0bb3c4d19 --- /dev/null +++ b/test/e2e/tests/notifications/account-syncing/onboarding-with-opt-out.spec.ts @@ -0,0 +1,168 @@ +import { Mockttp } from 'mockttp'; +import { + withFixtures, + defaultGanacheOptions, + completeImportSRPOnboardingFlow, + importSRPOnboardingFlow, + onboardingCompleteWalletCreationWithOptOut, + completeCreateNewWalletOnboardingFlowWithOptOut, +} from '../../../helpers'; +import FixtureBuilder from '../../../fixture-builder'; +import { mockNotificationServices } from '../mocks'; +import { + NOTIFICATIONS_TEAM_PASSWORD, + NOTIFICATIONS_TEAM_SEED_PHRASE, +} from '../constants'; +import { UserStorageMockttpController } from '../../../helpers/user-storage/userStorageMockttpController'; +import HeaderNavbar from '../../../page-objects/pages/header-navbar'; +import AccountListPage from '../../../page-objects/pages/account-list-page'; +import { accountsSyncMockResponse } from './mockData'; +import { getSRP, IS_ACCOUNT_SYNCING_ENABLED } from './helpers'; + +describe('Account syncing - Opt-out Profile Sync @no-mmi', function () { + if (!IS_ACCOUNT_SYNCING_ENABLED) { + return; + } + describe('from inside MetaMask', function () { + let walletSrp: string; + it('does not sync when profile sync is turned off - previously synced account', async function () { + const userStorageMockttpController = new UserStorageMockttpController(); + + await withFixtures( + { + fixtures: new FixtureBuilder({ onboarding: true }).build(), + ganacheOptions: defaultGanacheOptions, + title: this.test?.fullTitle(), + testSpecificMock: (server: Mockttp) => { + // Mocks are still set up to ensure that requests are not matched + userStorageMockttpController.setupPath('accounts', server, { + getResponse: accountsSyncMockResponse, + }); + return mockNotificationServices( + server, + userStorageMockttpController, + ); + }, + }, + async ({ driver }) => { + await driver.navigate(); + await importSRPOnboardingFlow( + driver, + NOTIFICATIONS_TEAM_SEED_PHRASE, + NOTIFICATIONS_TEAM_PASSWORD, + ); + + await onboardingCompleteWalletCreationWithOptOut(driver, { + isNewWallet: false, + basicFunctionality: false, + profileSync: true, + assets: false, + }); + + const header = new HeaderNavbar(driver); + await header.check_pageIsLoaded(); + await header.openAccountMenu(); + + const accountListPage = new AccountListPage(driver); + await accountListPage.check_pageIsLoaded(); + await accountListPage.check_numberOfAvailableAccounts(1); + await accountListPage.check_accountIsNotDisplayedInAccountList( + 'My First Synced Account', + ); + await accountListPage.check_accountIsNotDisplayedInAccountList( + 'My Second Synced Account', + ); + await accountListPage.check_accountDisplayedInAccountList( + 'Account 1', + ); + }, + ); + }); + + it('does not sync when profile sync is turned off - new user', async function () { + const userStorageMockttpController = new UserStorageMockttpController(); + + await withFixtures( + { + fixtures: new FixtureBuilder({ onboarding: true }).build(), + ganacheOptions: defaultGanacheOptions, + title: this.test?.fullTitle(), + testSpecificMock: (server: Mockttp) => { + // Mocks are still set up to ensure that requests are not matched + userStorageMockttpController.setupPath('accounts', server); + return mockNotificationServices( + server, + userStorageMockttpController, + ); + }, + }, + async ({ driver }) => { + await driver.navigate(); + await completeCreateNewWalletOnboardingFlowWithOptOut( + driver, + NOTIFICATIONS_TEAM_PASSWORD, + { + isNewWallet: true, + basicFunctionality: false, + profileSync: true, + assets: false, + }, + ); + + const header = new HeaderNavbar(driver); + await header.check_pageIsLoaded(); + await header.openAccountMenu(); + + const accountListPage = new AccountListPage(driver); + await accountListPage.check_pageIsLoaded(); + await accountListPage.check_numberOfAvailableAccounts(1); + await accountListPage.check_accountDisplayedInAccountList( + 'Account 1', + ); + await accountListPage.addNewAccountWithCustomLabel('New Account'); + + // Set SRP to use for retreival + walletSrp = await getSRP(driver, NOTIFICATIONS_TEAM_PASSWORD); + if (!walletSrp) { + throw new Error('Wallet SRP was not set'); + } + }, + ); + + await withFixtures( + { + fixtures: new FixtureBuilder({ onboarding: true }).build(), + ganacheOptions: defaultGanacheOptions, + title: this.test?.fullTitle(), + testSpecificMock: (server: Mockttp) => { + // Mocks are still set up to ensure that requests are not matched + userStorageMockttpController.setupPath('accounts', server); + return mockNotificationServices( + server, + userStorageMockttpController, + ); + }, + }, + async ({ driver }) => { + await driver.navigate(); + await completeImportSRPOnboardingFlow( + driver, + walletSrp, + NOTIFICATIONS_TEAM_PASSWORD, + ); + + const header = new HeaderNavbar(driver); + await header.check_pageIsLoaded(); + await header.openAccountMenu(); + + const accountListPage = new AccountListPage(driver); + await accountListPage.check_pageIsLoaded(); + await accountListPage.check_numberOfAvailableAccounts(1); + await accountListPage.check_accountDisplayedInAccountList( + 'Account 1', + ); + }, + ); + }); + }); +}); diff --git a/test/e2e/tests/notifications/account-syncing/sync-after-adding-account.spec.ts b/test/e2e/tests/notifications/account-syncing/sync-after-adding-account.spec.ts new file mode 100644 index 000000000000..d6c0dc373f69 --- /dev/null +++ b/test/e2e/tests/notifications/account-syncing/sync-after-adding-account.spec.ts @@ -0,0 +1,212 @@ +import { Mockttp } from 'mockttp'; +import { + withFixtures, + defaultGanacheOptions, + completeImportSRPOnboardingFlow, +} from '../../../helpers'; +import FixtureBuilder from '../../../fixture-builder'; +import { mockNotificationServices } from '../mocks'; +import { + NOTIFICATIONS_TEAM_PASSWORD, + NOTIFICATIONS_TEAM_SEED_PHRASE, +} from '../constants'; +import { UserStorageMockttpController } from '../../../helpers/user-storage/userStorageMockttpController'; +import HeaderNavbar from '../../../page-objects/pages/header-navbar'; +import AccountListPage from '../../../page-objects/pages/account-list-page'; +import { accountsSyncMockResponse } from './mockData'; +import { IS_ACCOUNT_SYNCING_ENABLED } from './helpers'; + +describe('Account syncing - Add Account @no-mmi', function () { + if (!IS_ACCOUNT_SYNCING_ENABLED) { + return; + } + describe('from inside MetaMask', function () { + it('syncs newly added accounts - custom name', async function () { + const userStorageMockttpController = new UserStorageMockttpController(); + + await withFixtures( + { + fixtures: new FixtureBuilder({ onboarding: true }).build(), + ganacheOptions: defaultGanacheOptions, + title: this.test?.fullTitle(), + testSpecificMock: (server: Mockttp) => { + userStorageMockttpController.setupPath('accounts', server, { + getResponse: accountsSyncMockResponse, + }); + + return mockNotificationServices( + server, + userStorageMockttpController, + ); + }, + }, + async ({ driver }) => { + await driver.navigate(); + await completeImportSRPOnboardingFlow( + driver, + NOTIFICATIONS_TEAM_SEED_PHRASE, + NOTIFICATIONS_TEAM_PASSWORD, + ); + + const header = new HeaderNavbar(driver); + await header.check_pageIsLoaded(); + await header.openAccountMenu(); + + const accountListPage = new AccountListPage(driver); + await accountListPage.check_pageIsLoaded(); + await accountListPage.check_numberOfAvailableAccounts( + accountsSyncMockResponse.length, + ); + await accountListPage.check_accountDisplayedInAccountList( + 'My First Synced Account', + ); + await accountListPage.check_accountDisplayedInAccountList( + 'My Second Synced Account', + ); + await accountListPage.addNewAccountWithCustomLabel( + 'My third account', + ); + }, + ); + + await withFixtures( + { + fixtures: new FixtureBuilder({ onboarding: true }).build(), + ganacheOptions: defaultGanacheOptions, + title: this.test?.fullTitle(), + testSpecificMock: (server: Mockttp) => { + userStorageMockttpController.setupPath('accounts', server); + return mockNotificationServices( + server, + userStorageMockttpController, + ); + }, + }, + async ({ driver }) => { + await driver.navigate(); + await completeImportSRPOnboardingFlow( + driver, + NOTIFICATIONS_TEAM_SEED_PHRASE, + NOTIFICATIONS_TEAM_PASSWORD, + ); + + const header = new HeaderNavbar(driver); + await header.check_pageIsLoaded(); + await header.openAccountMenu(); + + const accountListPage = new AccountListPage(driver); + await accountListPage.check_pageIsLoaded(); + + const accountSyncResponse = + userStorageMockttpController.paths.get('accounts')?.response; + + await accountListPage.check_numberOfAvailableAccounts( + accountSyncResponse?.length as number, + ); + await accountListPage.check_accountDisplayedInAccountList( + 'My First Synced Account', + ); + await accountListPage.check_accountDisplayedInAccountList( + 'My Second Synced Account', + ); + await accountListPage.check_accountDisplayedInAccountList( + 'My third account', + ); + }, + ); + }); + + it('syncs newly added accounts - default name', async function () { + const userStorageMockttpController = new UserStorageMockttpController(); + + await withFixtures( + { + fixtures: new FixtureBuilder({ onboarding: true }).build(), + ganacheOptions: defaultGanacheOptions, + title: this.test?.fullTitle(), + testSpecificMock: (server: Mockttp) => { + userStorageMockttpController.setupPath('accounts', server, { + getResponse: accountsSyncMockResponse, + }); + + return mockNotificationServices( + server, + userStorageMockttpController, + ); + }, + }, + async ({ driver }) => { + await driver.navigate(); + await completeImportSRPOnboardingFlow( + driver, + NOTIFICATIONS_TEAM_SEED_PHRASE, + NOTIFICATIONS_TEAM_PASSWORD, + ); + + const header = new HeaderNavbar(driver); + await header.check_pageIsLoaded(); + await header.openAccountMenu(); + + const accountListPage = new AccountListPage(driver); + await accountListPage.check_pageIsLoaded(); + await accountListPage.check_numberOfAvailableAccounts( + accountsSyncMockResponse.length, + ); + await accountListPage.check_accountDisplayedInAccountList( + 'My First Synced Account', + ); + await accountListPage.check_accountDisplayedInAccountList( + 'My Second Synced Account', + ); + await accountListPage.addNewAccountWithDefaultName(); + }, + ); + + await withFixtures( + { + fixtures: new FixtureBuilder({ onboarding: true }).build(), + ganacheOptions: defaultGanacheOptions, + title: this.test?.fullTitle(), + testSpecificMock: (server: Mockttp) => { + userStorageMockttpController.setupPath('accounts', server); + return mockNotificationServices( + server, + userStorageMockttpController, + ); + }, + }, + async ({ driver }) => { + await driver.navigate(); + await completeImportSRPOnboardingFlow( + driver, + NOTIFICATIONS_TEAM_SEED_PHRASE, + NOTIFICATIONS_TEAM_PASSWORD, + ); + + const header = new HeaderNavbar(driver); + await header.check_pageIsLoaded(); + await header.openAccountMenu(); + + const accountListPage = new AccountListPage(driver); + await accountListPage.check_pageIsLoaded(); + + const accountSyncResponse = + userStorageMockttpController.paths.get('accounts')?.response; + + await accountListPage.check_numberOfAvailableAccounts( + accountSyncResponse?.length as number, + ); + await accountListPage.check_accountDisplayedInAccountList( + 'My First Synced Account', + ); + await accountListPage.check_accountDisplayedInAccountList( + 'My Second Synced Account', + ); + await accountListPage.check_accountDisplayedInAccountList( + 'Account 3', + ); + }, + ); + }); + }); +}); diff --git a/test/e2e/tests/notifications/account-syncing/sync-after-modifying-account-name.spec.ts b/test/e2e/tests/notifications/account-syncing/sync-after-modifying-account-name.spec.ts new file mode 100644 index 000000000000..418962b370de --- /dev/null +++ b/test/e2e/tests/notifications/account-syncing/sync-after-modifying-account-name.spec.ts @@ -0,0 +1,114 @@ +import { Mockttp } from 'mockttp'; +import { + withFixtures, + defaultGanacheOptions, + completeImportSRPOnboardingFlow, +} from '../../../helpers'; +import FixtureBuilder from '../../../fixture-builder'; +import { mockNotificationServices } from '../mocks'; +import { + NOTIFICATIONS_TEAM_PASSWORD, + NOTIFICATIONS_TEAM_SEED_PHRASE, +} from '../constants'; +import { UserStorageMockttpController } from '../../../helpers/user-storage/userStorageMockttpController'; +import HeaderNavbar from '../../../page-objects/pages/header-navbar'; +import AccountListPage from '../../../page-objects/pages/account-list-page'; +import { accountsSyncMockResponse } from './mockData'; +import { IS_ACCOUNT_SYNCING_ENABLED } from './helpers'; + +describe('Account syncing - Rename Accounts @no-mmi', function () { + if (!IS_ACCOUNT_SYNCING_ENABLED) { + return; + } + describe('from inside MetaMask', function () { + it('syncs renamed account names', async function () { + const userStorageMockttpController = new UserStorageMockttpController(); + + await withFixtures( + { + fixtures: new FixtureBuilder({ onboarding: true }).build(), + ganacheOptions: defaultGanacheOptions, + title: this.test?.fullTitle(), + testSpecificMock: (server: Mockttp) => { + userStorageMockttpController.setupPath('accounts', server, { + getResponse: accountsSyncMockResponse, + }); + + return mockNotificationServices( + server, + userStorageMockttpController, + ); + }, + }, + async ({ driver }) => { + await driver.navigate(); + await completeImportSRPOnboardingFlow( + driver, + NOTIFICATIONS_TEAM_SEED_PHRASE, + NOTIFICATIONS_TEAM_PASSWORD, + ); + + const header = new HeaderNavbar(driver); + await header.check_pageIsLoaded(); + await header.openAccountMenu(); + + const accountListPage = new AccountListPage(driver); + await accountListPage.check_pageIsLoaded(); + await accountListPage.check_numberOfAvailableAccounts( + accountsSyncMockResponse.length, + ); + await accountListPage.check_accountDisplayedInAccountList( + 'My First Synced Account', + ); + await accountListPage.check_accountDisplayedInAccountList( + 'My Second Synced Account', + ); + await accountListPage.openAccountOptionsMenu(); + await accountListPage.changeAccountLabel('My Renamed First Account'); + }, + ); + + await withFixtures( + { + fixtures: new FixtureBuilder({ onboarding: true }).build(), + ganacheOptions: defaultGanacheOptions, + title: this.test?.fullTitle(), + testSpecificMock: (server: Mockttp) => { + userStorageMockttpController.setupPath('accounts', server); + return mockNotificationServices( + server, + userStorageMockttpController, + ); + }, + }, + async ({ driver }) => { + await driver.navigate(); + await completeImportSRPOnboardingFlow( + driver, + NOTIFICATIONS_TEAM_SEED_PHRASE, + NOTIFICATIONS_TEAM_PASSWORD, + ); + + const header = new HeaderNavbar(driver); + await header.check_pageIsLoaded(); + await header.openAccountMenu(); + + const accountListPage = new AccountListPage(driver); + await accountListPage.check_pageIsLoaded(); + await accountListPage.check_numberOfAvailableAccounts( + accountsSyncMockResponse.length, + ); + await accountListPage.check_accountIsNotDisplayedInAccountList( + 'My First Synced Account', + ); + await accountListPage.check_accountDisplayedInAccountList( + 'My Renamed First Account', + ); + await accountListPage.check_accountDisplayedInAccountList( + 'My Second Synced Account', + ); + }, + ); + }); + }); +}); diff --git a/test/e2e/tests/notifications/account-syncing/sync-after-onboarding.spec.ts b/test/e2e/tests/notifications/account-syncing/sync-after-onboarding.spec.ts index 1a55e38c713d..4ec904256525 100644 --- a/test/e2e/tests/notifications/account-syncing/sync-after-onboarding.spec.ts +++ b/test/e2e/tests/notifications/account-syncing/sync-after-onboarding.spec.ts @@ -11,10 +11,12 @@ import { NOTIFICATIONS_TEAM_SEED_PHRASE, } from '../constants'; import { UserStorageMockttpController } from '../../../helpers/user-storage/userStorageMockttpController'; +import HeaderNavbar from '../../../page-objects/pages/header-navbar'; +import AccountListPage from '../../../page-objects/pages/account-list-page'; import { accountsSyncMockResponse } from './mockData'; import { IS_ACCOUNT_SYNCING_ENABLED } from './helpers'; -describe('Account syncing @no-mmi', function () { +describe('Account syncing - Onboarding @no-mmi', function () { if (!IS_ACCOUNT_SYNCING_ENABLED) { return; } @@ -45,14 +47,21 @@ describe('Account syncing @no-mmi', function () { NOTIFICATIONS_TEAM_PASSWORD, ); - await driver.clickElement('[data-testid="account-menu-icon"]'); + const header = new HeaderNavbar(driver); + await header.check_pageIsLoaded(); + await header.openAccountMenu(); - await driver.wait(async () => { - const internalAccounts = await driver.findElements( - '.multichain-account-list-item', - ); - return internalAccounts.length === accountsSyncMockResponse.length; - }, 20000); + const accountListPage = new AccountListPage(driver); + await accountListPage.check_pageIsLoaded(); + await accountListPage.check_numberOfAvailableAccounts( + accountsSyncMockResponse.length, + ); + await accountListPage.check_accountDisplayedInAccountList( + 'My First Synced Account', + ); + await accountListPage.check_accountDisplayedInAccountList( + 'My Second Synced Account', + ); }, ); }); diff --git a/test/e2e/tests/notifications/constants.ts b/test/e2e/tests/notifications/constants.ts index 8c611dcd4f44..557483174b08 100644 --- a/test/e2e/tests/notifications/constants.ts +++ b/test/e2e/tests/notifications/constants.ts @@ -5,3 +5,6 @@ export const NOTIFICATIONS_TEAM_PASSWORD = 'notify_password'; // You can use the storage key below to generate mock data export const NOTIFICATIONS_TEAM_STORAGE_KEY = '0d55d30da233959674d14076737198c05ae3fb8631a17e20d3c28c60dddd82f7'; + +export const NOTIFICATIONS_TEAM_IMPORTED_PRIVATE_KEY = + '0179f7453ff337aba89d04b00085764092cf8c0cfe91d5614c39c2be902ad582'; diff --git a/ui/components/multichain/account-list-menu/account-list-menu.tsx b/ui/components/multichain/account-list-menu/account-list-menu.tsx index 19d313aedf54..eff0d3cb8868 100644 --- a/ui/components/multichain/account-list-menu/account-list-menu.tsx +++ b/ui/components/multichain/account-list-menu/account-list-menu.tsx @@ -455,6 +455,7 @@ export const AccountListMenu = ({ { trackEvent({ category: MetaMetricsEventCategory.Navigation,