From 95d9101ec5f000c321643f6ed3ec7c5ea8b0f9f1 Mon Sep 17 00:00:00 2001 From: "devin-ai-integration[bot]" <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Thu, 24 Oct 2024 14:46:37 +0200 Subject: [PATCH] test: [POM] Create onboarding related page object modal base pages and migrate e2e tests (#28036) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR migrates onboarding e2e tests to Page Object Model (POM) pattern, improving test stability and maintainability. Changes include: - Migrate test `test/e2e/tests/onboarding/onboarding.spec.js` to POM - Migrate test `test/e2e/tests/onboarding/onboarding.spec.js` to TypeScript - Created all onboarding-related pages and functions - Avoided unnecessary delays - Reduced flakiness - I will create follow-up PRs after this one is merged to avoid having a very big PR. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/27155?quickstart=1) ## **Related issues** Fixes: #https://github.com/MetaMask/metamask-extension/issues/27989 ## **Manual testing steps** Check code readability, make sure tests pass. ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --------- Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Chloe Gao Co-authored-by: chloeYue <105063779+chloeYue@users.noreply.github.com> Co-authored-by: seaona <54408225+seaona@users.noreply.github.com> --- test/e2e/page-objects/flows/login.flow.ts | 12 +- .../e2e/page-objects/flows/onboarding.flow.ts | 64 ++ test/e2e/page-objects/pages/header-navbar.ts | 30 + test/e2e/page-objects/pages/homepage.ts | 12 + .../onboarding/onboarding-complete-page.ts | 95 +++ .../onboarding/onboarding-metrics-page.ts | 38 + .../onboarding/onboarding-password-page.ts | 112 +++ .../onboarding-privacy-settings-page.ts | 194 +++++ .../pages/onboarding/onboarding-srp-page.ts | 105 +++ .../pages/onboarding/secure-wallet-page.ts | 107 +++ .../pages/onboarding/start-onboarding-page.ts | 52 ++ .../account/snap-account-signatures.spec.ts | 2 +- test/e2e/tests/onboarding/onboarding.spec.js | 748 ------------------ test/e2e/tests/onboarding/onboarding.spec.ts | 269 +++++++ .../account-tracker-api-usage.spec.ts | 0 .../tests/privacy/onboarding-privacy.spec.js | 283 +++++++ test/e2e/tests/transaction/ens.spec.ts | 1 + 17 files changed, 1369 insertions(+), 755 deletions(-) create mode 100644 test/e2e/page-objects/flows/onboarding.flow.ts create mode 100644 test/e2e/page-objects/pages/onboarding/onboarding-complete-page.ts create mode 100644 test/e2e/page-objects/pages/onboarding/onboarding-metrics-page.ts create mode 100644 test/e2e/page-objects/pages/onboarding/onboarding-password-page.ts create mode 100644 test/e2e/page-objects/pages/onboarding/onboarding-privacy-settings-page.ts create mode 100644 test/e2e/page-objects/pages/onboarding/onboarding-srp-page.ts create mode 100644 test/e2e/page-objects/pages/onboarding/secure-wallet-page.ts create mode 100644 test/e2e/page-objects/pages/onboarding/start-onboarding-page.ts delete mode 100644 test/e2e/tests/onboarding/onboarding.spec.js create mode 100644 test/e2e/tests/onboarding/onboarding.spec.ts rename test/e2e/tests/{api-usage => privacy}/account-tracker-api-usage.spec.ts (100%) create mode 100644 test/e2e/tests/privacy/onboarding-privacy.spec.js diff --git a/test/e2e/page-objects/flows/login.flow.ts b/test/e2e/page-objects/flows/login.flow.ts index 87239e3f19f1..fcd0bcb22d8a 100644 --- a/test/e2e/page-objects/flows/login.flow.ts +++ b/test/e2e/page-objects/flows/login.flow.ts @@ -18,10 +18,6 @@ export const loginWithoutBalanceValidation = async ( const loginPage = new LoginPage(driver); await loginPage.check_pageIsLoaded(); await loginPage.loginToHomepage(password); - - // user should land on homepage after successfully logging in with password - const homePage = new HomePage(driver); - await homePage.check_pageIsLoaded(); }; /** @@ -37,10 +33,14 @@ export const loginWithBalanceValidation = async ( password?: string, ) => { await loginWithoutBalanceValidation(driver, password); + // user should land on homepage after successfully logging in with password + const homePage = new HomePage(driver); + await homePage.check_pageIsLoaded(); + // Verify the expected balance on the homepage if (ganacheServer) { - await new HomePage(driver).check_ganacheBalanceIsDisplayed(ganacheServer); + await homePage.check_ganacheBalanceIsDisplayed(ganacheServer); } else { - await new HomePage(driver).check_expectedBalanceIsDisplayed(); + await homePage.check_expectedBalanceIsDisplayed(); } }; diff --git a/test/e2e/page-objects/flows/onboarding.flow.ts b/test/e2e/page-objects/flows/onboarding.flow.ts new file mode 100644 index 000000000000..70a4f7df82f2 --- /dev/null +++ b/test/e2e/page-objects/flows/onboarding.flow.ts @@ -0,0 +1,64 @@ +import { Driver } from '../../webdriver/driver'; +import OnboardingMetricsPage from '../pages/onboarding/onboarding-metrics-page'; +import OnboardingPasswordPage from '../pages/onboarding/onboarding-password-page'; +import OnboardingSrpPage from '../pages/onboarding/onboarding-srp-page'; +import StartOnboardingPage from '../pages/onboarding/start-onboarding-page'; +import SecureWalletPage from '../pages/onboarding/secure-wallet-page'; +import OnboardingCompletePage from '../pages/onboarding/onboarding-complete-page'; + +export const importSRPOnboardingFlow = async (driver: Driver) => { + console.log('start import srp onboarding flow '); + await driver.navigate(); + const startOnboardingPage = new StartOnboardingPage(driver); + await startOnboardingPage.check_pageIsLoaded(); + await startOnboardingPage.checkTermsCheckbox(); + await startOnboardingPage.clickImportWalletButton(); + + const onboardingMetricsPage = new OnboardingMetricsPage(driver); + await onboardingMetricsPage.check_pageIsLoaded(); + await onboardingMetricsPage.clickNoThanksButton(); + + const onboardingSrpPage = new OnboardingSrpPage(driver); + await onboardingSrpPage.check_pageIsLoaded(); + await onboardingSrpPage.fillSrp(); + await onboardingSrpPage.clickConfirmButton(); + + const onboardingPasswordPage = new OnboardingPasswordPage(driver); + await onboardingPasswordPage.check_pageIsLoaded(); + await onboardingPasswordPage.createImportedWalletPassword(); +}; + +export const completeCreateNewWalletOnboardingFlow = async (driver: Driver) => { + console.log('start to complete create new wallet onboarding flow '); + await driver.navigate(); + const startOnboardingPage = new StartOnboardingPage(driver); + await startOnboardingPage.check_pageIsLoaded(); + await startOnboardingPage.checkTermsCheckbox(); + await startOnboardingPage.clickCreateWalletButton(); + + const onboardingMetricsPage = new OnboardingMetricsPage(driver); + await onboardingMetricsPage.check_pageIsLoaded(); + await onboardingMetricsPage.clickNoThanksButton(); + + const onboardingPasswordPage = new OnboardingPasswordPage(driver); + await onboardingPasswordPage.check_pageIsLoaded(); + await onboardingPasswordPage.createWalletPassword(); + + const secureWalletPage = new SecureWalletPage(driver); + await secureWalletPage.check_pageIsLoaded(); + await secureWalletPage.revealAndConfirmSRP(); + + const onboardingCompletePage = new OnboardingCompletePage(driver); + await onboardingCompletePage.check_pageIsLoaded(); + await onboardingCompletePage.check_congratulationsMessageIsDisplayed(); + await onboardingCompletePage.completeOnboarding(); +}; + +export const completeImportSRPOnboardingFlow = async (driver: Driver) => { + console.log('start to complete import srp onboarding flow '); + await importSRPOnboardingFlow(driver); + const onboardingCompletePage = new OnboardingCompletePage(driver); + await onboardingCompletePage.check_pageIsLoaded(); + await onboardingCompletePage.check_walletReadyMessageIsDisplayed(); + await onboardingCompletePage.completeOnboarding(); +}; diff --git a/test/e2e/page-objects/pages/header-navbar.ts b/test/e2e/page-objects/pages/header-navbar.ts index 8bd29ea8c602..360b7a2a5d72 100644 --- a/test/e2e/page-objects/pages/header-navbar.ts +++ b/test/e2e/page-objects/pages/header-navbar.ts @@ -15,8 +15,16 @@ class HeaderNavbar { private readonly mmiPortfolioButton = '[data-testid="global-menu-mmi-portfolio"]'; + private readonly selectNetworkMessage = { + text: 'Select a network', + tag: 'h4', + }; + private readonly settingsButton = '[data-testid="global-menu-settings"]'; + private readonly switchNetworkDropDownButton = + '[data-testid="network-display"]'; + constructor(driver: Driver) { this.driver = driver; } @@ -63,6 +71,28 @@ class HeaderNavbar { await this.driver.clickElement(this.settingsButton); } + /** + * Switches to the specified network. + * + * @param networkName - The name of the network to switch to. + */ + async switchToNetwork(networkName: string): Promise { + console.log(`Switch to network ${networkName} in header bar`); + await this.driver.clickElement(this.switchNetworkDropDownButton); + await this.driver.waitForSelector(this.selectNetworkMessage); + await this.driver.clickElementAndWaitToDisappear( + `[data-testid="${networkName}"]`, + ); + // check the toaster message is displayed and the network is correctly selected + await this.driver.waitForSelector({ + tag: 'h6', + text: `“${networkName}” was successfully added!`, + }); + await this.driver.waitForSelector( + `${this.switchNetworkDropDownButton}[aria-label="Network Menu ${networkName}"]`, + ); + } + /** * Verifies that the displayed account label in header matches the expected label. * diff --git a/test/e2e/page-objects/pages/homepage.ts b/test/e2e/page-objects/pages/homepage.ts index 326ecc3188b7..432106c5c520 100644 --- a/test/e2e/page-objects/pages/homepage.ts +++ b/test/e2e/page-objects/pages/homepage.ts @@ -13,6 +13,11 @@ class HomePage { private readonly balance = '[data-testid="eth-overview__primary-currency"]'; + private readonly basicFunctionalityOffWarningMessage = { + text: 'Basic functionality is off', + css: '.mm-banner-alert', + }; + private readonly completedTransactions = '[data-testid="activity-list-item"]'; private readonly confirmedTransactions = { @@ -60,6 +65,13 @@ class HomePage { await this.driver.clickElement(this.activityTab); } + async check_basicFunctionalityOffWarnigMessageIsDisplayed(): Promise { + console.log( + 'Check if basic functionality off warning message is displayed on homepage', + ); + await this.driver.waitForSelector(this.basicFunctionalityOffWarningMessage); + } + /** * This function checks if the specified number of confirmed transactions are displayed in the activity list on homepage. * It waits up to 10 seconds for the expected number of confirmed transactions to be visible. diff --git a/test/e2e/page-objects/pages/onboarding/onboarding-complete-page.ts b/test/e2e/page-objects/pages/onboarding/onboarding-complete-page.ts new file mode 100644 index 000000000000..827f89899bad --- /dev/null +++ b/test/e2e/page-objects/pages/onboarding/onboarding-complete-page.ts @@ -0,0 +1,95 @@ +import { Driver } from '../../../webdriver/driver'; + +class OnboardingCompletePage { + private driver: Driver; + + private readonly congratulationsMessage = { + text: 'Congratulations!', + tag: 'h2', + }; + + private readonly defaultPrivacySettingsButton = { + text: 'Manage default privacy settings', + tag: 'button', + }; + + private readonly installCompleteMessage = { + text: 'Your MetaMask install is complete!', + tag: 'h2', + }; + + private readonly onboardingCompleteDoneButton = + '[data-testid="onboarding-complete-done"]'; + + private readonly pinExtensionDoneButton = + '[data-testid="pin-extension-done"]'; + + private readonly pinExtensionMessage = { + text: 'Click browser extension icon to access it instantly', + tag: 'p', + }; + + private readonly pinExtensionNextButton = + '[data-testid="pin-extension-next"]'; + + private readonly walletReadyMessage = { + text: 'Your wallet is ready', + tag: 'h2', + }; + + constructor(driver: Driver) { + this.driver = driver; + } + + async check_pageIsLoaded(): Promise { + try { + await this.driver.waitForMultipleSelectors([ + this.defaultPrivacySettingsButton, + this.onboardingCompleteDoneButton, + ]); + } catch (e) { + console.log( + 'Timeout while waiting for onboarding wallet creation complete page to be loaded', + e, + ); + throw e; + } + console.log('Onboarding wallet creation complete page is loaded'); + } + + async clickCreateWalletDoneButton(): Promise { + await this.driver.clickElementAndWaitToDisappear( + this.onboardingCompleteDoneButton, + ); + } + + async completeOnboarding(): Promise { + console.log('Complete onboarding'); + await this.clickCreateWalletDoneButton(); + await this.driver.waitForSelector(this.installCompleteMessage); + await this.driver.clickElement(this.pinExtensionNextButton); + + // Wait until the onboarding carousel has stopped moving otherwise the click has no effect. + await this.driver.waitForSelector(this.pinExtensionMessage); + await this.driver.waitForElementToStopMoving(this.pinExtensionDoneButton); + await this.driver.clickElementAndWaitToDisappear( + this.pinExtensionDoneButton, + ); + } + + async navigateToDefaultPrivacySettings(): Promise { + await this.driver.clickElementAndWaitToDisappear( + this.defaultPrivacySettingsButton, + ); + } + + async check_congratulationsMessageIsDisplayed(): Promise { + await this.driver.waitForSelector(this.congratulationsMessage); + } + + async check_walletReadyMessageIsDisplayed(): Promise { + await this.driver.waitForSelector(this.walletReadyMessage); + } +} + +export default OnboardingCompletePage; diff --git a/test/e2e/page-objects/pages/onboarding/onboarding-metrics-page.ts b/test/e2e/page-objects/pages/onboarding/onboarding-metrics-page.ts new file mode 100644 index 000000000000..2982acaa40c0 --- /dev/null +++ b/test/e2e/page-objects/pages/onboarding/onboarding-metrics-page.ts @@ -0,0 +1,38 @@ +import { Driver } from '../../../webdriver/driver'; + +class OnboardingMetricsPage { + private driver: Driver; + + private readonly metametricsMessage = { + text: 'Help us improve MetaMask', + tag: 'h2', + }; + + private readonly noThanksButton = '[data-testid="metametrics-no-thanks"]'; + + constructor(driver: Driver) { + this.driver = driver; + } + + async check_pageIsLoaded(): Promise { + try { + await this.driver.waitForMultipleSelectors([ + this.metametricsMessage, + this.noThanksButton, + ]); + } catch (e) { + console.log( + 'Timeout while waiting for onboarding metametrics page to be loaded', + e, + ); + throw e; + } + console.log('Onboarding metametrics page is loaded'); + } + + async clickNoThanksButton(): Promise { + await this.driver.clickElementAndWaitToDisappear(this.noThanksButton); + } +} + +export default OnboardingMetricsPage; diff --git a/test/e2e/page-objects/pages/onboarding/onboarding-password-page.ts b/test/e2e/page-objects/pages/onboarding/onboarding-password-page.ts new file mode 100644 index 000000000000..81c2d21aceb6 --- /dev/null +++ b/test/e2e/page-objects/pages/onboarding/onboarding-password-page.ts @@ -0,0 +1,112 @@ +import { strict as assert } from 'assert'; +import { Driver } from '../../../webdriver/driver'; +import { WALLET_PASSWORD } from '../../../helpers'; + +class OnboardingPasswordPage { + private driver: Driver; + + private readonly confirmPasswordInput = + '[data-testid="create-password-confirm"]'; + + private readonly createPasswordMessage = { + text: 'Create password', + tag: 'h2', + }; + + private readonly createWalletButton = + '[data-testid="create-password-wallet"]'; + + private readonly importWalletButton = + '[data-testid="create-password-import"]'; + + private readonly incorrectPasswordWarningMessage = { + text: "Passwords don't match", + tag: 'h6', + }; + + private readonly newPasswordInput = '[data-testid="create-password-new"]'; + + private readonly passwordTerms = '[data-testid="create-password-terms"]'; + + constructor(driver: Driver) { + this.driver = driver; + } + + async check_pageIsLoaded(): Promise { + try { + await this.driver.waitForMultipleSelectors([ + this.createPasswordMessage, + this.newPasswordInput, + this.confirmPasswordInput, + ]); + } catch (e) { + console.log( + 'Timeout while waiting for create password page to be loaded', + e, + ); + throw e; + } + console.log('Onboarding password page is loaded'); + } + + /** + * Create a password for new imported wallet + * + * @param newPassword - The new password to create. Defaults to WALLET_PASSWORD. + * @param confirmPassword - The confirm password to create. Defaults to WALLET_PASSWORD. + */ + async createImportedWalletPassword( + newPassword: string = WALLET_PASSWORD, + confirmPassword: string = WALLET_PASSWORD, + ): Promise { + console.log('Create password for new imported wallet'); + await this.fillWalletPassword(newPassword, confirmPassword); + await this.driver.clickElementAndWaitToDisappear(this.importWalletButton); + } + + /** + * Create a password for new created wallet + * + * @param newPassword - The new password to create. Defaults to WALLET_PASSWORD. + * @param confirmPassword - The confirm password to create. Defaults to WALLET_PASSWORD. + */ + async createWalletPassword( + newPassword: string = WALLET_PASSWORD, + confirmPassword: string = WALLET_PASSWORD, + ): Promise { + console.log('Create password for new created wallet'); + await this.fillWalletPassword(newPassword, confirmPassword); + await this.driver.clickElementAndWaitToDisappear(this.createWalletButton); + } + + /** + * Fill the wallet password fields + * + * @param newPassword - The new password to fill. + * @param confirmPassword - The confirm password to fill. + */ + async fillWalletPassword( + newPassword: string, + confirmPassword: string, + ): Promise { + console.log('Fill the wallet password fields'); + await this.driver.fill(this.newPasswordInput, newPassword); + await this.driver.fill(this.confirmPasswordInput, confirmPassword); + await this.driver.clickElement(this.passwordTerms); + } + + async check_confirmPasswordButtonIsDisabled(): Promise { + console.log('Check the confirm password button is disabled'); + const confirmPasswordButton = await this.driver.findElement( + this.createWalletButton, + ); + assert.equal(await confirmPasswordButton.isEnabled(), false); + } + + async check_incorrectPasswordWarningMessageIsDisplayed(): Promise { + console.log('Check the incorrect password warning message is displayed'); + await this.driver.waitForSelector(this.incorrectPasswordWarningMessage); + } +} + +export default OnboardingPasswordPage; diff --git a/test/e2e/page-objects/pages/onboarding/onboarding-privacy-settings-page.ts b/test/e2e/page-objects/pages/onboarding/onboarding-privacy-settings-page.ts new file mode 100644 index 000000000000..dac2ab447710 --- /dev/null +++ b/test/e2e/page-objects/pages/onboarding/onboarding-privacy-settings-page.ts @@ -0,0 +1,194 @@ +import { Driver } from '../../../webdriver/driver'; + +class OnboardingPrivacySettingsPage { + private driver: Driver; + + private readonly assetsSettings = '[data-testid="category-item-Assets"]'; + + private readonly categoryBackButton = '[data-testid="category-back-button"]'; + + private readonly generalSettings = '[data-testid="category-item-General"]'; + + private readonly privacySettingsBackButton = + '[data-testid="privacy-settings-back-button"]'; + + private readonly securitySettings = '[data-testid="category-item-Security"]'; + + // General settings + private readonly basicFunctionalityCheckbox = + '[id="basic-configuration-checkbox"]'; + + private readonly basicFunctionalityToggle = + '[data-testid="basic-functionality-toggle"] .toggle-button'; + + private readonly basicFunctionalityTurnOffButton = { + text: 'Turn off', + tag: 'button', + }; + + private readonly basicFunctionalityTurnOffMessage = { + text: 'Turn off basic functionality', + tag: 'h4', + }; + + private readonly generalSettingsMessage = { text: 'General', tag: 'h2' }; + + // General settings - add custom network section + private readonly addCustomNetworkButton = { + text: 'Add a network', + tag: 'p', + }; + + private readonly addCustomNetworkFormMessage = { + text: 'Add a custom network', + tag: 'h4', + }; + + private readonly addRpcUrlButton = { + text: 'Add RPC URL', + tag: 'button', + }; + + private readonly addRpcUrlDialogMessage = { + text: 'Add RPC URL', + tag: 'h4', + }; + + private readonly addRpcUrlDropDown = '[data-testid="test-add-rpc-drop-down"]'; + + private readonly chainIdInput = '[data-testid="network-form-chain-id"]'; + + private readonly confirmAddCustomNetworkButton = { + text: 'Save', + tag: 'button', + }; + + private readonly confirmAddRpcUrlButton = { + text: 'Add URL', + tag: 'button', + }; + + private readonly currencySymbolInput = + '[data-testid="network-form-ticker-input"]'; + + private readonly networkNameInput = + '[data-testid="network-form-network-name"]'; + + private readonly rpcUrlInput = '[data-testid="rpc-url-input-test"]'; + + // Assets settings + private readonly assetsPrivacyToggle = '.toggle-button.toggle-button--on'; + + private readonly assetsSettingsMessage = { text: 'Assets', tag: 'h2' }; + + constructor(driver: Driver) { + this.driver = driver; + } + + async check_pageIsLoaded(): Promise { + try { + await this.driver.waitForMultipleSelectors([ + this.generalSettings, + this.assetsSettings, + this.securitySettings, + ]); + } catch (e) { + console.log( + 'Timeout while waiting for onboarding privacy settings page to be loaded', + e, + ); + throw e; + } + console.log('Onboarding privacy settings page is loaded'); + } + + /** + * Adds a custom network to MetaMask during the onboarding process. + * + * @param networkName - The name of the custom network. + * @param chainId - The chain ID of the custom network. + * @param currencySymbol - The currency symbol for the custom network. + * @param networkUrl - The RPC URL for the custom network. + * @returns A promise that resolves when the custom network has been added. + */ + async addCustomNetwork( + networkName: string, + chainId: number, + currencySymbol: string, + networkUrl: string, + ): Promise { + await this.navigateToGeneralSettings(); + console.log('Adding custom network'); + await this.driver.clickElement(this.addCustomNetworkButton); + await this.driver.waitForSelector(this.addCustomNetworkFormMessage); + await this.driver.fill(this.networkNameInput, networkName); + await this.driver.fill(this.chainIdInput, chainId.toString()); + await this.driver.fill(this.currencySymbolInput, currencySymbol); + // Add rpc url + await this.driver.clickElement(this.addRpcUrlDropDown); + await this.driver.clickElement(this.addRpcUrlButton); + await this.driver.waitForSelector(this.addRpcUrlDialogMessage); + await this.driver.fill(this.rpcUrlInput, networkUrl); + await this.driver.clickElement(this.confirmAddRpcUrlButton); + await this.driver.clickElementAndWaitToDisappear( + this.confirmAddCustomNetworkButton, + ); + // Navigate back to default privacy settings + await this.driver.clickElement(this.categoryBackButton); + await this.driver.waitForElementToStopMoving(this.categoryBackButton); + } + + /** + * Navigate back to the onboarding complete page. + */ + async navigateBackToOnboardingCompletePage(): Promise { + console.log('Navigate back to onboarding complete page'); + // Wait until the onboarding carousel has stopped moving otherwise the click has no effect. + await this.driver.waitForElementToStopMoving( + this.privacySettingsBackButton, + ); + await this.driver.clickElementAndWaitToDisappear( + this.privacySettingsBackButton, + ); + } + + async navigateToGeneralSettings(): Promise { + console.log('Navigate to general settings'); + await this.check_pageIsLoaded(); + await this.driver.clickElement(this.generalSettings); + await this.driver.waitForSelector(this.generalSettingsMessage); + } + + /** + * Go to assets settings and toggle options, then navigate back. + */ + async toggleAssetsSettings(): Promise { + console.log('Toggle advanced assets settings in privacy settings'); + await this.check_pageIsLoaded(); + await this.driver.clickElement(this.assetsSettings); + await this.driver.waitForSelector(this.assetsSettingsMessage); + await Promise.all( + ( + await this.driver.findClickableElements(this.assetsPrivacyToggle) + ).map((toggle) => toggle.click()), + ); + await this.driver.clickElement(this.categoryBackButton); + await this.driver.waitForElementToStopMoving(this.categoryBackButton); + } + + /** + * Go to general settings and toggle options, then navigate back. + */ + async toggleBasicFunctionalitySettings(): Promise { + console.log('Toggle basic functionality settings in privacy settings'); + await this.navigateToGeneralSettings(); + await this.driver.clickElement(this.basicFunctionalityToggle); + await this.driver.waitForSelector(this.basicFunctionalityTurnOffMessage); + await this.driver.clickElement(this.basicFunctionalityCheckbox); + await this.driver.clickElement(this.basicFunctionalityTurnOffButton); + await this.driver.clickElement(this.categoryBackButton); + await this.driver.waitForElementToStopMoving(this.categoryBackButton); + } +} + +export default OnboardingPrivacySettingsPage; diff --git a/test/e2e/page-objects/pages/onboarding/onboarding-srp-page.ts b/test/e2e/page-objects/pages/onboarding/onboarding-srp-page.ts new file mode 100644 index 000000000000..da3e74153c67 --- /dev/null +++ b/test/e2e/page-objects/pages/onboarding/onboarding-srp-page.ts @@ -0,0 +1,105 @@ +import { strict as assert } from 'assert'; +import { Driver } from '../../../webdriver/driver'; +import { TEST_SEED_PHRASE } from '../../../helpers'; + +class OnboardingSrpPage { + private driver: Driver; + + private readonly srpConfirmButton = '[data-testid="import-srp-confirm"]'; + + private readonly srpDropdown = '.import-srp__number-of-words-dropdown'; + + private readonly srpDropdownOptions = + '.import-srp__number-of-words-dropdown option'; + + private readonly srpMessage = { + text: 'Access your wallet with your Secret Recovery Phrase', + tag: 'h2', + }; + + private readonly srpWord0 = '[data-testid="import-srp__srp-word-0"]'; + + private readonly srpWords = '.import-srp__srp-word'; + + private readonly wrongSrpWarningMessage = { + text: 'Invalid Secret Recovery Phrase', + css: '.import-srp__banner-alert-text', + }; + + constructor(driver: Driver) { + this.driver = driver; + } + + async check_pageIsLoaded(): Promise { + try { + await this.driver.waitForMultipleSelectors([ + this.srpMessage, + this.srpWord0, + ]); + } catch (e) { + console.log( + 'Timeout while waiting for onboarding srp page to be loaded', + e, + ); + throw e; + } + console.log('Onboarding srp page is loaded'); + } + + async clickConfirmButton(): Promise { + await this.driver.clickElementAndWaitToDisappear(this.srpConfirmButton); + } + + /** + * Fill the SRP words with the provided seed phrase + * + * @param seedPhrase - The seed phrase to fill. Defaults to TEST_SEED_PHRASE. + */ + async fillSrp(seedPhrase: string = TEST_SEED_PHRASE): Promise { + await this.driver.pasteIntoField(this.srpWord0, seedPhrase); + } + + async check_confirmSrpButtonIsDisabled(): Promise { + console.log('Check that confirm SRP button is disabled'); + const confirmSeedPhrase = await this.driver.findElement( + this.srpConfirmButton, + ); + assert.equal(await confirmSeedPhrase.isEnabled(), false); + } + + /** + * Check the SRP dropdown iterates through each option + * + * @param numOptions - The number of options to check. Defaults to 5. + */ + async check_srpDropdownIterations(numOptions: number = 5) { + console.log( + `Check the SRP dropdown iterates through ${numOptions} options`, + ); + await this.driver.clickElement(this.srpDropdown); + await this.driver.wait(async () => { + const options = await this.driver.findElements(this.srpDropdownOptions); + return options.length === numOptions; + }, this.driver.timeout); + + const options = await this.driver.findElements(this.srpDropdownOptions); + for (let i = 0; i < options.length; i++) { + if (i !== 0) { + await this.driver.clickElement(this.srpDropdown); + } + await options[i].click(); + const expectedNumFields = 12 + i * 3; + await this.driver.wait(async () => { + const srpWordsFields = await this.driver.findElements(this.srpWords); + return expectedNumFields === srpWordsFields.length; + }, this.driver.timeout); + } + } + + async check_wrongSrpWarningMessage(): Promise { + console.log('Check that wrong SRP warning message is displayed'); + await this.driver.waitForSelector(this.wrongSrpWarningMessage); + } +} + +export default OnboardingSrpPage; diff --git a/test/e2e/page-objects/pages/onboarding/secure-wallet-page.ts b/test/e2e/page-objects/pages/onboarding/secure-wallet-page.ts new file mode 100644 index 000000000000..cff7549a0f75 --- /dev/null +++ b/test/e2e/page-objects/pages/onboarding/secure-wallet-page.ts @@ -0,0 +1,107 @@ +import { Driver } from '../../../webdriver/driver'; + +class SecureWalletPage { + private driver: Driver; + + private readonly confirmRecoveryPhraseButton = + '[data-testid="recovery-phrase-confirm"]'; + + private readonly confirmSecretRecoveryPhraseMessage = { + text: 'Confirm Secret Recovery Phrase', + tag: 'h2', + }; + + private readonly recoveryPhraseChips = + '[data-testid="recovery-phrase-chips"]'; + + private readonly recoveryPhraseInputIndex2 = + '[data-testid="recovery-phrase-input-2"]'; + + private readonly recoveryPhraseInputIndex3 = + '[data-testid="recovery-phrase-input-3"]'; + + private readonly recoveryPhraseInputIndex7 = + '[data-testid="recovery-phrase-input-7"]'; + + private readonly recoveryPhraseNextButton = + '[data-testid="recovery-phrase-next"]'; + + private readonly revealSecretRecoveryPhraseButton = + '[data-testid="recovery-phrase-reveal"]'; + + private readonly secureWalletButton = + '[data-testid="secure-wallet-recommended"]'; + + private readonly secureWalletLaterButton = + '[data-testid="secure-wallet-later"]'; + + private readonly secureWalletMessage = { + text: 'Secure your wallet', + tag: 'h2', + }; + + private readonly writeDownSecretRecoveryPhraseMessage = { + text: 'Write down your Secret Recovery Phrase', + tag: 'h2', + }; + + constructor(driver: Driver) { + this.driver = driver; + } + + async check_pageIsLoaded(): Promise { + try { + await this.driver.waitForMultipleSelectors([ + this.secureWalletMessage, + this.secureWalletButton, + this.secureWalletLaterButton, + ]); + } catch (e) { + console.log( + 'Timeout while waiting for secure wallet page to be loaded', + e, + ); + throw e; + } + console.log('Secure wallet page is loaded'); + } + + async revealAndConfirmSRP(): Promise { + console.log( + 'Reveal and confirm SRP on secure wallet page during onboarding', + ); + // click secure my wallet button to reveal SRP + await this.driver.clickElement(this.secureWalletButton); + await this.driver.waitForMultipleSelectors([ + this.writeDownSecretRecoveryPhraseMessage, + this.revealSecretRecoveryPhraseButton, + ]); + + // click reveal button to reveal SRP + await this.driver.clickElement(this.revealSecretRecoveryPhraseButton); + await this.driver.waitForSelector(this.recoveryPhraseChips); + + let finalWords: string[] = []; + await this.driver.wait(async () => { + const recoveryPhraseChips = await this.driver.findElement( + this.recoveryPhraseChips, + ); + const recoveryPhrase = await recoveryPhraseChips.getText(); + const words = recoveryPhrase.split(/\s*(?:[0-9)]+|\n|\.|^$|$)\s*/u); + finalWords = words.filter((str) => str !== ''); + return finalWords.length === 12; + }, this.driver.timeout); + await this.driver.clickElement(this.recoveryPhraseNextButton); + + // confirm SRP + await this.driver.waitForSelector(this.confirmSecretRecoveryPhraseMessage); + await this.driver.fill(this.recoveryPhraseInputIndex2, finalWords[2]); + await this.driver.fill(this.recoveryPhraseInputIndex3, finalWords[3]); + await this.driver.fill(this.recoveryPhraseInputIndex7, finalWords[7]); + await this.driver.clickElementAndWaitToDisappear( + this.confirmRecoveryPhraseButton, + ); + } +} + +export default SecureWalletPage; diff --git a/test/e2e/page-objects/pages/onboarding/start-onboarding-page.ts b/test/e2e/page-objects/pages/onboarding/start-onboarding-page.ts new file mode 100644 index 000000000000..47c0b53a2b2f --- /dev/null +++ b/test/e2e/page-objects/pages/onboarding/start-onboarding-page.ts @@ -0,0 +1,52 @@ +import { Driver } from '../../../webdriver/driver'; + +class StartOnboardingPage { + private driver: Driver; + + private readonly createWalletButton = + '[data-testid="onboarding-create-wallet"]'; + + private readonly importWalletButton = + '[data-testid="onboarding-import-wallet"]'; + + private readonly startMessage = { + text: "Let's get started", + tag: 'h2', + }; + + private readonly termsCheckbox = '[data-testid="onboarding-terms-checkbox"]'; + + constructor(driver: Driver) { + this.driver = driver; + } + + async check_pageIsLoaded(): Promise { + try { + await this.driver.waitForMultipleSelectors([ + this.startMessage, + this.termsCheckbox, + ]); + } catch (e) { + console.log( + 'Timeout while waiting for start onboarding page to be loaded', + e, + ); + throw e; + } + console.log('Start onboarding page is loaded'); + } + + async checkTermsCheckbox(): Promise { + await this.driver.clickElement(this.termsCheckbox); + } + + async clickCreateWalletButton(): Promise { + await this.driver.clickElementAndWaitToDisappear(this.createWalletButton); + } + + async clickImportWalletButton(): Promise { + await this.driver.clickElementAndWaitToDisappear(this.importWalletButton); + } +} + +export default StartOnboardingPage; diff --git a/test/e2e/tests/account/snap-account-signatures.spec.ts b/test/e2e/tests/account/snap-account-signatures.spec.ts index fd2fe013c3c1..98cfe9b18337 100644 --- a/test/e2e/tests/account/snap-account-signatures.spec.ts +++ b/test/e2e/tests/account/snap-account-signatures.spec.ts @@ -18,7 +18,7 @@ import SnapSimpleKeyringPage from '../../page-objects/pages/snap-simple-keyring- import TestDapp from '../../page-objects/pages/test-dapp'; describe('Snap Account Signatures @no-mmi', function (this: Suite) { - this.timeout(120000); // This test is very long, so we need an unusually high timeout + this.timeout(150000); // This test is very long, so we need an unusually high timeout // Run sync, async approve, and async reject flows // (in Jest we could do this with test.each, but that does not exist here) diff --git a/test/e2e/tests/onboarding/onboarding.spec.js b/test/e2e/tests/onboarding/onboarding.spec.js deleted file mode 100644 index de040f825ee6..000000000000 --- a/test/e2e/tests/onboarding/onboarding.spec.js +++ /dev/null @@ -1,748 +0,0 @@ -const { strict: assert } = require('assert'); -const { toHex } = require('@metamask/controller-utils'); -const { By } = require('selenium-webdriver'); -const { - TEST_SEED_PHRASE, - convertToHexValue, - withFixtures, - completeCreateNewWalletOnboardingFlow, - completeImportSRPOnboardingFlow, - importSRPOnboardingFlow, - importWrongSRPOnboardingFlow, - testSRPDropdownIterations, - locateAccountBalanceDOM, - defaultGanacheOptions, - WALLET_PASSWORD, - onboardingBeginCreateNewWallet, - onboardingChooseMetametricsOption, - onboardingCreatePassword, - onboardingRevealAndConfirmSRP, - onboardingCompleteWalletCreation, - regularDelayMs, - unlockWallet, -} = require('../../helpers'); -const FixtureBuilder = require('../../fixture-builder'); -const { - FirstTimeFlowType, -} = require('../../../../shared/constants/onboarding'); - -describe('MetaMask onboarding @no-mmi', function () { - const wrongSeedPhrase = - 'test test test test test test test test test test test test'; - const wrongTestPassword = 'test test test test'; - - const ganacheOptions2 = { - accounts: [ - { - secretKey: - '0x53CB0AB5226EEBF4D872113D98332C1555DC304443BEE1CF759D15798D3C55A9', - balance: convertToHexValue(10000000000000000000), - }, - ], - }; - - it('Clicks create a new wallet, accepts a secure password, reveals the Secret Recovery Phrase, confirm SRP', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder({ onboarding: true }).build(), - ganacheOptions: defaultGanacheOptions, - title: this.test.fullTitle(), - }, - async ({ driver }) => { - await driver.navigate(); - - await completeCreateNewWalletOnboardingFlow(driver, WALLET_PASSWORD); - - const homePage = await driver.findElement('.home__main-view'); - const homePageDisplayed = await homePage.isDisplayed(); - - assert.equal(homePageDisplayed, true); - }, - ); - }); - - it('Clicks import a new wallet, accepts a secure password, reveals the Secret Recovery Phrase, confirm SRP', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder({ onboarding: true }).build(), - ganacheOptions: defaultGanacheOptions, - title: this.test.fullTitle(), - }, - async ({ driver }) => { - await driver.navigate(); - - await completeImportSRPOnboardingFlow( - driver, - TEST_SEED_PHRASE, - WALLET_PASSWORD, - ); - - const homePage = await driver.findElement('.home__main-view'); - const homePageDisplayed = await homePage.isDisplayed(); - - assert.equal(homePageDisplayed, true); - }, - ); - }); - - it('User import wrong Secret Recovery Phrase', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder({ onboarding: true }).build(), - ganacheOptions: defaultGanacheOptions, - title: this.test.fullTitle(), - }, - async ({ driver }) => { - await driver.navigate(); - - await importWrongSRPOnboardingFlow(driver, wrongSeedPhrase); - - const confirmSeedPhrase = await driver.findElement( - '[data-testid="import-srp-confirm"]', - ); - - assert.equal(await confirmSeedPhrase.isEnabled(), false); - }, - ); - }); - - it('Check if user select different type of secret recovery phrase', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder({ onboarding: true }).build(), - ganacheOptions: defaultGanacheOptions, - title: this.test.fullTitle(), - }, - async ({ driver }) => { - await driver.navigate(); - - // accept terms of use - await driver.clickElement('[data-testid="onboarding-terms-checkbox"]'); - - // welcome - await driver.clickElement('[data-testid="onboarding-import-wallet"]'); - - await driver.clickElement('[data-testid="metametrics-no-thanks"]'); - - const dropdownElement = await driver.findElement( - '.import-srp__number-of-words-dropdown', - ); - await dropdownElement.click(); - const options = await dropdownElement.findElements(By.css('option')); - - const iterations = options.length; - - await testSRPDropdownIterations(options, driver, iterations); - - const finalFormFields = await driver.findElements( - '.import-srp__srp-word-label', - ); - const expectedFinalNumFields = 24; // The last iteration will have 24 fields - const actualFinalNumFields = finalFormFields.length; - assert.equal(actualFinalNumFields, expectedFinalNumFields); - }, - ); - }); - - it('User enters the wrong password during password creation', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder({ onboarding: true }).build(), - ganacheOptions: defaultGanacheOptions, - title: this.test.fullTitle(), - }, - async ({ driver }) => { - await driver.navigate(); - - await driver.clickElement('[data-testid="onboarding-terms-checkbox"]'); - await driver.clickElement('[data-testid="onboarding-create-wallet"]'); - - // metrics - await driver.clickElement('[data-testid="metametrics-no-thanks"]'); - - // Fill in confirm password field with incorrect password - await driver.fill( - '[data-testid="create-password-new"]', - WALLET_PASSWORD, - ); - await driver.fill( - '[data-testid="create-password-confirm"]', - wrongTestPassword, - ); - - // Check that the error message is displayed for the password fields - await driver.isElementPresent( - { text: "Passwords don't match", tag: 'h6' }, - true, - ); - - // Check that the "Confirm Password" button is disabled - const confirmPasswordButton = await driver.findElement( - '[data-testid="create-password-wallet"]', - ); - assert.equal(await confirmPasswordButton.isEnabled(), false); - }, - ); - }); - - it('Verify that the user has been redirected to the correct page after importing their wallet', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder({ onboarding: true }).build(), - ganacheOptions: defaultGanacheOptions, - title: this.test.fullTitle(), - }, - async ({ driver }) => { - await driver.navigate(); - - await importSRPOnboardingFlow( - driver, - TEST_SEED_PHRASE, - WALLET_PASSWORD, - ); - // Verify site - assert.equal( - await driver.isElementPresent({ - text: 'Your wallet is ready', - tag: 'h2', - }), - true, - ); - }, - ); - }); - - it('Verify that the user has been redirected to the correct page after creating a password for their new wallet', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder({ onboarding: true }).build(), - ganacheOptions: defaultGanacheOptions, - title: this.test.fullTitle(), - }, - async ({ driver }) => { - await driver.navigate(); - - await driver.clickElement('[data-testid="onboarding-terms-checkbox"]'); - await driver.clickElement('[data-testid="onboarding-create-wallet"]'); - - // metrics - await driver.clickElement('[data-testid="metametrics-no-thanks"]'); - - // Fill in confirm password field with correct password - await driver.fill( - '[data-testid="create-password-new"]', - WALLET_PASSWORD, - ); - await driver.fill( - '[data-testid="create-password-confirm"]', - WALLET_PASSWORD, - ); - await driver.clickElement('[data-testid="create-password-terms"]'); - await driver.clickElement('[data-testid="create-password-wallet"]'); - - // Verify site - assert.equal( - await driver.isElementPresent({ - text: 'Secure your wallet', - tag: 'h2', - }), - true, - ); - }, - ); - }); - - it('User can add custom network during onboarding', async function () { - const networkName = 'Localhost 8546'; - const networkUrl = 'http://127.0.0.1:8546'; - const currencySymbol = 'ETH'; - const port = 8546; - const chainId = 1338; - await withFixtures( - { - fixtures: new FixtureBuilder({ onboarding: true }).build(), - ganacheOptions: { - ...defaultGanacheOptions, - concurrent: [{ port, chainId, ganacheOptions2 }], - }, - title: this.test.fullTitle(), - }, - - async ({ driver, secondaryGanacheServer }) => { - try { - await driver.navigate(); - await importSRPOnboardingFlow( - driver, - TEST_SEED_PHRASE, - WALLET_PASSWORD, - ); - - await driver.clickElement({ - text: 'Manage default privacy settings', - tag: 'button', - }); - - await driver.clickElement({ - text: 'General', - }); - await driver.clickElement({ text: 'Add a network' }); - - await driver.waitForSelector( - '.multichain-network-list-menu-content-wrapper__dialog', - ); - - await driver.fill( - '[data-testid="network-form-network-name"]', - networkName, - ); - await driver.fill( - '[data-testid="network-form-chain-id"]', - chainId.toString(), - ); - await driver.fill( - '[data-testid="network-form-ticker-input"]', - currencySymbol, - ); - - // Add rpc url - const rpcUrlInputDropDown = await driver.waitForSelector( - '[data-testid="test-add-rpc-drop-down"]', - ); - await rpcUrlInputDropDown.click(); - await driver.clickElement({ - text: 'Add RPC URL', - tag: 'button', - }); - const rpcUrlInput = await driver.waitForSelector( - '[data-testid="rpc-url-input-test"]', - ); - await rpcUrlInput.clear(); - await rpcUrlInput.sendKeys(networkUrl); - await driver.clickElement({ - text: 'Add URL', - tag: 'button', - }); - - await driver.clickElementAndWaitToDisappear({ - tag: 'button', - text: 'Save', - }); - - 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( - '[data-testid="privacy-settings-back-button"]', - ); - - await driver.clickElement( - '[data-testid="privacy-settings-back-button"]', - ); - - await driver.clickElementAndWaitToDisappear({ - text: 'Done', - tag: 'button', - }); - - await driver.clickElement({ - text: 'Next', - tag: 'button', - }); - - // Wait until the onboarding carousel has stopped moving - // otherwise the click has no effect. - await driver.waitForElementToStopMoving({ - text: 'Done', - tag: 'button', - }); - - await driver.clickElementAndWaitToDisappear({ - text: 'Done', - tag: 'button', - }); - - await driver.clickElement('.mm-picker-network'); - await driver.clickElement( - `[data-rbd-draggable-id="${toHex(chainId)}"]`, - ); - // Check localhost 8546 is selected and its balance value is correct - await driver.findElement({ - css: '[data-testid="network-display"]', - text: networkName, - }); - - await locateAccountBalanceDOM(driver, secondaryGanacheServer[0]); - } catch (error) { - console.error('Error in test:', error); - throw error; - } - }, - ); - }); - - it('User can turn off basic functionality in default settings', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder({ onboarding: true }).build(), - ganacheOptions: defaultGanacheOptions, - title: this.test.fullTitle(), - }, - async ({ driver }) => { - await driver.navigate(); - await importSRPOnboardingFlow( - driver, - TEST_SEED_PHRASE, - WALLET_PASSWORD, - ); - - await driver.clickElement({ - text: 'Manage default privacy settings', - tag: 'button', - }); - await driver.clickElement('[data-testid="category-item-General"]'); - await driver.clickElement( - '[data-testid="basic-functionality-toggle"] .toggle-button', - ); - await driver.clickElement('[id="basic-configuration-checkbox"]'); - await driver.clickElement({ text: 'Turn off', tag: 'button' }); - 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( - '[data-testid="privacy-settings-back-button"]', - ); - await driver.clickElement( - '[data-testid="privacy-settings-back-button"]', - ); - - await driver.clickElement('[data-testid="onboarding-complete-done"]'); - await driver.clickElement('[data-testid="pin-extension-next"]'); - await driver.clickElement('[data-testid="pin-extension-done"]'); - - // Check that the 'basic functionality is off' banner is displayed on the home screen after onboarding completion - await driver.waitForSelector({ - text: 'Basic functionality is off', - css: '.mm-banner-alert', - }); - }, - ); - }); - - it("doesn't make any network requests to infura before onboarding is completed", async function () { - async function mockInfura(mockServer) { - const infuraUrl = - 'https://mainnet.infura.io/v3/00000000000000000000000000000000'; - const sampleAddress = '1111111111111111111111111111111111111111'; - - return [ - await mockServer - .forPost(infuraUrl) - .withJsonBodyIncluding({ method: 'eth_blockNumber' }) - .thenCallback(() => { - return { - statusCode: 200, - json: { - jsonrpc: '2.0', - id: '1111111111111111', - result: '0x1', - }, - }; - }), - await mockServer - .forPost(infuraUrl) - .withJsonBodyIncluding({ method: 'eth_getBalance' }) - .thenCallback(() => { - return { - statusCode: 200, - json: { - jsonrpc: '2.0', - id: '1111111111111111', - result: '0x0', - }, - }; - }), - await mockServer - .forPost(infuraUrl) - .withJsonBodyIncluding({ method: 'eth_getBlockByNumber' }) - .thenCallback(() => { - return { - statusCode: 200, - json: { - jsonrpc: '2.0', - id: '1111111111111111', - result: {}, - }, - }; - }), - await mockServer - .forPost(infuraUrl) - .withJsonBodyIncluding({ method: 'eth_call' }) - .thenCallback(() => { - return { - statusCode: 200, - json: { - jsonrpc: '2.0', - id: '1111111111111111', - result: `0x000000000000000000000000${sampleAddress}`, - }, - }; - }), - await mockServer - .forPost(infuraUrl) - .withJsonBodyIncluding({ method: 'net_version' }) - .thenCallback(() => { - return { - statusCode: 200, - json: { id: 8262367391254633, jsonrpc: '2.0', result: '1337' }, - }; - }), - ]; - } - - await withFixtures( - { - fixtures: new FixtureBuilder({ onboarding: true }) - .withNetworkControllerOnMainnet() - .build(), - ganacheOptions: defaultGanacheOptions, - title: this.test.fullTitle(), - testSpecificMock: mockInfura, - }, - async ({ driver, mockedEndpoint: mockedEndpoints }) => { - const password = 'password'; - - await driver.navigate(); - - await onboardingBeginCreateNewWallet(driver); - await onboardingChooseMetametricsOption(driver, false); - await onboardingCreatePassword(driver, password); - await onboardingRevealAndConfirmSRP(driver); - await onboardingCompleteWalletCreation(driver); - - // pin extension walkthrough screen - await driver.clickElement('[data-testid="pin-extension-next"]'); - - for (let i = 0; i < mockedEndpoints.length; i += 1) { - const mockedEndpoint = await mockedEndpoints[i]; - const isPending = await mockedEndpoint.isPending(); - assert.equal( - isPending, - true, - `${mockedEndpoints[i]} mock should still be pending before onboarding`, - ); - const requests = await mockedEndpoint.getSeenRequests(); - - assert.equal( - requests.length, - 0, - `${mockedEndpoints[i]} should make no requests before onboarding`, - ); - } - - await driver.clickElement('[data-testid="pin-extension-done"]'); - // requests happen here! - - for (let i = 0; i < mockedEndpoints.length; i += 1) { - const mockedEndpoint = await mockedEndpoints[i]; - - await driver.wait(async () => { - const isPending = await mockedEndpoint.isPending(); - return isPending === false; - }, driver.timeout); - - const requests = await mockedEndpoint.getSeenRequests(); - - assert.equal( - requests.length > 0, - true, - `${mockedEndpoints[i]} should make requests after onboarding`, - ); - } - }, - ); - }); - - it("doesn't make any network requests to infura before onboarding by import is completed", async function () { - async function mockInfura(mockServer) { - const infuraUrl = - 'https://mainnet.infura.io/v3/00000000000000000000000000000000'; - const sampleAddress = '1111111111111111111111111111111111111111'; - - return [ - await mockServer - .forPost(infuraUrl) - .withJsonBodyIncluding({ method: 'eth_blockNumber' }) - .thenCallback(() => { - return { - statusCode: 200, - json: { - jsonrpc: '2.0', - id: '1111111111111111', - result: '0x1', - }, - }; - }), - await mockServer - .forPost(infuraUrl) - .withJsonBodyIncluding({ method: 'eth_getBalance' }) - .thenCallback(() => { - return { - statusCode: 200, - json: { - jsonrpc: '2.0', - id: '1111111111111111', - result: '0x0', - }, - }; - }), - await mockServer - .forPost(infuraUrl) - .withJsonBodyIncluding({ method: 'eth_getBlockByNumber' }) - .thenCallback(() => { - return { - statusCode: 200, - json: { - jsonrpc: '2.0', - id: '1111111111111111', - result: {}, - }, - }; - }), - await mockServer - .forPost(infuraUrl) - .withJsonBodyIncluding({ method: 'eth_call' }) - .thenCallback(() => { - return { - statusCode: 200, - json: { - jsonrpc: '2.0', - id: '1111111111111111', - result: `0x000000000000000000000000${sampleAddress}`, - }, - }; - }), - await mockServer - .forPost(infuraUrl) - .withJsonBodyIncluding({ method: 'net_version' }) - .thenCallback(() => { - return { - statusCode: 200, - json: { id: 8262367391254633, jsonrpc: '2.0', result: '1337' }, - }; - }), - ]; - } - - await withFixtures( - { - fixtures: new FixtureBuilder({ onboarding: true }) - .withNetworkControllerOnMainnet() - .build(), - ganacheOptions: defaultGanacheOptions, - title: this.test.fullTitle(), - testSpecificMock: mockInfura, - }, - async ({ driver, mockedEndpoint: mockedEndpoints }) => { - const password = 'password'; - - await driver.navigate(); - - await importSRPOnboardingFlow(driver, TEST_SEED_PHRASE, password); - - await driver.delay(regularDelayMs); - - for (let i = 0; i < mockedEndpoints.length; i += 1) { - const mockedEndpoint = await mockedEndpoints[i]; - const requests = await mockedEndpoint.getSeenRequests(); - - assert.equal( - requests.length, - 0, - `${mockedEndpoints[i]} should make no requests before onboarding`, - ); - } - - // complete - await driver.clickElement('[data-testid="onboarding-complete-done"]'); - - // pin extension - await driver.clickElement('[data-testid="pin-extension-next"]'); - await driver.clickElement('[data-testid="pin-extension-done"]'); - - // pin extension walkthrough screen - await driver.findElement('[data-testid="account-menu-icon"]'); - // requests happen here! - - for (let i = 0; i < mockedEndpoints.length; i += 1) { - const mockedEndpoint = await mockedEndpoints[i]; - - await driver.wait(async () => { - const isPending = await mockedEndpoint.isPending(); - return isPending === false; - }, driver.timeout); - - const requests = await mockedEndpoint.getSeenRequests(); - - assert.equal( - requests.length > 0, - true, - `${mockedEndpoints[i]} should make requests after onboarding`, - ); - } - }, - ); - }); - - it('Provides an onboarding path for a user who has restored their account from state persistence failure', async function () { - // We don't use onboarding:true here because we want there to be a vault, - // simulating what will happen when a user eventually restores their vault - // during a state persistence failure. Instead, we set the - // firstTimeFlowType to 'restore' and completedOnboarding to false. as well - // as some other first time state options to get us into an onboarding - // state similar to a new state tree. - await withFixtures( - { - fixtures: new FixtureBuilder() - .withOnboardingController({ - completedOnboarding: false, - firstTimeFlowType: FirstTimeFlowType.restore, - seedPhraseBackedUp: null, - }) - .withMetaMetricsController({ - participateInMetaMetrics: null, - metaMetricsId: null, - }) - .build(), - ganacheOptions: defaultGanacheOptions, - title: this.test.fullTitle(), - }, - async ({ driver }) => { - await unlockWallet(driver); - - // First screen we should be on is MetaMetrics - assert.equal( - await driver.isElementPresent({ - text: 'Help us improve MetaMask', - tag: 'h2', - }), - true, - 'First screen should be MetaMetrics', - ); - - // select no thanks - await driver.clickElement('[data-testid="metametrics-no-thanks"]'); - - // Next should be Secure your wallet screen - assert.equal( - await driver.isElementPresent({ - text: 'Secure your wallet', - tag: 'h2', - }), - true, - ); - }, - ); - }); -}); diff --git a/test/e2e/tests/onboarding/onboarding.spec.ts b/test/e2e/tests/onboarding/onboarding.spec.ts new file mode 100644 index 000000000000..1af2d5170841 --- /dev/null +++ b/test/e2e/tests/onboarding/onboarding.spec.ts @@ -0,0 +1,269 @@ +import { + convertToHexValue, + WALLET_PASSWORD, + withFixtures, +} from '../../helpers'; +import { Driver } from '../../webdriver/driver'; +import FixtureBuilder from '../../fixture-builder'; +import { FirstTimeFlowType } from '../../../../shared/constants/onboarding'; +import HomePage from '../../page-objects/pages/homepage'; +import OnboardingCompletePage from '../../page-objects/pages/onboarding/onboarding-complete-page'; +import OnboardingMetricsPage from '../../page-objects/pages/onboarding/onboarding-metrics-page'; +import OnboardingPasswordPage from '../../page-objects/pages/onboarding/onboarding-password-page'; +import OnboardingPrivacySettingsPage from '../../page-objects/pages/onboarding/onboarding-privacy-settings-page'; +import OnboardingSrpPage from '../../page-objects/pages/onboarding/onboarding-srp-page'; +import SecureWalletPage from '../../page-objects/pages/onboarding/secure-wallet-page'; +import StartOnboardingPage from '../../page-objects/pages/onboarding/start-onboarding-page'; +import { loginWithoutBalanceValidation } from '../../page-objects/flows/login.flow'; +import { + completeCreateNewWalletOnboardingFlow, + completeImportSRPOnboardingFlow, + importSRPOnboardingFlow, +} from '../../page-objects/flows/onboarding.flow'; + +describe('MetaMask onboarding @no-mmi', function () { + const ganacheOptions2 = { + accounts: [ + { + secretKey: + '0x53CB0AB5226EEBF4D872113D98332C1555DC304443BEE1CF759D15798D3C55A9', + balance: convertToHexValue(10000000000000000000), + }, + ], + }; + + it('Creates a new wallet, sets up a secure password, and completes the onboarding process', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder({ onboarding: true }).build(), + title: this.test?.fullTitle(), + }, + async ({ driver }: { driver: Driver }) => { + await completeCreateNewWalletOnboardingFlow(driver); + const homePage = new HomePage(driver); + await homePage.check_pageIsLoaded(); + await homePage.check_expectedBalanceIsDisplayed(); + }, + ); + }); + + it('Imports an existing wallet, sets up a secure password, and completes the onboarding process', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder({ onboarding: true }).build(), + title: this.test?.fullTitle(), + }, + async ({ driver }: { driver: Driver }) => { + await completeImportSRPOnboardingFlow(driver); + const homePage = new HomePage(driver); + await homePage.check_pageIsLoaded(); + await homePage.check_expectedBalanceIsDisplayed(); + }, + ); + }); + + it('Attempts to import a wallet with an incorrect Secret Recovery Phrase and verifies the error message', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder({ onboarding: true }).build(), + title: this.test?.fullTitle(), + }, + async ({ driver }: { driver: Driver }) => { + const wrongSeedPhrase = + 'test test test test test test test test test test test test'; + await driver.navigate(); + const startOnboardingPage = new StartOnboardingPage(driver); + await startOnboardingPage.check_pageIsLoaded(); + await startOnboardingPage.checkTermsCheckbox(); + await startOnboardingPage.clickImportWalletButton(); + + const onboardingMetricsPage = new OnboardingMetricsPage(driver); + await onboardingMetricsPage.check_pageIsLoaded(); + await onboardingMetricsPage.clickNoThanksButton(); + + const onboardingSrpPage = new OnboardingSrpPage(driver); + await onboardingSrpPage.check_pageIsLoaded(); + await onboardingSrpPage.fillSrp(wrongSeedPhrase); + + // check the wrong SRP warning message is displayed + await onboardingSrpPage.check_wrongSrpWarningMessage(); + await onboardingSrpPage.check_confirmSrpButtonIsDisabled(); + }, + ); + }); + + it('Verifies the functionality of selecting different Secret Recovery Phrase word counts', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder({ onboarding: true }).build(), + title: this.test?.fullTitle(), + }, + async ({ driver }: { driver: Driver }) => { + await driver.navigate(); + const startOnboardingPage = new StartOnboardingPage(driver); + await startOnboardingPage.check_pageIsLoaded(); + await startOnboardingPage.checkTermsCheckbox(); + await startOnboardingPage.clickImportWalletButton(); + + const onboardingMetricsPage = new OnboardingMetricsPage(driver); + await onboardingMetricsPage.check_pageIsLoaded(); + await onboardingMetricsPage.clickNoThanksButton(); + + const onboardingSrpPage = new OnboardingSrpPage(driver); + await onboardingSrpPage.check_pageIsLoaded(); + await onboardingSrpPage.check_srpDropdownIterations(); + }, + ); + }); + + it('Verifies error handling when entering an incorrect password during wallet creation', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder({ onboarding: true }).build(), + title: this.test?.fullTitle(), + }, + async ({ driver }: { driver: Driver }) => { + const wrongTestPassword = 'test test test test'; + await driver.navigate(); + const startOnboardingPage = new StartOnboardingPage(driver); + await startOnboardingPage.check_pageIsLoaded(); + await startOnboardingPage.checkTermsCheckbox(); + await startOnboardingPage.clickCreateWalletButton(); + + const onboardingMetricsPage = new OnboardingMetricsPage(driver); + await onboardingMetricsPage.check_pageIsLoaded(); + await onboardingMetricsPage.clickNoThanksButton(); + + const onboardingPasswordPage = new OnboardingPasswordPage(driver); + await onboardingPasswordPage.check_pageIsLoaded(); + await onboardingPasswordPage.fillWalletPassword( + WALLET_PASSWORD, + wrongTestPassword, + ); + + // check the incorrect password warning message is displayed + await onboardingPasswordPage.check_incorrectPasswordWarningMessageIsDisplayed(); + await onboardingPasswordPage.check_confirmPasswordButtonIsDisabled(); + }, + ); + }); + + it('User can add custom network during onboarding', async function () { + const networkName = 'Localhost 8546'; + const networkUrl = 'http://127.0.0.1:8546'; + const currencySymbol = 'ETH'; + const port = 8546; + const chainId = 1338; + await withFixtures( + { + fixtures: new FixtureBuilder({ onboarding: true }).build(), + ganacheOptions: { + concurrent: [{ port, chainId, ganacheOptions2 }], + }, + title: this.test?.fullTitle(), + }, + async ({ driver, secondaryGanacheServer }) => { + await importSRPOnboardingFlow(driver); + + const onboardingCompletePage = new OnboardingCompletePage(driver); + await onboardingCompletePage.check_pageIsLoaded(); + await onboardingCompletePage.check_walletReadyMessageIsDisplayed(); + await onboardingCompletePage.navigateToDefaultPrivacySettings(); + + const onboardingPrivacySettingsPage = new OnboardingPrivacySettingsPage( + driver, + ); + await onboardingPrivacySettingsPage.addCustomNetwork( + networkName, + chainId, + currencySymbol, + networkUrl, + ); + await onboardingPrivacySettingsPage.navigateBackToOnboardingCompletePage(); + + await onboardingCompletePage.check_pageIsLoaded(); + await onboardingCompletePage.completeOnboarding(); + + const homePage = new HomePage(driver); + await homePage.check_pageIsLoaded(); + await homePage.headerNavbar.switchToNetwork(networkName); + + // Check the correct balance for the custom network is displayed + if (secondaryGanacheServer && Array.isArray(secondaryGanacheServer)) { + await homePage.check_ganacheBalanceIsDisplayed( + secondaryGanacheServer[0], + ); + } else { + throw new Error('Custom network Ganache server not available'); + } + }, + ); + }); + + it('User can turn off basic functionality in default settings', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder({ onboarding: true }).build(), + title: this.test?.fullTitle(), + }, + async ({ driver }) => { + await importSRPOnboardingFlow(driver); + + const onboardingCompletePage = new OnboardingCompletePage(driver); + await onboardingCompletePage.check_pageIsLoaded(); + await onboardingCompletePage.check_walletReadyMessageIsDisplayed(); + await onboardingCompletePage.navigateToDefaultPrivacySettings(); + + const onboardingPrivacySettingsPage = new OnboardingPrivacySettingsPage( + driver, + ); + await onboardingPrivacySettingsPage.toggleBasicFunctionalitySettings(); + await onboardingPrivacySettingsPage.navigateBackToOnboardingCompletePage(); + + await onboardingCompletePage.check_pageIsLoaded(); + await onboardingCompletePage.completeOnboarding(); + + const homePage = new HomePage(driver); + await homePage.check_pageIsLoaded(); + // check the basic functionality is off warning message is displayed + await homePage.check_basicFunctionalityOffWarnigMessageIsDisplayed(); + }, + ); + }); + + it('Provides an onboarding path for a user who has restored their account from state persistence failure', async function () { + // We don't use onboarding: true here because we want there to be a vault, + // simulating what will happen when a user eventually restores their vault + // during a state persistence failure. Instead, we set the + // firstTimeFlowType to 'restore' and completedOnboarding to false. as well + // as some other first time state options to get us into an onboarding + // state similar to a new state tree. + await withFixtures( + { + fixtures: new FixtureBuilder() + .withOnboardingController({ + completedOnboarding: false, + firstTimeFlowType: FirstTimeFlowType.restore, + seedPhraseBackedUp: null, + }) + .withMetaMetricsController({ + participateInMetaMetrics: null, + metaMetricsId: null, + }) + .build(), + title: this.test?.fullTitle(), + }, + async ({ driver }) => { + await loginWithoutBalanceValidation(driver); + // First screen we should be on is MetaMetrics + const onboardingMetricsPage = new OnboardingMetricsPage(driver); + await onboardingMetricsPage.check_pageIsLoaded(); + await onboardingMetricsPage.clickNoThanksButton(); + + // Next screen should be Secure your wallet screen + const secureWalletPage = new SecureWalletPage(driver); + await secureWalletPage.check_pageIsLoaded(); + }, + ); + }); +}); diff --git a/test/e2e/tests/api-usage/account-tracker-api-usage.spec.ts b/test/e2e/tests/privacy/account-tracker-api-usage.spec.ts similarity index 100% rename from test/e2e/tests/api-usage/account-tracker-api-usage.spec.ts rename to test/e2e/tests/privacy/account-tracker-api-usage.spec.ts diff --git a/test/e2e/tests/privacy/onboarding-privacy.spec.js b/test/e2e/tests/privacy/onboarding-privacy.spec.js new file mode 100644 index 000000000000..7febe8eb1a9f --- /dev/null +++ b/test/e2e/tests/privacy/onboarding-privacy.spec.js @@ -0,0 +1,283 @@ +const { strict: assert } = require('assert'); +const { + TEST_SEED_PHRASE, + withFixtures, + importSRPOnboardingFlow, + defaultGanacheOptions, + onboardingBeginCreateNewWallet, + onboardingChooseMetametricsOption, + onboardingCreatePassword, + onboardingRevealAndConfirmSRP, + onboardingCompleteWalletCreation, + regularDelayMs, +} = require('../../helpers'); +const FixtureBuilder = require('../../fixture-builder'); + +describe('MetaMask onboarding @no-mmi', function () { + it("doesn't make any network requests to infura before onboarding is completed", async function () { + async function mockInfura(mockServer) { + const infuraUrl = + 'https://mainnet.infura.io/v3/00000000000000000000000000000000'; + const sampleAddress = '1111111111111111111111111111111111111111'; + + return [ + await mockServer + .forPost(infuraUrl) + .withJsonBodyIncluding({ method: 'eth_blockNumber' }) + .thenCallback(() => { + return { + statusCode: 200, + json: { + jsonrpc: '2.0', + id: '1111111111111111', + result: '0x1', + }, + }; + }), + await mockServer + .forPost(infuraUrl) + .withJsonBodyIncluding({ method: 'eth_getBalance' }) + .thenCallback(() => { + return { + statusCode: 200, + json: { + jsonrpc: '2.0', + id: '1111111111111111', + result: '0x0', + }, + }; + }), + await mockServer + .forPost(infuraUrl) + .withJsonBodyIncluding({ method: 'eth_getBlockByNumber' }) + .thenCallback(() => { + return { + statusCode: 200, + json: { + jsonrpc: '2.0', + id: '1111111111111111', + result: {}, + }, + }; + }), + await mockServer + .forPost(infuraUrl) + .withJsonBodyIncluding({ method: 'eth_call' }) + .thenCallback(() => { + return { + statusCode: 200, + json: { + jsonrpc: '2.0', + id: '1111111111111111', + result: `0x000000000000000000000000${sampleAddress}`, + }, + }; + }), + await mockServer + .forPost(infuraUrl) + .withJsonBodyIncluding({ method: 'net_version' }) + .thenCallback(() => { + return { + statusCode: 200, + json: { id: 8262367391254633, jsonrpc: '2.0', result: '1337' }, + }; + }), + ]; + } + + await withFixtures( + { + fixtures: new FixtureBuilder({ onboarding: true }) + .withNetworkControllerOnMainnet() + .build(), + ganacheOptions: defaultGanacheOptions, + title: this.test.fullTitle(), + testSpecificMock: mockInfura, + }, + async ({ driver, mockedEndpoint: mockedEndpoints }) => { + const password = 'password'; + + await driver.navigate(); + + await onboardingBeginCreateNewWallet(driver); + await onboardingChooseMetametricsOption(driver, false); + await onboardingCreatePassword(driver, password); + await onboardingRevealAndConfirmSRP(driver); + await onboardingCompleteWalletCreation(driver); + + // pin extension walkthrough screen + await driver.clickElement('[data-testid="pin-extension-next"]'); + + await driver.delay(regularDelayMs); + + for (let i = 0; i < mockedEndpoints.length; i += 1) { + const mockedEndpoint = await mockedEndpoints[i]; + const isPending = await mockedEndpoint.isPending(); + assert.equal( + isPending, + true, + `${mockedEndpoints[i]} mock should still be pending before onboarding`, + ); + const requests = await mockedEndpoint.getSeenRequests(); + + assert.equal( + requests.length, + 0, + `${mockedEndpoints[i]} should make no requests before onboarding`, + ); + } + + await driver.clickElement('[data-testid="pin-extension-done"]'); + // requests happen here! + + for (let i = 0; i < mockedEndpoints.length; i += 1) { + const mockedEndpoint = await mockedEndpoints[i]; + + await driver.wait(async () => { + const isPending = await mockedEndpoint.isPending(); + return isPending === false; + }, driver.timeout); + + const requests = await mockedEndpoint.getSeenRequests(); + + assert.equal( + requests.length > 0, + true, + `${mockedEndpoints[i]} should make requests after onboarding`, + ); + } + }, + ); + }); + + it("doesn't make any network requests to infura before onboarding by import is completed", async function () { + async function mockInfura(mockServer) { + const infuraUrl = + 'https://mainnet.infura.io/v3/00000000000000000000000000000000'; + const sampleAddress = '1111111111111111111111111111111111111111'; + + return [ + await mockServer + .forPost(infuraUrl) + .withJsonBodyIncluding({ method: 'eth_blockNumber' }) + .thenCallback(() => { + return { + statusCode: 200, + json: { + jsonrpc: '2.0', + id: '1111111111111111', + result: '0x1', + }, + }; + }), + await mockServer + .forPost(infuraUrl) + .withJsonBodyIncluding({ method: 'eth_getBalance' }) + .thenCallback(() => { + return { + statusCode: 200, + json: { + jsonrpc: '2.0', + id: '1111111111111111', + result: '0x0', + }, + }; + }), + await mockServer + .forPost(infuraUrl) + .withJsonBodyIncluding({ method: 'eth_getBlockByNumber' }) + .thenCallback(() => { + return { + statusCode: 200, + json: { + jsonrpc: '2.0', + id: '1111111111111111', + result: {}, + }, + }; + }), + await mockServer + .forPost(infuraUrl) + .withJsonBodyIncluding({ method: 'eth_call' }) + .thenCallback(() => { + return { + statusCode: 200, + json: { + jsonrpc: '2.0', + id: '1111111111111111', + result: `0x000000000000000000000000${sampleAddress}`, + }, + }; + }), + await mockServer + .forPost(infuraUrl) + .withJsonBodyIncluding({ method: 'net_version' }) + .thenCallback(() => { + return { + statusCode: 200, + json: { id: 8262367391254633, jsonrpc: '2.0', result: '1337' }, + }; + }), + ]; + } + + await withFixtures( + { + fixtures: new FixtureBuilder({ onboarding: true }) + .withNetworkControllerOnMainnet() + .build(), + ganacheOptions: defaultGanacheOptions, + title: this.test.fullTitle(), + testSpecificMock: mockInfura, + }, + async ({ driver, mockedEndpoint: mockedEndpoints }) => { + const password = 'password'; + + await driver.navigate(); + + await importSRPOnboardingFlow(driver, TEST_SEED_PHRASE, password); + + await driver.delay(regularDelayMs); + + for (let i = 0; i < mockedEndpoints.length; i += 1) { + const mockedEndpoint = await mockedEndpoints[i]; + const requests = await mockedEndpoint.getSeenRequests(); + + assert.equal( + requests.length, + 0, + `${mockedEndpoints[i]} should make no requests before onboarding`, + ); + } + + // complete + await driver.clickElement('[data-testid="onboarding-complete-done"]'); + + // pin extension + await driver.clickElement('[data-testid="pin-extension-next"]'); + await driver.clickElement('[data-testid="pin-extension-done"]'); + + // pin extension walkthrough screen + await driver.findElement('[data-testid="account-menu-icon"]'); + // requests happen here! + + for (let i = 0; i < mockedEndpoints.length; i += 1) { + const mockedEndpoint = await mockedEndpoints[i]; + + await driver.wait(async () => { + const isPending = await mockedEndpoint.isPending(); + return isPending === false; + }, driver.timeout); + + const requests = await mockedEndpoint.getSeenRequests(); + + assert.equal( + requests.length > 0, + true, + `${mockedEndpoints[i]} should make requests after onboarding`, + ); + } + }, + ); + }); +}); diff --git a/test/e2e/tests/transaction/ens.spec.ts b/test/e2e/tests/transaction/ens.spec.ts index 4700ab8fac3f..47bae3e5e4cc 100644 --- a/test/e2e/tests/transaction/ens.spec.ts +++ b/test/e2e/tests/transaction/ens.spec.ts @@ -112,6 +112,7 @@ describe('ENS', function (this: Suite) { // click send button on homepage to start send flow const homepage = new HomePage(driver); + await homepage.check_pageIsLoaded(); await homepage.check_expectedBalanceIsDisplayed('<0.000001'); await homepage.startSendFlow();