diff --git a/wallets/metamask/src/metamask.ts b/wallets/metamask/src/metamask.ts index f47ba851c..e54d3aeed 100644 --- a/wallets/metamask/src/metamask.ts +++ b/wallets/metamask/src/metamask.ts @@ -1,10 +1,16 @@ -import type { BrowserContext, Page } from '@playwright/test' -import { CrashPage, HomePage, LockPage, NotificationPage, OnboardingPage } from './pages' -import type { Network } from './pages/HomePage/actions' -import { SettingsSidebarMenus } from './pages/HomePage/selectors/settings' -import type { GasSetting } from './pages/NotificationPage/actions' - -const NO_EXTENSION_ID_ERROR = new Error('MetaMask extensionId is not set') +import type { BrowserContext, Page } from "@playwright/test"; +import { + CrashPage, + HomePage, + LockPage, + NotificationPage, + OnboardingPage, +} from "./pages"; +import type { Network } from "./pages/HomePage/actions"; +import { SettingsSidebarMenus } from "./pages/HomePage/selectors/settings"; +import type { GasSetting } from "./pages/NotificationPage/actions"; + +const NO_EXTENSION_ID_ERROR = new Error("MetaMask extensionId is not set"); /** * This class is the heart of Synpress's MetaMask API. @@ -15,31 +21,31 @@ export class MetaMask { * * @group Selectors */ - readonly crashPage: CrashPage + readonly crashPage: CrashPage; /** * This property can be used to access selectors for a given page. * * @group Selectors */ - readonly onboardingPage: OnboardingPage + readonly onboardingPage: OnboardingPage; /** * This property can be used to access selectors for a given page. * * @group Selectors */ - readonly lockPage: LockPage + readonly lockPage: LockPage; /** * This property can be used to access selectors for a given page. * * @group Selectors */ - readonly homePage: HomePage + readonly homePage: HomePage; /** * This property can be used to access selectors for a given page. * * @group Selectors */ - readonly notificationPage: NotificationPage + readonly notificationPage: NotificationPage; /** * Class constructor. @@ -69,12 +75,12 @@ export class MetaMask { */ readonly extensionId?: string ) { - this.crashPage = new CrashPage() + this.crashPage = new CrashPage(); - this.onboardingPage = new OnboardingPage(page) - this.lockPage = new LockPage(page) - this.homePage = new HomePage(page) - this.notificationPage = new NotificationPage(page) + this.onboardingPage = new OnboardingPage(page); + this.lockPage = new LockPage(page); + this.homePage = new HomePage(page); + this.notificationPage = new NotificationPage(page); } /** @@ -83,7 +89,7 @@ export class MetaMask { * @param seedPhrase - The seed phrase to import. */ async importWallet(seedPhrase: string) { - await this.onboardingPage.importWallet(seedPhrase, this.password) + await this.onboardingPage.importWallet(seedPhrase, this.password); } /** @@ -92,7 +98,7 @@ export class MetaMask { * @param accountName - The name of the new account. */ async addNewAccount(accountName: string) { - await this.homePage.addNewAccount(accountName) + await this.homePage.addNewAccount(accountName); } /** @@ -101,7 +107,7 @@ export class MetaMask { * @param privateKey - The private key to import. */ async importWalletFromPrivateKey(privateKey: string) { - await this.homePage.importWalletFromPrivateKey(privateKey) + await this.homePage.importWalletFromPrivateKey(privateKey); } /** @@ -110,7 +116,7 @@ export class MetaMask { * @param accountName - The name of the account to switch to. */ async switchAccount(accountName: string) { - await this.homePage.switchAccount(accountName) + await this.homePage.switchAccount(accountName); } /** @@ -124,7 +130,7 @@ export class MetaMask { * @param network.blockExplorerUrl - The block explorer URL of the network. */ async addNetwork(network: Network) { - await this.homePage.addNetwork(network) + await this.homePage.addNetwork(network); } /** @@ -134,7 +140,7 @@ export class MetaMask { * @param isTestnet - If switch to a test network. */ async switchNetwork(networkName: string, isTestnet: boolean = false) { - await this.homePage.switchNetwork(networkName, isTestnet) + await this.homePage.switchNetwork(networkName, isTestnet); } /** @@ -142,24 +148,24 @@ export class MetaMask { */ async connectToDapp(accounts?: string[]) { if (!this.extensionId) { - throw NO_EXTENSION_ID_ERROR + throw NO_EXTENSION_ID_ERROR; } - await this.notificationPage.connectToDapp(this.extensionId, accounts) + await this.notificationPage.connectToDapp(this.extensionId, accounts); } /** * Locks MetaMask. */ async lock() { - await this.homePage.lock() + await this.homePage.lock(); } /** * Unlocks MetaMask. */ async unlock() { - await this.lockPage.unlock(this.password) + await this.lockPage.unlock(this.password); } /** @@ -167,10 +173,10 @@ export class MetaMask { */ async confirmSignature() { if (!this.extensionId) { - throw NO_EXTENSION_ID_ERROR + throw NO_EXTENSION_ID_ERROR; } - await this.notificationPage.signMessage(this.extensionId) + await this.notificationPage.signMessage(this.extensionId); } /** @@ -178,10 +184,10 @@ export class MetaMask { */ async rejectSignature() { if (!this.extensionId) { - throw NO_EXTENSION_ID_ERROR + throw NO_EXTENSION_ID_ERROR; } - await this.notificationPage.rejectMessage(this.extensionId) + await this.notificationPage.rejectMessage(this.extensionId); } /** @@ -189,10 +195,10 @@ export class MetaMask { */ async approveNewNetwork() { if (!this.extensionId) { - throw NO_EXTENSION_ID_ERROR + throw NO_EXTENSION_ID_ERROR; } - await this.notificationPage.approveNewNetwork(this.extensionId) + await this.notificationPage.approveNewNetwork(this.extensionId); } /** @@ -200,10 +206,10 @@ export class MetaMask { */ async rejectNewNetwork() { if (!this.extensionId) { - throw NO_EXTENSION_ID_ERROR + throw NO_EXTENSION_ID_ERROR; } - await this.notificationPage.rejectNewNetwork(this.extensionId) + await this.notificationPage.rejectNewNetwork(this.extensionId); } /** @@ -211,10 +217,10 @@ export class MetaMask { */ async approveSwitchNetwork() { if (!this.extensionId) { - throw NO_EXTENSION_ID_ERROR + throw NO_EXTENSION_ID_ERROR; } - await this.notificationPage.approveSwitchNetwork(this.extensionId) + await this.notificationPage.approveSwitchNetwork(this.extensionId); } /** @@ -222,10 +228,10 @@ export class MetaMask { */ async rejectSwitchNetwork() { if (!this.extensionId) { - throw NO_EXTENSION_ID_ERROR + throw NO_EXTENSION_ID_ERROR; } - await this.notificationPage.rejectSwitchNetwork(this.extensionId) + await this.notificationPage.rejectSwitchNetwork(this.extensionId); } /** @@ -236,10 +242,10 @@ export class MetaMask { */ async confirmTransaction(options?: { gasSetting?: GasSetting }) { if (!this.extensionId) { - throw NO_EXTENSION_ID_ERROR + throw NO_EXTENSION_ID_ERROR; } - await this.notificationPage.confirmTransaction(this.extensionId, options) + await this.notificationPage.confirmTransaction(this.extensionId, options); } /** @@ -247,10 +253,10 @@ export class MetaMask { */ async rejectTransaction() { if (!this.extensionId) { - throw NO_EXTENSION_ID_ERROR + throw NO_EXTENSION_ID_ERROR; } - await this.notificationPage.rejectTransaction(this.extensionId) + await this.notificationPage.rejectTransaction(this.extensionId); } /** @@ -264,12 +270,18 @@ export class MetaMask { * @param options.spendLimit - The spend limit to use for the permission. * @param options.gasSetting - The gas setting to use for the approval transaction. */ - async approveTokenPermission(options?: { spendLimit?: 'max' | number; gasSetting?: GasSetting }) { + async approveTokenPermission(options?: { + spendLimit?: "max" | number; + gasSetting?: GasSetting; + }) { if (!this.extensionId) { - throw NO_EXTENSION_ID_ERROR + throw NO_EXTENSION_ID_ERROR; } - await this.notificationPage.approveTokenPermission(this.extensionId, options) + await this.notificationPage.approveTokenPermission( + this.extensionId, + options + ); } /** @@ -281,24 +293,24 @@ export class MetaMask { */ async rejectTokenPermission() { if (!this.extensionId) { - throw NO_EXTENSION_ID_ERROR + throw NO_EXTENSION_ID_ERROR; } - await this.notificationPage.rejectTokenPermission(this.extensionId) + await this.notificationPage.rejectTokenPermission(this.extensionId); } /** * Goes back to the home page of MetaMask tab. */ async goBackToHomePage() { - await this.homePage.goBackToHomePage() + await this.homePage.goBackToHomePage(); } /** * Opens the settings page. */ async openSettings() { - await this.homePage.openSettings() + await this.homePage.openSettings(); } /** @@ -307,7 +319,7 @@ export class MetaMask { * @param menu - The menu to open. */ async openSidebarMenu(menu: SettingsSidebarMenus) { - await this.homePage.openSidebarMenu(menu) + await this.homePage.openSidebarMenu(menu); } /** @@ -318,7 +330,7 @@ export class MetaMask { * ::: */ async toggleShowTestNetworks() { - await this.homePage.toggleShowTestNetworks() + await this.homePage.toggleShowTestNetworks(); } /** @@ -329,7 +341,7 @@ export class MetaMask { * ::: */ async toggleDismissSecretRecoveryPhraseReminder() { - await this.homePage.toggleDismissSecretRecoveryPhraseReminder() + await this.homePage.toggleDismissSecretRecoveryPhraseReminder(); } /** @@ -340,7 +352,7 @@ export class MetaMask { * ::: */ async resetAccount() { - await this.homePage.resetAccount() + await this.homePage.resetAccount(); } /// ------------------------------------------- @@ -357,12 +369,17 @@ export class MetaMask { * @experimental * @group Experimental Methods */ - async confirmTransactionAndWaitForMining(options?: { gasSetting?: GasSetting }) { + async confirmTransactionAndWaitForMining(options?: { + gasSetting?: GasSetting; + }) { if (!this.extensionId) { - throw NO_EXTENSION_ID_ERROR + throw NO_EXTENSION_ID_ERROR; } - await this.notificationPage.confirmTransactionAndWaitForMining(this.extensionId, options) + await this.notificationPage.confirmTransactionAndWaitForMining( + this.extensionId, + options + ); } /** @@ -374,7 +391,7 @@ export class MetaMask { * @group Experimental Methods */ async openTransactionDetails(txIndex: number) { - await this.homePage.openTransactionDetails(txIndex) + await this.homePage.openTransactionDetails(txIndex); } /** @@ -384,6 +401,6 @@ export class MetaMask { * @group Experimental Methods */ async closeTransactionDetails() { - await this.homePage.closeTransactionDetails() + await this.homePage.closeTransactionDetails(); } } diff --git a/wallets/metamask/src/pages/HomePage/actions/switchNetwork.ts b/wallets/metamask/src/pages/HomePage/actions/switchNetwork.ts index 5dfbfa529..619eaf67b 100644 --- a/wallets/metamask/src/pages/HomePage/actions/switchNetwork.ts +++ b/wallets/metamask/src/pages/HomePage/actions/switchNetwork.ts @@ -1,39 +1,50 @@ -import type { Page } from '@playwright/test' -import { allTextContents } from '../../../utils/allTextContents' -import Selectors from '../selectors' -import { closeRecoveryPhraseReminder } from './popups' +import type { Page } from "@playwright/test"; +import { allTextContents } from "../../../utils/allTextContents"; +import Selectors from "../selectors"; +import { closeRecoveryPhraseReminder } from "./popups"; async function openTestnetSection(page: Page) { - const toggleButtonLocator = page.locator(Selectors.networkDropdown.showTestNetworksToggle) - const classes = await toggleButtonLocator.getAttribute('class') - if (classes && classes.includes('toggle-button--off')) { - await toggleButtonLocator.click() - await page.locator(Selectors.networkDropdown.toggleOn).isChecked() + const toggleButtonLocator = page.locator( + Selectors.networkDropdown.showTestNetworksToggle + ); + const classes = await toggleButtonLocator.getAttribute("class"); + if (classes && classes.includes("toggle-button--off")) { + await toggleButtonLocator.click(); + await page.locator(Selectors.networkDropdown.toggleOn).isChecked(); } } -export async function switchNetwork(page: Page, networkName: string, includeTestNetworks: boolean) { - await page.locator(Selectors.networkDropdown.dropdownButton).click() +export async function switchNetwork( + page: Page, + networkName: string, + includeTestNetworks: boolean +) { + await page.locator(Selectors.networkDropdown.dropdownButton).click(); if (includeTestNetworks) { - await openTestnetSection(page) + await openTestnetSection(page); } - const networkLocators = await page.locator(Selectors.networkDropdown.networks).all() - const networkNames = await allTextContents(networkLocators) + const networkLocators = await page + .locator(Selectors.networkDropdown.networks) + .all(); + const networkNames = await allTextContents(networkLocators); const seekedNetworkNameIndex = networkNames.findIndex( (name) => name.toLocaleLowerCase() === networkName.toLocaleLowerCase() - ) + ); - const seekedNetworkLocator = seekedNetworkNameIndex >= 0 && networkLocators[seekedNetworkNameIndex] + const seekedNetworkLocator = + seekedNetworkNameIndex >= 0 && networkLocators[seekedNetworkNameIndex]; if (!seekedNetworkLocator) { - throw new Error(`[SwitchNetwork] Network with name ${networkName} not found`) + throw new Error( + `[SwitchNetwork] Network with name ${networkName} not found` + ); } - await seekedNetworkLocator.click() + await seekedNetworkLocator.click(); // TODO: This is not really needed if we do `metamask.toggleDismissSecretRecoveryPhraseReminder()` by default. Figure this out! - await closeRecoveryPhraseReminder(page) + await closeRecoveryPhraseReminder(page); } diff --git a/wallets/metamask/test/e2e/metamask/switchNetwork.spec.ts b/wallets/metamask/test/e2e/metamask/switchNetwork.spec.ts index 0ab2b36bd..e309df68e 100644 --- a/wallets/metamask/test/e2e/metamask/switchNetwork.spec.ts +++ b/wallets/metamask/test/e2e/metamask/switchNetwork.spec.ts @@ -1,39 +1,67 @@ -import { testWithSynpress } from '@synthetixio/synpress-fixtures' -import { MetaMask, unlockForFixture } from '../../../src' +import { testWithSynpress } from "@synthetixio/synpress-fixtures"; +import { MetaMask, unlockForFixture } from "../../../src"; -import basicSetup from '../wallet-setup/basic.setup' +import basicSetup from "../wallet-setup/basic.setup"; -const test = testWithSynpress(basicSetup, unlockForFixture) +const test = testWithSynpress(basicSetup, unlockForFixture); -const { expect } = test +const { expect } = test; -test('should switch network', async ({ context, metamaskPage }) => { - const metamask = new MetaMask(context, metamaskPage, basicSetup.walletPassword) +test("should switch network", async ({ context, metamaskPage }) => { + const metamask = new MetaMask( + context, + metamaskPage, + basicSetup.walletPassword + ); - await expect(metamaskPage.locator(metamask.homePage.selectors.currentNetwork)).toHaveText('Ethereum Mainnet') + await expect( + metamaskPage.locator(metamask.homePage.selectors.currentNetwork) + ).toHaveText("Ethereum Mainnet"); - const targetNetwork = 'Linea Mainnet' - await metamask.switchNetwork(targetNetwork) + const targetNetwork = "Linea Mainnet"; + await metamask.switchNetwork(targetNetwork); - await expect(metamaskPage.locator(metamask.homePage.selectors.currentNetwork)).toHaveText(targetNetwork) -}) + await expect( + metamaskPage.locator(metamask.homePage.selectors.currentNetwork) + ).toHaveText(targetNetwork); +}); -test('should switch network to a testnet', async ({ context, metamaskPage }) => { - const metamask = new MetaMask(context, metamaskPage, basicSetup.walletPassword) +test("should switch network to a testnet", async ({ + context, + metamaskPage, +}) => { + const metamask = new MetaMask( + context, + metamaskPage, + basicSetup.walletPassword + ); - await expect(metamaskPage.locator(metamask.homePage.selectors.currentNetwork)).toHaveText('Ethereum Mainnet') + await expect( + metamaskPage.locator(metamask.homePage.selectors.currentNetwork) + ).toHaveText("Ethereum Mainnet"); - const targetNetwork = 'Sepolia' - await metamask.switchNetwork(targetNetwork, true) + const targetNetwork = "Sepolia"; + await metamask.switchNetwork(targetNetwork, true); - await expect(metamaskPage.locator(metamask.homePage.selectors.currentNetwork)).toHaveText(targetNetwork) -}) + await expect( + metamaskPage.locator(metamask.homePage.selectors.currentNetwork) + ).toHaveText(targetNetwork); +}); -test('should throw an error if there is no account with target name', async ({ context, metamaskPage }) => { - const metamask = new MetaMask(context, metamaskPage, basicSetup.walletPassword) +test("should throw an error if there is no account with target name", async ({ + context, + metamaskPage, +}) => { + const metamask = new MetaMask( + context, + metamaskPage, + basicSetup.walletPassword + ); - const accountName = 'Account 420' - const switchAccountPromise = metamask.switchAccount(accountName) + const accountName = "Account 420"; + const switchAccountPromise = metamask.switchAccount(accountName); - await expect(switchAccountPromise).rejects.toThrowError(`[SwitchAccount] Account with name ${accountName} not found`) -}) + await expect(switchAccountPromise).rejects.toThrowError( + `[SwitchAccount] Account with name ${accountName} not found` + ); +});