From af123ce32aefbdcde47432b23171dd0c52940e00 Mon Sep 17 00:00:00 2001 From: matstyler Date: Thu, 18 Apr 2024 20:38:29 +0200 Subject: [PATCH 1/4] :art:feat: ethereum-wallet-mock package --- examples/new-dawn/test/e2e/00_mock.spec.ts | 45 ++-- pnpm-lock.yaml | 46 ++-- release/package.json | 4 +- release/src/index.ts | 26 ++- .../environment.d.ts | 0 .../package.json | 2 +- .../playwright.config.ts | 0 .../src/ethereum-wallet-mock.ts | 220 ++++++++++++++++++ wallets/ethereum-wallet-mock/src/index.ts | 3 + .../src/network/Network.ts | 0 .../src/testWithEthereumWalletMock.ts | 66 ++++++ .../src/utils/constants.ts | 14 ++ .../ethereum-wallet-mock/src/utils/index.ts | 2 + .../src/utils/mockEthereum.ts | 17 ++ .../test/e2e/metamask/addNewAccount.spec.ts | 19 ++ .../importWalletFromPrivateKey.spec.ts | 19 ++ .../e2e/metamask/mock/mockEthereum.spec.ts | 45 ++++ .../test/e2e/metamask/switchAccount.spec.ts | 12 + .../test/e2e/metamask/switchNetwork.spec.ts | 23 ++ .../tsconfig.build.json | 0 .../tsconfig.json | 0 .../tsup.config.ts | 2 +- .../vitest.config.ts | 0 wallets/metamask-mock/src/index.ts | 3 - wallets/metamask-mock/src/metamask-mock.ts | 189 --------------- .../metamask-mock/src/testWithMetaMaskMock.ts | 59 ----- wallets/metamask-mock/src/utils/index.ts | 1 - .../metamask-mock/src/utils/mockEthereum.ts | 9 - .../test/e2e/metamask/addNewAccount.spec.ts | 18 -- .../importWalletFromPrivateKey.spec.ts | 12 - .../e2e/metamask/mock/mockEthereum.spec.ts | 25 -- .../test/e2e/metamask/switchAccount.spec.ts | 12 - .../test/e2e/metamask/switchNetwork.spec.ts | 19 -- 33 files changed, 515 insertions(+), 397 deletions(-) rename wallets/{metamask-mock => ethereum-wallet-mock}/environment.d.ts (100%) rename wallets/{metamask-mock => ethereum-wallet-mock}/package.json (95%) rename wallets/{metamask-mock => ethereum-wallet-mock}/playwright.config.ts (100%) create mode 100644 wallets/ethereum-wallet-mock/src/ethereum-wallet-mock.ts create mode 100644 wallets/ethereum-wallet-mock/src/index.ts rename wallets/{metamask-mock => ethereum-wallet-mock}/src/network/Network.ts (100%) create mode 100644 wallets/ethereum-wallet-mock/src/testWithEthereumWalletMock.ts create mode 100644 wallets/ethereum-wallet-mock/src/utils/constants.ts create mode 100644 wallets/ethereum-wallet-mock/src/utils/index.ts create mode 100644 wallets/ethereum-wallet-mock/src/utils/mockEthereum.ts create mode 100644 wallets/ethereum-wallet-mock/test/e2e/metamask/addNewAccount.spec.ts create mode 100644 wallets/ethereum-wallet-mock/test/e2e/metamask/importWalletFromPrivateKey.spec.ts create mode 100644 wallets/ethereum-wallet-mock/test/e2e/metamask/mock/mockEthereum.spec.ts create mode 100644 wallets/ethereum-wallet-mock/test/e2e/metamask/switchAccount.spec.ts create mode 100644 wallets/ethereum-wallet-mock/test/e2e/metamask/switchNetwork.spec.ts rename wallets/{metamask-mock => ethereum-wallet-mock}/tsconfig.build.json (100%) rename wallets/{metamask-mock => ethereum-wallet-mock}/tsconfig.json (100%) rename wallets/{metamask-mock => ethereum-wallet-mock}/tsup.config.ts (87%) rename wallets/{metamask-mock => ethereum-wallet-mock}/vitest.config.ts (100%) delete mode 100644 wallets/metamask-mock/src/index.ts delete mode 100644 wallets/metamask-mock/src/metamask-mock.ts delete mode 100644 wallets/metamask-mock/src/testWithMetaMaskMock.ts delete mode 100644 wallets/metamask-mock/src/utils/index.ts delete mode 100644 wallets/metamask-mock/src/utils/mockEthereum.ts delete mode 100644 wallets/metamask-mock/test/e2e/metamask/addNewAccount.spec.ts delete mode 100644 wallets/metamask-mock/test/e2e/metamask/importWalletFromPrivateKey.spec.ts delete mode 100644 wallets/metamask-mock/test/e2e/metamask/mock/mockEthereum.spec.ts delete mode 100644 wallets/metamask-mock/test/e2e/metamask/switchAccount.spec.ts delete mode 100644 wallets/metamask-mock/test/e2e/metamask/switchNetwork.spec.ts diff --git a/examples/new-dawn/test/e2e/00_mock.spec.ts b/examples/new-dawn/test/e2e/00_mock.spec.ts index ebcbf11fa..b23e8fa31 100644 --- a/examples/new-dawn/test/e2e/00_mock.spec.ts +++ b/examples/new-dawn/test/e2e/00_mock.spec.ts @@ -1,23 +1,38 @@ -import { MetaMaskMock, testWithMetaMaskMock } from '@synthetixio/synpress' +import { + EthereumWalletMock, + testWithEthereumWalletMock, +} from "@synthetixio/synpress"; -const test = testWithMetaMaskMock +const test = testWithEthereumWalletMock; -const { expect } = test +const { expect } = test; -test('should mock MetaMask in the Test Dapp', async ({ page }) => { - await page.goto('/') +test("should mock MetaMask in the Test Dapp", async ({ page, walletMock }) => { + expect(await walletMock.getAllAccounts()).toHaveLength(1); - await expect(page.locator('#accounts')).toHaveText('0xd73b04b0e696b0945283defa3eee453814758f1a') + await page.locator("#connectButton").click(); - await page.locator('#getAccounts').click() - await expect(page.locator('#getAccountsResult')).toHaveText('0xd73b04b0e696b0945283defa3eee453814758f1a') -}) + await expect(page.locator("#accounts")).toHaveText( + "0xd73b04b0e696b0945283defa3eee453814758f1a" + ); -test('should add new account using MetaMask mock', async ({ page }) => { - const metamask = new MetaMaskMock(page) + await page.locator("#getAccounts").click(); + await expect(page.locator("#getAccountsResult")).toHaveText( + "0xd73b04b0e696b0945283defa3eee453814758f1a" + ); +}); - metamask.importWallet('candy maple cake sugar pudding cream honey rich smooth crumble sweet treat') - await metamask.addNewAccount() +test("should add new account using MetaMask mock", async ({ page }) => { + const walletMock = new EthereumWalletMock(page); - await expect(page.locator('#accounts')).toHaveText('0xd73b04b0e696b0945283defa3eee453814758f1a') -}) + await walletMock.importWallet( + "candy maple cake sugar pudding cream honey rich smooth crumble sweet treat" + ); + await walletMock.addNewAccount(); + + await page.locator("#connectButton").click(); + + await expect(page.locator("#accounts")).toHaveText( + "0x6503D95e3F20389EE9496b277ABfFDb8eCCD2cc5,0xd73b04b0e696b0945283defa3eee453814758f1a" + ); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 711978ab3..010ad8f50 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -211,6 +211,9 @@ importers: '@playwright/test': specifier: 1.41.2 version: 1.41.2 + '@synthetixio/ethereum-wallet-mock': + specifier: 0.0.1-alpha.3 + version: link:../wallets/ethereum-wallet-mock '@synthetixio/synpress-core': specifier: 0.0.1-alpha.3 version: link:../packages/core @@ -220,9 +223,6 @@ importers: '@synthetixio/synpress-metamask': specifier: 0.0.1-alpha.3 version: link:../wallets/metamask - '@synthetixio/synpress-metamask-mock': - specifier: 0.0.1-alpha.3 - version: link:../wallets/metamask-mock devDependencies: '@synthetixio/synpress-tsconfig': specifier: 0.0.1-alpha.3 @@ -240,20 +240,17 @@ importers: specifier: 5.3.3 version: 5.3.3 - wallets/metamask: + wallets/ethereum-wallet-mock: dependencies: + '@depay/web3-mock': + specifier: 14.17.0 + version: 14.17.0 '@playwright/test': specifier: 1.41.2 version: 1.41.2 - '@synthetixio/synpress-core': - specifier: 0.0.1-alpha.3 - version: link:../../packages/core - '@synthetixio/synpress-fixtures': - specifier: 0.0.1-alpha.3 - version: link:../../packages/fixtures - zod: - specifier: 3.22.4 - version: 3.22.4 + viem: + specifier: 2.9.9 + version: 2.9.9(typescript@5.3.3) devDependencies: '@synthetixio/synpress-tsconfig': specifier: 0.0.1-alpha.3 @@ -273,21 +270,21 @@ importers: typescript: specifier: 5.3.3 version: 5.3.3 - vitest: - specifier: 1.2.2 - version: 1.2.2(@types/node@20.11.17) - wallets/metamask-mock: + wallets/metamask: dependencies: - '@depay/web3-mock': - specifier: 14.17.0 - version: 14.17.0 '@playwright/test': specifier: 1.41.2 version: 1.41.2 - viem: - specifier: 2.9.9 - version: 2.9.9(typescript@5.3.3) + '@synthetixio/synpress-core': + specifier: 0.0.1-alpha.3 + version: link:../../packages/core + '@synthetixio/synpress-fixtures': + specifier: 0.0.1-alpha.3 + version: link:../../packages/fixtures + zod: + specifier: 3.22.4 + version: 3.22.4 devDependencies: '@synthetixio/synpress-tsconfig': specifier: 0.0.1-alpha.3 @@ -307,6 +304,9 @@ importers: typescript: specifier: 5.3.3 version: 5.3.3 + vitest: + specifier: 1.2.2 + version: 1.2.2(@types/node@20.11.17) packages: diff --git a/release/package.json b/release/package.json index 37240e689..0a3902bde 100644 --- a/release/package.json +++ b/release/package.json @@ -26,10 +26,10 @@ "types:check": "tsc --noEmit" }, "dependencies": { + "@synthetixio/ethereum-wallet-mock": "0.0.1-alpha.3", "@synthetixio/synpress-core": "0.0.1-alpha.3", "@synthetixio/synpress-fixtures": "0.0.1-alpha.3", - "@synthetixio/synpress-metamask": "0.0.1-alpha.3", - "@synthetixio/synpress-metamask-mock": "0.0.1-alpha.3" + "@synthetixio/synpress-metamask": "0.0.1-alpha.3" }, "devDependencies": { "@synthetixio/synpress-tsconfig": "0.0.1-alpha.3", diff --git a/release/src/index.ts b/release/src/index.ts index 75bd9686d..362c788d1 100644 --- a/release/src/index.ts +++ b/release/src/index.ts @@ -1,18 +1,28 @@ -import { defineWalletSetup } from '@synthetixio/synpress-core' -import { getExtensionId, testWithSynpress } from '@synthetixio/synpress-fixtures' -import { MetaMask, homePageSelectors, unlockForFixture } from '@synthetixio/synpress-metamask' -import { MetaMaskMock, testWithMetaMaskMock } from '@synthetixio/synpress-metamask-mock' +import { defineWalletSetup } from "@synthetixio/synpress-core"; +import { + getExtensionId, + testWithSynpress, +} from "@synthetixio/synpress-fixtures"; +import { + MetaMask, + homePageSelectors, + unlockForFixture, +} from "@synthetixio/synpress-metamask"; +import { + EthereumWalletMock, + testWithEthereumWalletMock, +} from "@synthetixio/ethereum-wallet-mock"; export { // Framework fixtures testWithSynpress, - testWithMetaMaskMock, + testWithEthereumWalletMock, // API MetaMask, - MetaMaskMock, + EthereumWalletMock, // Helpers defineWalletSetup, getExtensionId, unlockForFixture, - homePageSelectors -} + homePageSelectors, +}; diff --git a/wallets/metamask-mock/environment.d.ts b/wallets/ethereum-wallet-mock/environment.d.ts similarity index 100% rename from wallets/metamask-mock/environment.d.ts rename to wallets/ethereum-wallet-mock/environment.d.ts diff --git a/wallets/metamask-mock/package.json b/wallets/ethereum-wallet-mock/package.json similarity index 95% rename from wallets/metamask-mock/package.json rename to wallets/ethereum-wallet-mock/package.json index 12baa8293..79dfa6411 100644 --- a/wallets/metamask-mock/package.json +++ b/wallets/ethereum-wallet-mock/package.json @@ -1,5 +1,5 @@ { - "name": "@synthetixio/synpress-metamask-mock", + "name": "@synthetixio/ethereum-wallet-mock", "version": "0.0.1-alpha.3", "type": "module", "exports": { diff --git a/wallets/metamask-mock/playwright.config.ts b/wallets/ethereum-wallet-mock/playwright.config.ts similarity index 100% rename from wallets/metamask-mock/playwright.config.ts rename to wallets/ethereum-wallet-mock/playwright.config.ts diff --git a/wallets/ethereum-wallet-mock/src/ethereum-wallet-mock.ts b/wallets/ethereum-wallet-mock/src/ethereum-wallet-mock.ts new file mode 100644 index 000000000..0aec066f0 --- /dev/null +++ b/wallets/ethereum-wallet-mock/src/ethereum-wallet-mock.ts @@ -0,0 +1,220 @@ +import type { Page } from "@playwright/test"; +import { mnemonicToAccount, privateKeyToAccount } from "viem/accounts"; +import type { Network } from "./network/Network"; +import { ACCOUNT_MOCK, BLOCKCHAIN, BSC_NETWORK_ID } from "./utils"; + +export type WalletMock = + | "metamask" + | "coinbase" + | "phantom" + | "walletconnect" + | "walletlink"; + +/** + * This class is the heart of Synpress's MetaMask API. + */ +export class EthereumWalletMock { + seedPhrase = ""; + wallet: WalletMock = "metamask"; + + constructor( + /** + * The MetaMask tab page. + */ + readonly page: Page + ) { + this.page = page; + } + + /** + * Imports a wallet using the given seed phrase. + * + * @param seedPhrase - The seed phrase to import. + */ + importWallet(seedPhrase: string) { + this.seedPhrase = seedPhrase; + + return this.page.evaluate( + ([blockchain, wallet, accounts]) => { + return Web3Mock.mock({ + blockchain, + wallet, + accounts: { + return: accounts, + }, + }); + }, + [BLOCKCHAIN, this.wallet, [ACCOUNT_MOCK]] + ); + } + + /** + * Retrieves the current account address. + */ + async getAllAccounts(): Promise { + return this.page.evaluate(() => { + return window.ethereum.request({ method: "eth_requestAccounts" }); + }); + } + + /** + * Adds a new account. This account is based on the initially imported seed phrase. + */ + async addNewAccount() { + const accounts = await this.getAllAccounts(); + + const newAccount = mnemonicToAccount(this.seedPhrase, { + accountIndex: accounts.length, + }); + + return this.page.evaluate( + ([blockchain, wallet, accounts]) => { + return Web3Mock.mock({ + blockchain, + wallet, + accounts: { + return: accounts, + }, + }); + }, + [BLOCKCHAIN, this.wallet, [newAccount.address, ...accounts]] + ); + } + + /** + * Imports a wallet using the given private key. + * + * @param privateKey - The private key to import. + */ + async importWalletFromPrivateKey(privateKey: `0x${string}`) { + const newAccount = privateKeyToAccount(privateKey); + + return this.page.evaluate( + ([blockchain, wallet, account]) => { + return Web3Mock.mock({ + blockchain, + wallet, + accounts: { + return: account, + }, + }); + }, + [BLOCKCHAIN, this.wallet, [newAccount.address]] + ); + } + + /** + * Switches to the account with the given name. + * + * @param accountAddress - The name of the account to switch to. + */ + async switchAccount(accountAddress: string) { + return this.page.evaluate( + ([blockchain, wallet, accountAddress]) => { + return Web3Mock.mock({ + blockchain, + wallet, + accounts: { + return: [accountAddress], + }, + }); + }, + [BLOCKCHAIN, this.wallet, accountAddress] + ); + } + + /** + * Adds a new network. + * + * @param network - The network object to use for adding the new network. + * @param network.name - The name of the network. + * @param network.rpcUrl - The RPC URL of the network. + * @param network.chainId - The chain ID of the network. + * @param network.symbol - The currency symbol of the network. + * @param network.blockExplorerUrl - The block explorer URL of the network. + */ + async addNetwork(network: Network) { + const networkInfo = { + chainId: network.chainId, + chainName: network.name, + nativeCurrency: network.nativeCurrency, + rpcUrls: [network.rpcUrl], + blockExplorerUrls: [network.blockExplorerUrl], + }; + + return this.page.evaluate( + ([blockchain, wallet, networkInfo]) => { + return Web3Mock.mock({ + blockchain, + wallet, + network: { + add: networkInfo, + }, + }); + }, + [BLOCKCHAIN, this.wallet, networkInfo] + ); + } + + /** + * Retrieves the current account address. + */ + async getAccountAddress() { + return (await this.getAllAccounts())[0]; + } + + /** + * Switches to the network with the given name. + * + * @param networkName - The name of the network to switch to. + */ + async switchNetwork(networkName: string) { + return this.page.evaluate( + ([blockchain, wallet, networkName, chainId]) => { + Web3Mock.mock({ + blockchain, + wallet, + network: { + switchTo: networkName, + }, + }); + + window.ethereum.request({ + method: "wallet_switchEthereumChain", + // Mock do not support custom network IDs + params: [{ chainId }], + }); + }, + [BLOCKCHAIN, this.wallet, networkName, BSC_NETWORK_ID] + ); + } + + /** + * Connects wallet to the dapp. + */ + async connectToDapp(wallet: WalletMock = "metamask") { + this.wallet = wallet; + return this.page.evaluate( + ([blockchain, accounts, wallet]) => { + // Cannot pass custom class as an argument to `page.evaluate` + class WalletConnectStub {} + + let connector: WalletConnectStub | undefined; + + if (wallet === "walletconnect") { + connector = WalletConnectStub; + } + + return Web3Mock.mock({ + blockchain, + wallet, + accounts: { + return: accounts, + }, + connector, + }); + }, + [BLOCKCHAIN, [ACCOUNT_MOCK], wallet] + ); + } +} diff --git a/wallets/ethereum-wallet-mock/src/index.ts b/wallets/ethereum-wallet-mock/src/index.ts new file mode 100644 index 000000000..68111873d --- /dev/null +++ b/wallets/ethereum-wallet-mock/src/index.ts @@ -0,0 +1,3 @@ +export * from "./ethereum-wallet-mock"; +export * from "./utils"; +export * from "./testWithEthereumWalletMock"; diff --git a/wallets/metamask-mock/src/network/Network.ts b/wallets/ethereum-wallet-mock/src/network/Network.ts similarity index 100% rename from wallets/metamask-mock/src/network/Network.ts rename to wallets/ethereum-wallet-mock/src/network/Network.ts diff --git a/wallets/ethereum-wallet-mock/src/testWithEthereumWalletMock.ts b/wallets/ethereum-wallet-mock/src/testWithEthereumWalletMock.ts new file mode 100644 index 000000000..40353cdd5 --- /dev/null +++ b/wallets/ethereum-wallet-mock/src/testWithEthereumWalletMock.ts @@ -0,0 +1,66 @@ +import { readFileSync } from "fs"; +import { createRequire } from "node:module"; +import { test as base } from "@playwright/test"; +import { EthereumWalletMock } from "./ethereum-wallet-mock"; +import type { Network } from "./network/Network"; +import { + ANVIL_CHAIN_ID, + ANVIL_URL_URL, + mockEthereum, + SEED_PHRASE, +} from "./utils"; + +const require = createRequire(import.meta.url); +// Relative path to the web3-mock bundle +const web3MockPath = require.resolve( + "@depay/web3-mock/dist/umd/index.bundle.js" +); + +export const testWithEthereumWalletMock = base.extend<{ + walletMock: EthereumWalletMock; + createAnvilNetwork: () => Network; + deployToken: () => Promise; +}>({ + context: async ({ context }, use) => { + // Dependency and mock function has to be added at the same time - https://playwright.dev/docs/api/class-browsercontext#browser-context-add-init-script + await context.addInitScript({ + content: `${readFileSync( + web3MockPath, + "utf-8" + )}\n(${mockEthereum.toString()})();`, + }); + + await use(context); + + await context.close(); + }, + page: async ({ context }, use) => { + const page = await context.newPage(); + + await page.goto("/"); + + await use(page); + }, + walletMock: async ({ page }, use) => { + const walletMock = new EthereumWalletMock(page); + + await walletMock.importWallet(SEED_PHRASE); + + await use(walletMock); + }, + createAnvilNetwork: async ({ context: _ }, use) => { + await use(() => { + return { + name: "Anvil", + rpcUrl: ANVIL_URL_URL, + chainId: ANVIL_CHAIN_ID, + blockExplorerUrl: "https://etherscan.io/", + nativeCurrency: { + decimals: 18, + name: "Anvil", + symbol: "ETH", + }, + }; + }); + }, +}); diff --git a/wallets/ethereum-wallet-mock/src/utils/constants.ts b/wallets/ethereum-wallet-mock/src/utils/constants.ts new file mode 100644 index 000000000..ea146e1a1 --- /dev/null +++ b/wallets/ethereum-wallet-mock/src/utils/constants.ts @@ -0,0 +1,14 @@ +export const BLOCKCHAIN = "ethereum"; + +export const ACCOUNT_MOCK = "0xd73b04b0e696b0945283defa3eee453814758f1a"; + +export const SEED_PHRASE = + "test test test test test test test test test test test junk"; + +export const PRIVATE_KEY = + "ea084c575a01e2bbefcca3db101eaeab1d8af15554640a510c73692db24d0a6a"; + +export const ANVIL_CHAIN_ID = 31337; +export const ANVIL_URL_URL = "http://anvil:5000"; + +export const BSC_NETWORK_ID = "0x38"; diff --git a/wallets/ethereum-wallet-mock/src/utils/index.ts b/wallets/ethereum-wallet-mock/src/utils/index.ts new file mode 100644 index 000000000..bed844583 --- /dev/null +++ b/wallets/ethereum-wallet-mock/src/utils/index.ts @@ -0,0 +1,2 @@ +export { default as mockEthereum } from "./mockEthereum"; +export * from "./constants"; diff --git a/wallets/ethereum-wallet-mock/src/utils/mockEthereum.ts b/wallets/ethereum-wallet-mock/src/utils/mockEthereum.ts new file mode 100644 index 000000000..b9b7e5227 --- /dev/null +++ b/wallets/ethereum-wallet-mock/src/utils/mockEthereum.ts @@ -0,0 +1,17 @@ +export default function mockEthereum( + wallet: + | "metamask" + | "coinbase" + | "phantom" + | "walletconnect" + | "walletlink" = "metamask", + accounts: `0x${string}`[] = [] +) { + Web3Mock.mock({ + blockchain: "ethereum", + wallet, + accounts: { + return: accounts, + }, + }); +} diff --git a/wallets/ethereum-wallet-mock/test/e2e/metamask/addNewAccount.spec.ts b/wallets/ethereum-wallet-mock/test/e2e/metamask/addNewAccount.spec.ts new file mode 100644 index 000000000..09ba8ea9c --- /dev/null +++ b/wallets/ethereum-wallet-mock/test/e2e/metamask/addNewAccount.spec.ts @@ -0,0 +1,19 @@ +import { testWithEthereumWalletMock } from "../../../src"; + +const test = testWithEthereumWalletMock; + +const { expect } = test; + +test("should add a new account with specified name", async ({ walletMock }) => { + // Imported wallet includes 1 account + expect(await walletMock.getAllAccounts()).toHaveLength(1); + + await walletMock.addNewAccount(); + + expect(await walletMock.getAllAccounts()).toHaveLength(2); + + await walletMock.addNewAccount(); + await walletMock.addNewAccount(); + + expect(await walletMock.getAllAccounts()).toHaveLength(4); +}); diff --git a/wallets/ethereum-wallet-mock/test/e2e/metamask/importWalletFromPrivateKey.spec.ts b/wallets/ethereum-wallet-mock/test/e2e/metamask/importWalletFromPrivateKey.spec.ts new file mode 100644 index 000000000..7fc8eddee --- /dev/null +++ b/wallets/ethereum-wallet-mock/test/e2e/metamask/importWalletFromPrivateKey.spec.ts @@ -0,0 +1,19 @@ +import { testWithEthereumWalletMock } from "../../../src"; + +const test = testWithEthereumWalletMock; + +const { expect } = test; + +test("should import account using private key", async ({ + page, + walletMock, +}) => { + await walletMock.importWalletFromPrivateKey( + "0xea084c575a01e2bbefcca3db101eaeab1d8af15554640a510c73692db24d0a6a" + ); + + await page.locator("#getAccounts").click(); + await expect(page.locator("#getAccountsResult")).toHaveText( + "0xa2ce797cA71d0EaE1be5a7EffD27Fd6C38126801" + ); +}); diff --git a/wallets/ethereum-wallet-mock/test/e2e/metamask/mock/mockEthereum.spec.ts b/wallets/ethereum-wallet-mock/test/e2e/metamask/mock/mockEthereum.spec.ts new file mode 100644 index 000000000..fa2834826 --- /dev/null +++ b/wallets/ethereum-wallet-mock/test/e2e/metamask/mock/mockEthereum.spec.ts @@ -0,0 +1,45 @@ +import { testWithEthereumWalletMock } from "../../../../src"; + +const test = testWithEthereumWalletMock; + +const { expect } = test; + +test("should be able to access ethereum API", async ({ page }) => { + const ethereum = await page.evaluate(() => window.ethereum); + expect(ethereum).toBeTruthy(); +}); + +test("should be connected to metamask by default", async ({ page }) => { + const ethereum = await page.evaluate(() => window.ethereum); + expect(ethereum.isMetaMask).toBe(true); +}); + +test("should connect to ethereum", async ({ page }) => { + const currentChainId = await page.evaluate(() => + window.ethereum.request({ + method: "eth_chainId", + }) + ); + + expect(currentChainId).toEqual("0x1"); +}); + +test("should be able to connect to every supported ethereum wallet", async ({ + page, + walletMock, +}) => { + // Metamask + let ethereum = await page.evaluate(() => window.ethereum); + expect(ethereum.isMetaMask).toBe(true); + expect(ethereum.isCoinbaseWallet).toBe(undefined); + + // Coinbase wallet + await walletMock.connectToDapp("coinbase"); + ethereum = await page.evaluate(() => window.ethereum); + expect(ethereum.isCoinbaseWallet).toBe(true); + + // Walletconnect + await walletMock.connectToDapp("walletconnect"); + ethereum = await page.evaluate(() => window.ethereum); + expect(ethereum.isWalletLink).toBe(true); +}); diff --git a/wallets/ethereum-wallet-mock/test/e2e/metamask/switchAccount.spec.ts b/wallets/ethereum-wallet-mock/test/e2e/metamask/switchAccount.spec.ts new file mode 100644 index 000000000..c09f541e8 --- /dev/null +++ b/wallets/ethereum-wallet-mock/test/e2e/metamask/switchAccount.spec.ts @@ -0,0 +1,12 @@ +import { testWithEthereumWalletMock } from '../../../src' + +const test = testWithEthereumWalletMock + +const { expect } = test + +test('should switch account', async ({ page, walletMock }) => { + await walletMock.switchAccount('0x4444797cA71d0EaE1be5a7EffD27Fd6C38126801') + + await page.locator('#getAccounts').click() + await expect(page.locator('#getAccountsResult')).toHaveText('0x4444797cA71d0EaE1be5a7EffD27Fd6C38126801') +}) diff --git a/wallets/ethereum-wallet-mock/test/e2e/metamask/switchNetwork.spec.ts b/wallets/ethereum-wallet-mock/test/e2e/metamask/switchNetwork.spec.ts new file mode 100644 index 000000000..5dc844cbb --- /dev/null +++ b/wallets/ethereum-wallet-mock/test/e2e/metamask/switchNetwork.spec.ts @@ -0,0 +1,23 @@ +import { testWithEthereumWalletMock } from "../../../src"; + +const test = testWithEthereumWalletMock; + +const { expect } = test; + +test("should switch network", async ({ + createAnvilNetwork, + walletMock, + page, +}) => { + const network = createAnvilNetwork(); + + await walletMock.addNetwork(network); + + await walletMock.switchNetwork(network.name); + + const chainId = await page.evaluate(async () => { + return await window.ethereum.request({ method: "eth_chainId" }); + }); + + expect(chainId).toBe("0x38"); +}); diff --git a/wallets/metamask-mock/tsconfig.build.json b/wallets/ethereum-wallet-mock/tsconfig.build.json similarity index 100% rename from wallets/metamask-mock/tsconfig.build.json rename to wallets/ethereum-wallet-mock/tsconfig.build.json diff --git a/wallets/metamask-mock/tsconfig.json b/wallets/ethereum-wallet-mock/tsconfig.json similarity index 100% rename from wallets/metamask-mock/tsconfig.json rename to wallets/ethereum-wallet-mock/tsconfig.json diff --git a/wallets/metamask-mock/tsup.config.ts b/wallets/ethereum-wallet-mock/tsup.config.ts similarity index 87% rename from wallets/metamask-mock/tsup.config.ts rename to wallets/ethereum-wallet-mock/tsup.config.ts index 63ed05775..a7e4c2978 100644 --- a/wallets/metamask-mock/tsup.config.ts +++ b/wallets/ethereum-wallet-mock/tsup.config.ts @@ -1,7 +1,7 @@ import { defineConfig } from 'tsup' export default defineConfig({ - name: 'metamask', + name: 'ethereum-wallet-mock', entry: ['src/index.ts'], outDir: 'dist', format: 'esm', diff --git a/wallets/metamask-mock/vitest.config.ts b/wallets/ethereum-wallet-mock/vitest.config.ts similarity index 100% rename from wallets/metamask-mock/vitest.config.ts rename to wallets/ethereum-wallet-mock/vitest.config.ts diff --git a/wallets/metamask-mock/src/index.ts b/wallets/metamask-mock/src/index.ts deleted file mode 100644 index 94d5183c1..000000000 --- a/wallets/metamask-mock/src/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './metamask-mock' -export * from './utils' -export * from './testWithMetaMaskMock' diff --git a/wallets/metamask-mock/src/metamask-mock.ts b/wallets/metamask-mock/src/metamask-mock.ts deleted file mode 100644 index 798277a1c..000000000 --- a/wallets/metamask-mock/src/metamask-mock.ts +++ /dev/null @@ -1,189 +0,0 @@ -// @ts-ignore -import { connect } from '@depay/web3-mock' -import type { Page } from '@playwright/test' -import { mnemonicToAccount, privateKeyToAccount } from 'viem/accounts' -import type { Network } from './network/Network' - -export const blockchain = 'ethereum' -export const wallet = 'metamask' - -const networkConfig = { - blockchain, - wallet -} - -const BSC_NETWORK_ID = '0x38' - -export const SEED_PHRASE = 'test test test test test test test test test test test junk' - -export const PRIVATE_KEY = 'ea084c575a01e2bbefcca3db101eaeab1d8af15554640a510c73692db24d0a6a' - -/** - * This class is the heart of Synpress's MetaMask API. - */ -export class MetaMaskMock { - seedPhrase = '' - - constructor( - /** - * The MetaMask tab page. - */ - readonly page: Page - ) { - this.page = page - } - - /** - * Imports a wallet using the given seed phrase. - * - * @param seedPhrase - The seed phrase to import. - */ - importWallet(seedPhrase: string) { - this.seedPhrase = seedPhrase - } - - /** - * Retrieves the current account address. - */ - async getAllAccounts(): Promise { - return this.page.evaluate(() => { - return window.ethereum.request({ method: 'eth_requestAccounts' }) - }) - } - - /** - * Adds a new account. This account is based on the initially imported seed phrase. - */ - async addNewAccount() { - const accounts = await this.getAllAccounts() - - const newAccount = mnemonicToAccount(this.seedPhrase, { - accountIndex: accounts.length - }) - - return this.page.evaluate( - ([networkConfig, accounts]) => { - return Web3Mock.mock({ - ...networkConfig, - accounts: { - return: accounts - } - }) - }, - [networkConfig, [newAccount.address, ...accounts]] - ) - } - - /** - * Imports a wallet using the given private key. - * - * @param privateKey - The private key to import. - */ - async importWalletFromPrivateKey(privateKey: `0x${string}`) { - const newAccount = privateKeyToAccount(privateKey) - - return this.page.evaluate( - ([networkConfig, account]) => { - return Web3Mock.mock({ - ...networkConfig, - accounts: { - return: account - } - }) - }, - [networkConfig, [newAccount.address]] - ) - } - - /** - * Switches to the account with the given name. - * - * @param accountAddress - The name of the account to switch to. - */ - async switchAccount(accountAddress: string) { - return this.page.evaluate( - ([networkConfig, accountAddress]) => { - return Web3Mock.mock({ - // @ts-ignore - ...networkConfig, - accounts: { - return: [accountAddress] - } - }) - }, - [networkConfig, accountAddress] - ) - } - - /** - * Adds a new network. - * - * @param network - The network object to use for adding the new network. - * @param network.name - The name of the network. - * @param network.rpcUrl - The RPC URL of the network. - * @param network.chainId - The chain ID of the network. - * @param network.symbol - The currency symbol of the network. - * @param network.blockExplorerUrl - The block explorer URL of the network. - */ - async addNetwork(network: Network) { - const networkInfo = { - chainId: network.chainId, - chainName: network.name, - nativeCurrency: network.nativeCurrency, - rpcUrls: [network.rpcUrl], - blockExplorerUrls: [network.blockExplorerUrl] - } - - return this.page.evaluate( - ([networkConfig, networkInfo]) => { - return Web3Mock.mock({ - ...networkConfig, - network: { - add: networkInfo - } - }) - }, - [networkConfig, networkInfo] - ) - } - - /** - * Retrieves the current account address. - */ - async getAccountAddress() { - return (await this.getAllAccounts())[0] - } - - /** - * Switches to the network with the given name. - * - * @param networkName - The name of the network to switch to. - */ - async switchNetwork(networkName: string) { - return this.page.evaluate( - ([networkConfig, networkName, chainId]) => { - Web3Mock.mock({ - // @ts-ignore - ...networkConfig, - network: { - switchTo: networkName - } - }) - - window.ethereum.request({ - method: 'wallet_switchEthereumChain', - // Mock do not support custom network IDs - params: [{ chainId }] - }) - }, - [networkConfig, networkName, BSC_NETWORK_ID] - ) - } - - /** - * Connects to the dapp using the currently selected account. - */ - async connectToDapp(network: string) { - connect(network) - } -} diff --git a/wallets/metamask-mock/src/testWithMetaMaskMock.ts b/wallets/metamask-mock/src/testWithMetaMaskMock.ts deleted file mode 100644 index f6bd28f93..000000000 --- a/wallets/metamask-mock/src/testWithMetaMaskMock.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { readFileSync } from 'fs' -import { createRequire } from 'node:module' -import { test as base } from '@playwright/test' -import { MetaMaskMock, SEED_PHRASE } from './metamask-mock' -import type { Network } from './network/Network' -import { mockEthereum } from './utils' - -const ANVIL_CHAIN_ID = 31337 -const ANVIL_URL_URL = 'http://anvil:5000' - -const require = createRequire(import.meta.url) -// Relative path to the web3-mock bundle -const web3MockPath = require.resolve('@depay/web3-mock/dist/umd/index.bundle.js') - -export const testWithMetaMaskMock = base.extend<{ - metamask: MetaMaskMock - createAnvilNetwork: () => Network - deployToken: () => Promise -}>({ - context: async ({ context }, use) => { - // Dependency and mock function has to be added at the same time - https://playwright.dev/docs/api/class-browsercontext#browser-context-add-init-script - await context.addInitScript({ - content: `${readFileSync(web3MockPath, 'utf-8')}\n(${mockEthereum.toString()})();` - }) - - await use(context) - - await context.close() - }, - page: async ({ context }, use) => { - const page = await context.newPage() - - await page.goto('/') - - await use(page) - }, - metamask: async ({ page }, use) => { - const metamask = new MetaMaskMock(page) - - metamask.importWallet(SEED_PHRASE) - - await use(metamask) - }, - createAnvilNetwork: async ({ context: _ }, use) => { - await use(() => { - return { - name: 'Anvil', - rpcUrl: ANVIL_URL_URL, - chainId: ANVIL_CHAIN_ID, - blockExplorerUrl: 'https://etherscan.io/', - nativeCurrency: { - decimals: 18, - name: 'Anvil', - symbol: 'ETH' - } - } - }) - } -}) diff --git a/wallets/metamask-mock/src/utils/index.ts b/wallets/metamask-mock/src/utils/index.ts deleted file mode 100644 index 8fe4e82ee..000000000 --- a/wallets/metamask-mock/src/utils/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as mockEthereum } from './mockEthereum' diff --git a/wallets/metamask-mock/src/utils/mockEthereum.ts b/wallets/metamask-mock/src/utils/mockEthereum.ts deleted file mode 100644 index 5c500f5f7..000000000 --- a/wallets/metamask-mock/src/utils/mockEthereum.ts +++ /dev/null @@ -1,9 +0,0 @@ -export default function mockEthereum() { - Web3Mock.mock({ - blockchain: 'ethereum', - wallet: 'metamask', - accounts: { - return: ['0xd73b04b0e696b0945283defa3eee453814758f1a'] - } - }) -} diff --git a/wallets/metamask-mock/test/e2e/metamask/addNewAccount.spec.ts b/wallets/metamask-mock/test/e2e/metamask/addNewAccount.spec.ts deleted file mode 100644 index 66d501321..000000000 --- a/wallets/metamask-mock/test/e2e/metamask/addNewAccount.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { testWithMetaMaskMock } from '../../../src' - -const test = testWithMetaMaskMock - -const { expect } = test - -test('should add a new account with specified name', async ({ metamask }) => { - expect(await metamask.getAllAccounts()).toHaveLength(1) - - await metamask.addNewAccount() - - expect(await metamask.getAllAccounts()).toHaveLength(2) - - await metamask.addNewAccount() - await metamask.addNewAccount() - - expect(await metamask.getAllAccounts()).toHaveLength(4) -}) diff --git a/wallets/metamask-mock/test/e2e/metamask/importWalletFromPrivateKey.spec.ts b/wallets/metamask-mock/test/e2e/metamask/importWalletFromPrivateKey.spec.ts deleted file mode 100644 index 8d699d21c..000000000 --- a/wallets/metamask-mock/test/e2e/metamask/importWalletFromPrivateKey.spec.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { testWithMetaMaskMock } from '../../../src' - -const test = testWithMetaMaskMock - -const { expect } = test - -test('should import account using private key', async ({ page, metamask }) => { - await metamask.importWalletFromPrivateKey('0xea084c575a01e2bbefcca3db101eaeab1d8af15554640a510c73692db24d0a6a') - - await page.locator('#getAccounts').click() - await expect(page.locator('#getAccountsResult')).toHaveText('0xa2ce797cA71d0EaE1be5a7EffD27Fd6C38126801') -}) diff --git a/wallets/metamask-mock/test/e2e/metamask/mock/mockEthereum.spec.ts b/wallets/metamask-mock/test/e2e/metamask/mock/mockEthereum.spec.ts deleted file mode 100644 index 70fb1be59..000000000 --- a/wallets/metamask-mock/test/e2e/metamask/mock/mockEthereum.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { testWithMetaMaskMock } from '../../../../src' - -const test = testWithMetaMaskMock - -const { expect } = test - -test('should be able to access ethereum API', async ({ page }) => { - const ethereum = await page.evaluate(() => window.ethereum) - expect(ethereum).toBeTruthy() -}) - -test('should be connected to metamask', async ({ page }) => { - const ethereum = await page.evaluate(() => window.ethereum) - expect(ethereum.isMetaMask).toBe(true) -}) - -test('should connect to ethereum', async ({ page }) => { - const currentChainId = await page.evaluate(() => - window.ethereum.request({ - method: 'eth_chainId' - }) - ) - - expect(currentChainId).toEqual('0x1') -}) diff --git a/wallets/metamask-mock/test/e2e/metamask/switchAccount.spec.ts b/wallets/metamask-mock/test/e2e/metamask/switchAccount.spec.ts deleted file mode 100644 index b3570e38d..000000000 --- a/wallets/metamask-mock/test/e2e/metamask/switchAccount.spec.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { testWithMetaMaskMock } from '../../../src' - -const test = testWithMetaMaskMock - -const { expect } = test - -test('should switch account', async ({ page, metamask }) => { - await metamask.switchAccount('0x4444797cA71d0EaE1be5a7EffD27Fd6C38126801') - - await page.locator('#getAccounts').click() - await expect(page.locator('#getAccountsResult')).toHaveText('0x4444797cA71d0EaE1be5a7EffD27Fd6C38126801') -}) diff --git a/wallets/metamask-mock/test/e2e/metamask/switchNetwork.spec.ts b/wallets/metamask-mock/test/e2e/metamask/switchNetwork.spec.ts deleted file mode 100644 index d04a2f238..000000000 --- a/wallets/metamask-mock/test/e2e/metamask/switchNetwork.spec.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { testWithMetaMaskMock } from '../../../src' - -const test = testWithMetaMaskMock - -const { expect } = test - -test('should switch network', async ({ createAnvilNetwork, metamask, page }) => { - const network = createAnvilNetwork() - - await metamask.addNetwork(network) - - await metamask.switchNetwork(network.name) - - const chainId = await page.evaluate(async () => { - return await window.ethereum.request({ method: 'eth_chainId' }) - }) - - expect(chainId).toBe('0x38') -}) From 4f671877095f647bd8d2cd15234384fda93dbf5a Mon Sep 17 00:00:00 2001 From: matstyler Date: Thu, 18 Apr 2024 20:47:08 +0200 Subject: [PATCH 2/4] fix: format --- examples/new-dawn/test/e2e/00_mock.spec.ts | 47 +++---- release/src/index.ts | 22 +-- .../src/ethereum-wallet-mock.ts | 129 ++++++++---------- wallets/ethereum-wallet-mock/src/index.ts | 6 +- .../src/testWithEthereumWalletMock.ts | 72 +++++----- .../src/utils/constants.ts | 16 +-- .../ethereum-wallet-mock/src/utils/index.ts | 4 +- .../src/utils/mockEthereum.ts | 15 +- .../test/e2e/metamask/addNewAccount.spec.ts | 22 +-- .../importWalletFromPrivateKey.spec.ts | 23 ++-- .../e2e/metamask/mock/mockEthereum.spec.ts | 57 ++++---- .../test/e2e/metamask/switchNetwork.spec.ts | 26 ++-- 12 files changed, 188 insertions(+), 251 deletions(-) diff --git a/examples/new-dawn/test/e2e/00_mock.spec.ts b/examples/new-dawn/test/e2e/00_mock.spec.ts index b23e8fa31..02a1ff137 100644 --- a/examples/new-dawn/test/e2e/00_mock.spec.ts +++ b/examples/new-dawn/test/e2e/00_mock.spec.ts @@ -1,38 +1,29 @@ -import { - EthereumWalletMock, - testWithEthereumWalletMock, -} from "@synthetixio/synpress"; +import { EthereumWalletMock, testWithEthereumWalletMock } from '@synthetixio/synpress' -const test = testWithEthereumWalletMock; +const test = testWithEthereumWalletMock -const { expect } = test; +const { expect } = test -test("should mock MetaMask in the Test Dapp", async ({ page, walletMock }) => { - expect(await walletMock.getAllAccounts()).toHaveLength(1); +test('should mock MetaMask in the Test Dapp', async ({ page, walletMock }) => { + expect(await walletMock.getAllAccounts()).toHaveLength(1) - await page.locator("#connectButton").click(); + await page.locator('#connectButton').click() - await expect(page.locator("#accounts")).toHaveText( - "0xd73b04b0e696b0945283defa3eee453814758f1a" - ); + await expect(page.locator('#accounts')).toHaveText('0xd73b04b0e696b0945283defa3eee453814758f1a') - await page.locator("#getAccounts").click(); - await expect(page.locator("#getAccountsResult")).toHaveText( - "0xd73b04b0e696b0945283defa3eee453814758f1a" - ); -}); + await page.locator('#getAccounts').click() + await expect(page.locator('#getAccountsResult')).toHaveText('0xd73b04b0e696b0945283defa3eee453814758f1a') +}) -test("should add new account using MetaMask mock", async ({ page }) => { - const walletMock = new EthereumWalletMock(page); +test('should add new account using MetaMask mock', async ({ page }) => { + const walletMock = new EthereumWalletMock(page) - await walletMock.importWallet( - "candy maple cake sugar pudding cream honey rich smooth crumble sweet treat" - ); - await walletMock.addNewAccount(); + await walletMock.importWallet('candy maple cake sugar pudding cream honey rich smooth crumble sweet treat') + await walletMock.addNewAccount() - await page.locator("#connectButton").click(); + await page.locator('#connectButton').click() - await expect(page.locator("#accounts")).toHaveText( - "0x6503D95e3F20389EE9496b277ABfFDb8eCCD2cc5,0xd73b04b0e696b0945283defa3eee453814758f1a" - ); -}); + await expect(page.locator('#accounts')).toHaveText( + '0x6503D95e3F20389EE9496b277ABfFDb8eCCD2cc5,0xd73b04b0e696b0945283defa3eee453814758f1a' + ) +}) diff --git a/release/src/index.ts b/release/src/index.ts index 362c788d1..e0bb3d6ce 100644 --- a/release/src/index.ts +++ b/release/src/index.ts @@ -1,17 +1,7 @@ -import { defineWalletSetup } from "@synthetixio/synpress-core"; -import { - getExtensionId, - testWithSynpress, -} from "@synthetixio/synpress-fixtures"; -import { - MetaMask, - homePageSelectors, - unlockForFixture, -} from "@synthetixio/synpress-metamask"; -import { - EthereumWalletMock, - testWithEthereumWalletMock, -} from "@synthetixio/ethereum-wallet-mock"; +import { EthereumWalletMock, testWithEthereumWalletMock } from '@synthetixio/ethereum-wallet-mock' +import { defineWalletSetup } from '@synthetixio/synpress-core' +import { getExtensionId, testWithSynpress } from '@synthetixio/synpress-fixtures' +import { MetaMask, homePageSelectors, unlockForFixture } from '@synthetixio/synpress-metamask' export { // Framework fixtures @@ -24,5 +14,5 @@ export { defineWalletSetup, getExtensionId, unlockForFixture, - homePageSelectors, -}; + homePageSelectors +} diff --git a/wallets/ethereum-wallet-mock/src/ethereum-wallet-mock.ts b/wallets/ethereum-wallet-mock/src/ethereum-wallet-mock.ts index 0aec066f0..81f9314b4 100644 --- a/wallets/ethereum-wallet-mock/src/ethereum-wallet-mock.ts +++ b/wallets/ethereum-wallet-mock/src/ethereum-wallet-mock.ts @@ -1,29 +1,16 @@ -import type { Page } from "@playwright/test"; -import { mnemonicToAccount, privateKeyToAccount } from "viem/accounts"; -import type { Network } from "./network/Network"; -import { ACCOUNT_MOCK, BLOCKCHAIN, BSC_NETWORK_ID } from "./utils"; - -export type WalletMock = - | "metamask" - | "coinbase" - | "phantom" - | "walletconnect" - | "walletlink"; - -/** - * This class is the heart of Synpress's MetaMask API. - */ +import type { Page } from '@playwright/test' +import { mnemonicToAccount, privateKeyToAccount } from 'viem/accounts' +import type { Network } from './network/Network' +import { ACCOUNT_MOCK, BLOCKCHAIN, BSC_NETWORK_ID } from './utils' + +export type WalletMock = 'metamask' | 'coinbase' | 'phantom' | 'walletconnect' | 'walletlink' + export class EthereumWalletMock { - seedPhrase = ""; - wallet: WalletMock = "metamask"; - - constructor( - /** - * The MetaMask tab page. - */ - readonly page: Page - ) { - this.page = page; + seedPhrase = '' + wallet: WalletMock = 'metamask' + + constructor(readonly page: Page) { + this.page = page } /** @@ -32,7 +19,7 @@ export class EthereumWalletMock { * @param seedPhrase - The seed phrase to import. */ importWallet(seedPhrase: string) { - this.seedPhrase = seedPhrase; + this.seedPhrase = seedPhrase return this.page.evaluate( ([blockchain, wallet, accounts]) => { @@ -40,12 +27,12 @@ export class EthereumWalletMock { blockchain, wallet, accounts: { - return: accounts, - }, - }); + return: accounts + } + }) }, [BLOCKCHAIN, this.wallet, [ACCOUNT_MOCK]] - ); + ) } /** @@ -53,19 +40,19 @@ export class EthereumWalletMock { */ async getAllAccounts(): Promise { return this.page.evaluate(() => { - return window.ethereum.request({ method: "eth_requestAccounts" }); - }); + return window.ethereum.request({ method: 'eth_requestAccounts' }) + }) } /** * Adds a new account. This account is based on the initially imported seed phrase. */ async addNewAccount() { - const accounts = await this.getAllAccounts(); + const accounts = await this.getAllAccounts() const newAccount = mnemonicToAccount(this.seedPhrase, { - accountIndex: accounts.length, - }); + accountIndex: accounts.length + }) return this.page.evaluate( ([blockchain, wallet, accounts]) => { @@ -73,12 +60,12 @@ export class EthereumWalletMock { blockchain, wallet, accounts: { - return: accounts, - }, - }); + return: accounts + } + }) }, [BLOCKCHAIN, this.wallet, [newAccount.address, ...accounts]] - ); + ) } /** @@ -87,7 +74,7 @@ export class EthereumWalletMock { * @param privateKey - The private key to import. */ async importWalletFromPrivateKey(privateKey: `0x${string}`) { - const newAccount = privateKeyToAccount(privateKey); + const newAccount = privateKeyToAccount(privateKey) return this.page.evaluate( ([blockchain, wallet, account]) => { @@ -95,12 +82,12 @@ export class EthereumWalletMock { blockchain, wallet, accounts: { - return: account, - }, - }); + return: account + } + }) }, [BLOCKCHAIN, this.wallet, [newAccount.address]] - ); + ) } /** @@ -115,12 +102,12 @@ export class EthereumWalletMock { blockchain, wallet, accounts: { - return: [accountAddress], - }, - }); + return: [accountAddress] + } + }) }, [BLOCKCHAIN, this.wallet, accountAddress] - ); + ) } /** @@ -139,8 +126,8 @@ export class EthereumWalletMock { chainName: network.name, nativeCurrency: network.nativeCurrency, rpcUrls: [network.rpcUrl], - blockExplorerUrls: [network.blockExplorerUrl], - }; + blockExplorerUrls: [network.blockExplorerUrl] + } return this.page.evaluate( ([blockchain, wallet, networkInfo]) => { @@ -148,19 +135,19 @@ export class EthereumWalletMock { blockchain, wallet, network: { - add: networkInfo, - }, - }); + add: networkInfo + } + }) }, [BLOCKCHAIN, this.wallet, networkInfo] - ); + ) } /** * Retrieves the current account address. */ async getAccountAddress() { - return (await this.getAllAccounts())[0]; + return (await this.getAllAccounts())[0] } /** @@ -175,46 +162,46 @@ export class EthereumWalletMock { blockchain, wallet, network: { - switchTo: networkName, - }, - }); + switchTo: networkName + } + }) window.ethereum.request({ - method: "wallet_switchEthereumChain", + method: 'wallet_switchEthereumChain', // Mock do not support custom network IDs - params: [{ chainId }], - }); + params: [{ chainId }] + }) }, [BLOCKCHAIN, this.wallet, networkName, BSC_NETWORK_ID] - ); + ) } /** * Connects wallet to the dapp. */ - async connectToDapp(wallet: WalletMock = "metamask") { - this.wallet = wallet; + async connectToDapp(wallet: WalletMock = 'metamask') { + this.wallet = wallet return this.page.evaluate( ([blockchain, accounts, wallet]) => { // Cannot pass custom class as an argument to `page.evaluate` class WalletConnectStub {} - let connector: WalletConnectStub | undefined; + let connector: WalletConnectStub | undefined - if (wallet === "walletconnect") { - connector = WalletConnectStub; + if (wallet === 'walletconnect') { + connector = WalletConnectStub } return Web3Mock.mock({ blockchain, wallet, accounts: { - return: accounts, + return: accounts }, - connector, - }); + connector + }) }, [BLOCKCHAIN, [ACCOUNT_MOCK], wallet] - ); + ) } } diff --git a/wallets/ethereum-wallet-mock/src/index.ts b/wallets/ethereum-wallet-mock/src/index.ts index 68111873d..c75e6ec10 100644 --- a/wallets/ethereum-wallet-mock/src/index.ts +++ b/wallets/ethereum-wallet-mock/src/index.ts @@ -1,3 +1,3 @@ -export * from "./ethereum-wallet-mock"; -export * from "./utils"; -export * from "./testWithEthereumWalletMock"; +export * from './ethereum-wallet-mock' +export * from './utils' +export * from './testWithEthereumWalletMock' diff --git a/wallets/ethereum-wallet-mock/src/testWithEthereumWalletMock.ts b/wallets/ethereum-wallet-mock/src/testWithEthereumWalletMock.ts index 40353cdd5..eb5412a83 100644 --- a/wallets/ethereum-wallet-mock/src/testWithEthereumWalletMock.ts +++ b/wallets/ethereum-wallet-mock/src/testWithEthereumWalletMock.ts @@ -1,66 +1,56 @@ -import { readFileSync } from "fs"; -import { createRequire } from "node:module"; -import { test as base } from "@playwright/test"; -import { EthereumWalletMock } from "./ethereum-wallet-mock"; -import type { Network } from "./network/Network"; -import { - ANVIL_CHAIN_ID, - ANVIL_URL_URL, - mockEthereum, - SEED_PHRASE, -} from "./utils"; - -const require = createRequire(import.meta.url); +import { readFileSync } from 'fs' +import { createRequire } from 'node:module' +import { test as base } from '@playwright/test' +import { EthereumWalletMock } from './ethereum-wallet-mock' +import type { Network } from './network/Network' +import { ANVIL_CHAIN_ID, ANVIL_URL_URL, SEED_PHRASE, mockEthereum } from './utils' + +const require = createRequire(import.meta.url) // Relative path to the web3-mock bundle -const web3MockPath = require.resolve( - "@depay/web3-mock/dist/umd/index.bundle.js" -); +const web3MockPath = require.resolve('@depay/web3-mock/dist/umd/index.bundle.js') export const testWithEthereumWalletMock = base.extend<{ - walletMock: EthereumWalletMock; - createAnvilNetwork: () => Network; - deployToken: () => Promise; + walletMock: EthereumWalletMock + createAnvilNetwork: () => Network + deployToken: () => Promise }>({ context: async ({ context }, use) => { // Dependency and mock function has to be added at the same time - https://playwright.dev/docs/api/class-browsercontext#browser-context-add-init-script await context.addInitScript({ - content: `${readFileSync( - web3MockPath, - "utf-8" - )}\n(${mockEthereum.toString()})();`, - }); + content: `${readFileSync(web3MockPath, 'utf-8')}\n(${mockEthereum.toString()})();` + }) - await use(context); + await use(context) - await context.close(); + await context.close() }, page: async ({ context }, use) => { - const page = await context.newPage(); + const page = await context.newPage() - await page.goto("/"); + await page.goto('/') - await use(page); + await use(page) }, walletMock: async ({ page }, use) => { - const walletMock = new EthereumWalletMock(page); + const walletMock = new EthereumWalletMock(page) - await walletMock.importWallet(SEED_PHRASE); + await walletMock.importWallet(SEED_PHRASE) - await use(walletMock); + await use(walletMock) }, createAnvilNetwork: async ({ context: _ }, use) => { await use(() => { return { - name: "Anvil", + name: 'Anvil', rpcUrl: ANVIL_URL_URL, chainId: ANVIL_CHAIN_ID, - blockExplorerUrl: "https://etherscan.io/", + blockExplorerUrl: 'https://etherscan.io/', nativeCurrency: { decimals: 18, - name: "Anvil", - symbol: "ETH", - }, - }; - }); - }, -}); + name: 'Anvil', + symbol: 'ETH' + } + } + }) + } +}) diff --git a/wallets/ethereum-wallet-mock/src/utils/constants.ts b/wallets/ethereum-wallet-mock/src/utils/constants.ts index ea146e1a1..c55d1bd8f 100644 --- a/wallets/ethereum-wallet-mock/src/utils/constants.ts +++ b/wallets/ethereum-wallet-mock/src/utils/constants.ts @@ -1,14 +1,12 @@ -export const BLOCKCHAIN = "ethereum"; +export const BLOCKCHAIN = 'ethereum' -export const ACCOUNT_MOCK = "0xd73b04b0e696b0945283defa3eee453814758f1a"; +export const ACCOUNT_MOCK = '0xd73b04b0e696b0945283defa3eee453814758f1a' -export const SEED_PHRASE = - "test test test test test test test test test test test junk"; +export const SEED_PHRASE = 'test test test test test test test test test test test junk' -export const PRIVATE_KEY = - "ea084c575a01e2bbefcca3db101eaeab1d8af15554640a510c73692db24d0a6a"; +export const PRIVATE_KEY = 'ea084c575a01e2bbefcca3db101eaeab1d8af15554640a510c73692db24d0a6a' -export const ANVIL_CHAIN_ID = 31337; -export const ANVIL_URL_URL = "http://anvil:5000"; +export const ANVIL_CHAIN_ID = 31337 +export const ANVIL_URL_URL = 'http://anvil:5000' -export const BSC_NETWORK_ID = "0x38"; +export const BSC_NETWORK_ID = '0x38' diff --git a/wallets/ethereum-wallet-mock/src/utils/index.ts b/wallets/ethereum-wallet-mock/src/utils/index.ts index bed844583..2813a058c 100644 --- a/wallets/ethereum-wallet-mock/src/utils/index.ts +++ b/wallets/ethereum-wallet-mock/src/utils/index.ts @@ -1,2 +1,2 @@ -export { default as mockEthereum } from "./mockEthereum"; -export * from "./constants"; +export { default as mockEthereum } from './mockEthereum' +export * from './constants' diff --git a/wallets/ethereum-wallet-mock/src/utils/mockEthereum.ts b/wallets/ethereum-wallet-mock/src/utils/mockEthereum.ts index b9b7e5227..a3871b9df 100644 --- a/wallets/ethereum-wallet-mock/src/utils/mockEthereum.ts +++ b/wallets/ethereum-wallet-mock/src/utils/mockEthereum.ts @@ -1,17 +1,12 @@ export default function mockEthereum( - wallet: - | "metamask" - | "coinbase" - | "phantom" - | "walletconnect" - | "walletlink" = "metamask", + wallet: 'metamask' | 'coinbase' | 'phantom' | 'walletconnect' | 'walletlink' = 'metamask', accounts: `0x${string}`[] = [] ) { Web3Mock.mock({ - blockchain: "ethereum", + blockchain: 'ethereum', wallet, accounts: { - return: accounts, - }, - }); + return: accounts + } + }) } diff --git a/wallets/ethereum-wallet-mock/test/e2e/metamask/addNewAccount.spec.ts b/wallets/ethereum-wallet-mock/test/e2e/metamask/addNewAccount.spec.ts index 09ba8ea9c..7ec93d0b8 100644 --- a/wallets/ethereum-wallet-mock/test/e2e/metamask/addNewAccount.spec.ts +++ b/wallets/ethereum-wallet-mock/test/e2e/metamask/addNewAccount.spec.ts @@ -1,19 +1,19 @@ -import { testWithEthereumWalletMock } from "../../../src"; +import { testWithEthereumWalletMock } from '../../../src' -const test = testWithEthereumWalletMock; +const test = testWithEthereumWalletMock -const { expect } = test; +const { expect } = test -test("should add a new account with specified name", async ({ walletMock }) => { +test('should add a new account with specified name', async ({ walletMock }) => { // Imported wallet includes 1 account - expect(await walletMock.getAllAccounts()).toHaveLength(1); + expect(await walletMock.getAllAccounts()).toHaveLength(1) - await walletMock.addNewAccount(); + await walletMock.addNewAccount() - expect(await walletMock.getAllAccounts()).toHaveLength(2); + expect(await walletMock.getAllAccounts()).toHaveLength(2) - await walletMock.addNewAccount(); - await walletMock.addNewAccount(); + await walletMock.addNewAccount() + await walletMock.addNewAccount() - expect(await walletMock.getAllAccounts()).toHaveLength(4); -}); + expect(await walletMock.getAllAccounts()).toHaveLength(4) +}) diff --git a/wallets/ethereum-wallet-mock/test/e2e/metamask/importWalletFromPrivateKey.spec.ts b/wallets/ethereum-wallet-mock/test/e2e/metamask/importWalletFromPrivateKey.spec.ts index 7fc8eddee..07d9d1fb1 100644 --- a/wallets/ethereum-wallet-mock/test/e2e/metamask/importWalletFromPrivateKey.spec.ts +++ b/wallets/ethereum-wallet-mock/test/e2e/metamask/importWalletFromPrivateKey.spec.ts @@ -1,19 +1,12 @@ -import { testWithEthereumWalletMock } from "../../../src"; +import { testWithEthereumWalletMock } from '../../../src' -const test = testWithEthereumWalletMock; +const test = testWithEthereumWalletMock -const { expect } = test; +const { expect } = test -test("should import account using private key", async ({ - page, - walletMock, -}) => { - await walletMock.importWalletFromPrivateKey( - "0xea084c575a01e2bbefcca3db101eaeab1d8af15554640a510c73692db24d0a6a" - ); +test('should import account using private key', async ({ page, walletMock }) => { + await walletMock.importWalletFromPrivateKey('0xea084c575a01e2bbefcca3db101eaeab1d8af15554640a510c73692db24d0a6a') - await page.locator("#getAccounts").click(); - await expect(page.locator("#getAccountsResult")).toHaveText( - "0xa2ce797cA71d0EaE1be5a7EffD27Fd6C38126801" - ); -}); + await page.locator('#getAccounts').click() + await expect(page.locator('#getAccountsResult')).toHaveText('0xa2ce797cA71d0EaE1be5a7EffD27Fd6C38126801') +}) diff --git a/wallets/ethereum-wallet-mock/test/e2e/metamask/mock/mockEthereum.spec.ts b/wallets/ethereum-wallet-mock/test/e2e/metamask/mock/mockEthereum.spec.ts index fa2834826..4917df84f 100644 --- a/wallets/ethereum-wallet-mock/test/e2e/metamask/mock/mockEthereum.spec.ts +++ b/wallets/ethereum-wallet-mock/test/e2e/metamask/mock/mockEthereum.spec.ts @@ -1,45 +1,42 @@ -import { testWithEthereumWalletMock } from "../../../../src"; +import { testWithEthereumWalletMock } from '../../../../src' -const test = testWithEthereumWalletMock; +const test = testWithEthereumWalletMock -const { expect } = test; +const { expect } = test -test("should be able to access ethereum API", async ({ page }) => { - const ethereum = await page.evaluate(() => window.ethereum); - expect(ethereum).toBeTruthy(); -}); +test('should be able to access ethereum API', async ({ page }) => { + const ethereum = await page.evaluate(() => window.ethereum) + expect(ethereum).toBeTruthy() +}) -test("should be connected to metamask by default", async ({ page }) => { - const ethereum = await page.evaluate(() => window.ethereum); - expect(ethereum.isMetaMask).toBe(true); -}); +test('should be connected to metamask by default', async ({ page }) => { + const ethereum = await page.evaluate(() => window.ethereum) + expect(ethereum.isMetaMask).toBe(true) +}) -test("should connect to ethereum", async ({ page }) => { +test('should connect to ethereum', async ({ page }) => { const currentChainId = await page.evaluate(() => window.ethereum.request({ - method: "eth_chainId", + method: 'eth_chainId' }) - ); + ) - expect(currentChainId).toEqual("0x1"); -}); + expect(currentChainId).toEqual('0x1') +}) -test("should be able to connect to every supported ethereum wallet", async ({ - page, - walletMock, -}) => { +test('should be able to connect to every supported ethereum wallet', async ({ page, walletMock }) => { // Metamask - let ethereum = await page.evaluate(() => window.ethereum); - expect(ethereum.isMetaMask).toBe(true); - expect(ethereum.isCoinbaseWallet).toBe(undefined); + let ethereum = await page.evaluate(() => window.ethereum) + expect(ethereum.isMetaMask).toBe(true) + expect(ethereum.isCoinbaseWallet).toBe(undefined) // Coinbase wallet - await walletMock.connectToDapp("coinbase"); - ethereum = await page.evaluate(() => window.ethereum); - expect(ethereum.isCoinbaseWallet).toBe(true); + await walletMock.connectToDapp('coinbase') + ethereum = await page.evaluate(() => window.ethereum) + expect(ethereum.isCoinbaseWallet).toBe(true) // Walletconnect - await walletMock.connectToDapp("walletconnect"); - ethereum = await page.evaluate(() => window.ethereum); - expect(ethereum.isWalletLink).toBe(true); -}); + await walletMock.connectToDapp('walletconnect') + ethereum = await page.evaluate(() => window.ethereum) + expect(ethereum.isWalletLink).toBe(true) +}) diff --git a/wallets/ethereum-wallet-mock/test/e2e/metamask/switchNetwork.spec.ts b/wallets/ethereum-wallet-mock/test/e2e/metamask/switchNetwork.spec.ts index 5dc844cbb..dbee188ff 100644 --- a/wallets/ethereum-wallet-mock/test/e2e/metamask/switchNetwork.spec.ts +++ b/wallets/ethereum-wallet-mock/test/e2e/metamask/switchNetwork.spec.ts @@ -1,23 +1,19 @@ -import { testWithEthereumWalletMock } from "../../../src"; +import { testWithEthereumWalletMock } from '../../../src' -const test = testWithEthereumWalletMock; +const test = testWithEthereumWalletMock -const { expect } = test; +const { expect } = test -test("should switch network", async ({ - createAnvilNetwork, - walletMock, - page, -}) => { - const network = createAnvilNetwork(); +test('should switch network', async ({ createAnvilNetwork, walletMock, page }) => { + const network = createAnvilNetwork() - await walletMock.addNetwork(network); + await walletMock.addNetwork(network) - await walletMock.switchNetwork(network.name); + await walletMock.switchNetwork(network.name) const chainId = await page.evaluate(async () => { - return await window.ethereum.request({ method: "eth_chainId" }); - }); + return await window.ethereum.request({ method: 'eth_chainId' }) + }) - expect(chainId).toBe("0x38"); -}); + expect(chainId).toBe('0x38') +}) From a7406fe12898a04c998273eb1f7965089381dc9f Mon Sep 17 00:00:00 2001 From: matstyler Date: Thu, 18 Apr 2024 21:55:20 +0200 Subject: [PATCH 3/4] fix: tests --- .../test/e2e/metamask/connectToDapp.spec.ts | 67 ++++++++++++------- 1 file changed, 44 insertions(+), 23 deletions(-) diff --git a/wallets/metamask/test/e2e/metamask/connectToDapp.spec.ts b/wallets/metamask/test/e2e/metamask/connectToDapp.spec.ts index 52c6439fd..e3ca6cd06 100644 --- a/wallets/metamask/test/e2e/metamask/connectToDapp.spec.ts +++ b/wallets/metamask/test/e2e/metamask/connectToDapp.spec.ts @@ -1,37 +1,58 @@ -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 connect wallet to dapp', async ({ context, page, extensionId }) => { - const metamask = new MetaMask(context, page, basicSetup.walletPassword, extensionId) +test("should connect wallet to dapp", async ({ + context, + page, + extensionId, +}) => { + const metamask = new MetaMask( + context, + page, + basicSetup.walletPassword, + extensionId + ); - await page.goto('/') + await page.goto("/"); - await page.locator('#connectButton').click() + await page.locator("#connectButton").click(); - await metamask.connectToDapp() + await metamask.connectToDapp(); - await expect(page.locator('#accounts')).toHaveText('0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266') -}) + await expect(page.locator("#accounts")).toHaveText( + "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266" + ); +}); -test('should connect multiple wallets to dapp', async ({ context, page, metamaskPage, extensionId }) => { - const metamask = new MetaMask(context, metamaskPage, basicSetup.walletPassword, extensionId) +test("should connect multiple wallets to dapp", async ({ + context, + page, + metamaskPage, + extensionId, +}) => { + const metamask = new MetaMask( + context, + metamaskPage, + basicSetup.walletPassword, + extensionId + ); - await metamask.addNewAccount('Account x2') - await metamask.addNewAccount('Account x3') + await metamask.addNewAccount("Account x2"); + await metamask.addNewAccount("Account x3"); - await page.goto('/') - await page.locator('#connectButton').click() + await page.goto("/"); + await page.locator("#connectButton").click(); // "accounts" param is order agnostic - await metamask.connectToDapp(['Account x2', 'Account 1']) + await metamask.connectToDapp(["Account x2", "Account 1"]); - await expect(page.locator('#accounts')).toHaveText( - '0x976ea74026e726554db657fa54763abd0c3a0aa9,0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266' - ) -}) + await expect(page.locator("#accounts")).toHaveText( + "0x70997970c51812dc3a010c7d01b50e0d17dc79c8,0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266" + ); +}); From d9a478c14d761ab22d8a0050d483b479cfb6e1ec Mon Sep 17 00:00:00 2001 From: matstyler Date: Thu, 18 Apr 2024 21:57:11 +0200 Subject: [PATCH 4/4] fix: format --- .../test/e2e/metamask/connectToDapp.spec.ts | 67 +++++++------------ 1 file changed, 23 insertions(+), 44 deletions(-) diff --git a/wallets/metamask/test/e2e/metamask/connectToDapp.spec.ts b/wallets/metamask/test/e2e/metamask/connectToDapp.spec.ts index e3ca6cd06..0a9e56292 100644 --- a/wallets/metamask/test/e2e/metamask/connectToDapp.spec.ts +++ b/wallets/metamask/test/e2e/metamask/connectToDapp.spec.ts @@ -1,58 +1,37 @@ -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 connect wallet to dapp", async ({ - context, - page, - extensionId, -}) => { - const metamask = new MetaMask( - context, - page, - basicSetup.walletPassword, - extensionId - ); +test('should connect wallet to dapp', async ({ context, page, extensionId }) => { + const metamask = new MetaMask(context, page, basicSetup.walletPassword, extensionId) - await page.goto("/"); + await page.goto('/') - await page.locator("#connectButton").click(); + await page.locator('#connectButton').click() - await metamask.connectToDapp(); + await metamask.connectToDapp() - await expect(page.locator("#accounts")).toHaveText( - "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266" - ); -}); + await expect(page.locator('#accounts')).toHaveText('0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266') +}) -test("should connect multiple wallets to dapp", async ({ - context, - page, - metamaskPage, - extensionId, -}) => { - const metamask = new MetaMask( - context, - metamaskPage, - basicSetup.walletPassword, - extensionId - ); +test('should connect multiple wallets to dapp', async ({ context, page, metamaskPage, extensionId }) => { + const metamask = new MetaMask(context, metamaskPage, basicSetup.walletPassword, extensionId) - await metamask.addNewAccount("Account x2"); - await metamask.addNewAccount("Account x3"); + await metamask.addNewAccount('Account x2') + await metamask.addNewAccount('Account x3') - await page.goto("/"); - await page.locator("#connectButton").click(); + await page.goto('/') + await page.locator('#connectButton').click() // "accounts" param is order agnostic - await metamask.connectToDapp(["Account x2", "Account 1"]); + await metamask.connectToDapp(['Account x2', 'Account 1']) - await expect(page.locator("#accounts")).toHaveText( - "0x70997970c51812dc3a010c7d01b50e0d17dc79c8,0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266" - ); -}); + await expect(page.locator('#accounts')).toHaveText( + '0x70997970c51812dc3a010c7d01b50e0d17dc79c8,0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266' + ) +})