diff --git a/docs/api/cypress/classes/MetaMask.md b/docs/api/cypress/classes/MetaMask.md new file mode 100644 index 000000000..3404f36e0 --- /dev/null +++ b/docs/api/cypress/classes/MetaMask.md @@ -0,0 +1,771 @@ +# Class: MetaMask + +MetaMask class for interacting with the MetaMask extension in Cypress tests. + +## Constructors + +### new MetaMask() + +```ts +new MetaMask( + context, + metamaskExtensionPage, + metamaskExtensionId): MetaMask +``` + +Creates an instance of MetaMask. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `context` | `BrowserContext` | The browser context | +| `metamaskExtensionPage` | `Page` | The MetaMask extension page | +| `metamaskExtensionId` | `string` | The MetaMask extension ID | + +#### Returns + +[`MetaMask`](MetaMask.md) + +## Properties + +| Property | Modifier | Type | Description | +| :------ | :------ | :------ | :------ | +| `metamaskExtensionPage` | `readonly` | `Page` | The MetaMask extension page | +| `metamaskPlaywright` | `readonly` | [`MetaMask`](../../playwright/classes/MetaMask.md) | The MetaMask instance for Playwright | + +## Methods + +### addNetwork() + +```ts +addNetwork(network): Promise +``` + +Adds a new network to MetaMask. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `network` | `object` | The network configuration to add | +| `network.blockExplorerUrl`? | `string` | - | +| `network.chainId` | `number` | - | +| `network.name` | `string` | - | +| `network.rpcUrl` | `string` | - | +| `network.symbol` | `string` | - | + +#### Returns + +`Promise`\<`boolean`\> + +True if the network was added successfully + +*** + +### addNewAccount() + +```ts +addNewAccount(accountName): Promise +``` + +Adds a new account with the given name. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `accountName` | `string` | The name for the new account | + +#### Returns + +`Promise`\<`boolean`\> + +True if the account was added successfully + +*** + +### addNewToken() + +```ts +addNewToken(): Promise +``` + +Adds a new token to MetaMask. + +#### Returns + +`Promise`\<`boolean`\> + +True if the token was added successfully + +*** + +### approveNewNetwork() + +```ts +approveNewNetwork(): Promise +``` + +Approves adding a new network. + +#### Returns + +`Promise`\<`boolean`\> + +True if the new network was approved successfully + +*** + +### approveSwitchNetwork() + +```ts +approveSwitchNetwork(): Promise +``` + +Approves switching to a new network. + +#### Returns + +`Promise`\<`boolean`\> + +True if the network switch was approved successfully + +*** + +### approveTokenPermission() + +```ts +approveTokenPermission(options?): Promise +``` + +Approves token permission. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `options`? | `object` | Optional settings for token approval | +| `options.gasSetting`? | \| `"low"` \| `"market"` \| `"aggressive"` \| `"site"` \| \{ `"gasLimit"`: `number`; `"maxBaseFee"`: `number`; `"priorityFee"`: `number`; \} | Gas settings for the transaction | +| `options.spendLimit`? | `number` \| `"max"` | The spend limit for the token (number or 'max') | + +#### Returns + +`Promise`\<`boolean`\> + +True if the permission was approved, false otherwise + +*** + +### closeTransactionDetails() + +```ts +closeTransactionDetails(): Promise +``` + +Closes the transaction details view. + +#### Returns + +`Promise`\<`boolean`\> + +True if the transaction details were closed successfully, false otherwise + +*** + +### confirmSignature() + +```ts +confirmSignature(): Promise +``` + +Confirms a signature request. + +#### Returns + +`Promise`\<`boolean`\> + +True if the signature was confirmed successfully, false otherwise + +*** + +### confirmTransaction() + +```ts +confirmTransaction(options?): Promise +``` + +Confirms a transaction. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `options`? | `object` | Optional gas settings for the transaction | +| `options.gasSetting`? | \| `"low"` \| `"market"` \| `"aggressive"` \| `"site"` \| \{ `"gasLimit"`: `number`; `"maxBaseFee"`: `number`; `"priorityFee"`: `number`; \} | - | + +#### Returns + +`Promise`\<`boolean`\> + +True if the transaction was confirmed successfully + +*** + +### confirmTransactionAndWaitForMining() + +```ts +confirmTransactionAndWaitForMining(): Promise +``` + +Confirms a transaction and waits for it to be mined. + +#### Returns + +`Promise`\<`boolean`\> + +True if the transaction was confirmed and mined successfully, false otherwise + +*** + +### connectToAnvil() + +```ts +connectToAnvil(options): Promise +``` + +Connects to an Anvil node. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `options` | `object` | Object containing the RPC URL and chain ID | +| `options.chainId` | `number` | The chain ID of the Anvil node | +| `options.rpcUrl` | `string` | The RPC URL of the Anvil node | + +#### Returns + +`Promise`\<`boolean`\> + +True if the connection was successful, false otherwise + +*** + +### connectToDapp() + +```ts +connectToDapp(accounts?): Promise +``` + +Connects MetaMask to a dApp. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `accounts`? | `string`[] | Optional array of account addresses to connect | + +#### Returns + +`Promise`\<`boolean`\> + +True if the connection was successful + +*** + +### createAnvilNode() + +```ts +createAnvilNode(options?): Promise<{ + "anvil": any; + "chainId": number; + "rpcUrl": string; +}> +``` + +Creates an Anvil node for testing. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `options`? | `CreateAnvilOptions` | Optional Anvil node creation options | + +#### Returns + +`Promise`\<\{ + `"anvil"`: `any`; + `"chainId"`: `number`; + `"rpcUrl"`: `string`; + \}\> + +Object containing the Anvil instance, RPC URL, and chain ID + +| Member | Type | +| :------ | :------ | +| `anvil` | `any` | +| `chainId` | `number` | +| `rpcUrl` | `string` | + +*** + +### decrypt() + +```ts +decrypt(): Promise +``` + +Decrypts a message. + +#### Returns + +`Promise`\<`boolean`\> + +True if the message was decrypted successfully, false otherwise + +*** + +### deployToken() + +```ts +deployToken(): Promise +``` + +Deploys a token. + +#### Returns + +`Promise`\<`boolean`\> + +True if the token was deployed successfully + +*** + +### emptyAnvilNode() + +```ts +emptyAnvilNode(): Promise +``` + +Empties the Anvil node pool. + +#### Returns + +`Promise`\<`boolean`\> + +True if the operation was successful + +*** + +### getAccount() + +```ts +getAccount(): Promise +``` + +Gets the current account name. + +#### Returns + +`Promise`\<`string`\> + +The current account name + +*** + +### getAccountAddress() + +```ts +getAccountAddress(): Promise +``` + +Gets the current account address. + +#### Returns + +`Promise`\<`string`\> + +The current account address + +*** + +### getNetwork() + +```ts +getNetwork(): Promise +``` + +Gets the current network name. + +#### Returns + +`Promise`\<`string`\> + +The current network name + +*** + +### goBackToHomePage() + +```ts +goBackToHomePage(): Promise +``` + +Navigates back to the home page. + +#### Returns + +`Promise`\<`boolean`\> + +True if the navigation was successful + +*** + +### importWallet() + +```ts +importWallet(seedPhrase): Promise +``` + +Imports a wallet using a seed phrase. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `seedPhrase` | `string` | The seed phrase to import | + +#### Returns + +`Promise`\<`boolean`\> + +True if the import was successful + +*** + +### importWalletFromPrivateKey() + +```ts +importWalletFromPrivateKey(privateKey): Promise +``` + +Imports a wallet using a private key. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `privateKey` | `string` | The private key to import | + +#### Returns + +`Promise`\<`boolean`\> + +True if the import was successful + +*** + +### lock() + +```ts +lock(): Promise +``` + +Locks the MetaMask wallet. + +#### Returns + +`Promise`\<`boolean`\> + +True if the wallet was locked successfully + +*** + +### openSettings() + +```ts +openSettings(): Promise +``` + +Opens the settings page. + +#### Returns + +`Promise`\<`boolean`\> + +True if the settings page was opened successfully + +*** + +### openSidebarMenu() + +```ts +openSidebarMenu(menu): Promise +``` + +Opens a specific sidebar menu in the settings. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `menu` | `SettingsSidebarMenus` | The menu to open | + +#### Returns + +`Promise`\<`boolean`\> + +True if the menu was opened successfully + +*** + +### openTransactionDetails() + +```ts +openTransactionDetails(txIndex): Promise +``` + +Opens the details of a specific transaction. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `txIndex` | `number` | The index of the transaction to open | + +#### Returns + +`Promise`\<`boolean`\> + +True if the transaction details were opened successfully, false otherwise + +*** + +### providePublicEncryptionKey() + +```ts +providePublicEncryptionKey(): Promise +``` + +Provides a public encryption key. + +#### Returns + +`Promise`\<`boolean`\> + +True if the key was provided successfully, false otherwise + +*** + +### rejectNewNetwork() + +```ts +rejectNewNetwork(): Promise +``` + +Rejects adding a new network. + +#### Returns + +`Promise`\<`boolean`\> + +True if the new network was rejected successfully + +*** + +### rejectSignature() + +```ts +rejectSignature(): Promise +``` + +Rejects a signature request. + +#### Returns + +`Promise`\<`boolean`\> + +True if the signature was rejected successfully + +*** + +### rejectSwitchNetwork() + +```ts +rejectSwitchNetwork(): Promise +``` + +Rejects switching to a new network. + +#### Returns + +`Promise`\<`boolean`\> + +True if the network switch was rejected successfully + +*** + +### rejectTokenPermission() + +```ts +rejectTokenPermission(): Promise +``` + +Rejects token permission. + +#### Returns + +`Promise`\<`boolean`\> + +True if the permission was rejected successfully + +*** + +### rejectTransaction() + +```ts +rejectTransaction(): Promise +``` + +Rejects a transaction. + +#### Returns + +`Promise`\<`boolean`\> + +True if the transaction was rejected successfully + +*** + +### renameAccount() + +```ts +renameAccount(options): Promise +``` + +Renames an account. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `options` | `object` | Object containing the current and new account names | +| `options.currentAccountName` | `string` | The current name of the account | +| `options.newAccountName` | `string` | The new name for the account | + +#### Returns + +`Promise`\<`boolean`\> + +True if the rename was successful + +*** + +### resetAccount() + +```ts +resetAccount(): Promise +``` + +Resets the current account. + +#### Returns + +`Promise`\<`boolean`\> + +True if the reset was successful + +*** + +### switchAccount() + +```ts +switchAccount(accountName): Promise +``` + +Switches to the account with the given name. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `accountName` | `string` | The name of the account to switch to | + +#### Returns + +`Promise`\<`boolean`\> + +True if the switch was successful + +*** + +### switchNetwork() + +```ts +switchNetwork(options): Promise +``` + +Switches to the specified network. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `options` | `object` | Object containing the network name and testnet flag | +| `options.isTestnet`? | `boolean` | Whether the network is a testnet (default: false) | +| `options.networkName` | `string` | The name of the network to switch to | + +#### Returns + +`Promise`\<`boolean`\> + +True if the switch was successful, false otherwise + +*** + +### toggleDismissSecretRecoveryPhraseReminder() + +```ts +toggleDismissSecretRecoveryPhraseReminder(): Promise +``` + +Toggles the dismissal of the secret recovery phrase reminder. + +#### Returns + +`Promise`\<`boolean`\> + +True if the toggle was successful + +*** + +### toggleShowTestNetworks() + +```ts +toggleShowTestNetworks(): Promise +``` + +Toggles the display of test networks. + +#### Returns + +`Promise`\<`boolean`\> + +True if the toggle was successful + +*** + +### unlock() + +```ts +unlock(): Promise +``` + +Unlocks the MetaMask wallet. + +#### Returns + +`Promise`\<`boolean`\> + +True if the wallet was unlocked successfully diff --git a/docs/api/cypress/functions/configureSynpressForEthereumWalletMock.md b/docs/api/cypress/functions/configureSynpressForEthereumWalletMock.md new file mode 100644 index 000000000..988c3653d --- /dev/null +++ b/docs/api/cypress/functions/configureSynpressForEthereumWalletMock.md @@ -0,0 +1,331 @@ +# Function: configureSynpressForEthereumWalletMock() + +```ts +function configureSynpressForEthereumWalletMock(on, config): { + "animationDistanceThreshold": number; + "arch": string; + "autoOpen": boolean; + "baseUrl": string | null; + "blockHosts": string | string[] | null; + "browser": Cypress.Browser; + "browserUrl": string; + "browsers": Cypress.Browser[]; + "chromeWebSecurity": boolean; + "clientCertificates": Cypress.ClientCertificate[]; + "clientRoute": string; + "component": Cypress.ComponentConfigOptions; + "configFile": string; + "cypressBinaryRoot": string; + "cypressEnv": string; + "defaultCommandTimeout": number; + "devServerPublicPathRoute": string; + "downloadsFolder": string; + "e2e": Cypress.EndToEndConfigOptions; + "env": {}; + "excludeSpecPattern": string | string[]; + "execTimeout": number; + "experimentalCspAllowList": boolean | Cypress.experimentalCspAllowedDirectives[]; + "experimentalFetchPolyfill": boolean; + "experimentalInteractiveRunEvents": boolean; + "experimentalMemoryManagement": boolean; + "experimentalModifyObstructiveThirdPartyCode": boolean; + "experimentalSkipDomainInjection": string[] | null; + "experimentalSourceRewriting": boolean; + "experimentalStudio": boolean; + "experimentalWebKitSupport": boolean; + "fileServerFolder": string; + "fixturesFolder": string | false; + "hideCommandLog": boolean; + "hideRunnerUi": boolean; + "hosts": {} | null; + "includeShadowDom": boolean; + "indexHtmlFile": string; + "isInteractive": boolean; + "isNewProject": boolean; + "isTextTerminal": boolean; + "modifyObstructiveCode": boolean; + "morgan": boolean; + "namespace": string; + "numTestsKeptInMemory": number; + "pageLoadTimeout": number; + "parentTestsFolder": string; + "parentTestsFolderDisplay": string; + "platform": "linux" | "darwin" | "win32"; + "port": number | null; + "projectId": string | null; + "projectName": string; + "projectRoot": string; + "protocolEnabled": boolean; + "proxyUrl": string; + "redirectionLimit": number; + "remote": Cypress.RemoteState; + "repoRoot": string | null; + "report": boolean; + "reporter": string; + "reporterOptions": {}; + "reporterRoute": string; + "reporterUrl": string; + "requestTimeout": number; + "resolvedNodePath": string; + "resolvedNodeVersion": string; + "responseTimeout": number; + "retries": Cypress.Nullable; + "runMode": Cypress.Nullable; + } | Cypress.RetryStrategyWithModeSpecs>; + "screenshotOnRunFailure": boolean; + "screenshotsFolder": string | false; + "scrollBehavior": Cypress.scrollBehaviorOptions; + "setupNodeEvents": (on, config) => void | Cypress.PluginConfigOptions | Promise; + "slowTestThreshold": number; + "socketId": string | null; + "socketIoCookie": string; + "socketIoRoute": string; + "spec": Cypress.Spec | null; + "specPattern": string | string[]; + "specs": Cypress.Spec[]; + "supportFile": string | false; + "supportFolder": string; + "taskTimeout": number; + "testIsolation": boolean; + "testingType": Cypress.TestingType; + "trashAssetsBeforeRuns": boolean; + "userAgent": string | null; + "version": string; + "video": boolean; + "videoCompression": number | boolean; + "videosFolder": string; + "viewportHeight": number; + "viewportWidth": number; + "waitForAnimations": boolean; + "watchForFileChanges": boolean; +} +``` + +Configures Synpress for use with the Ethereum Wallet Mock. + +This function sets up the necessary configurations and hooks for running +Cypress tests with the Ethereum Wallet Mock. It performs the following tasks: + +1. Filters the available browsers to ensure only Chrome is used. +2. Sets up a 'before:browser:launch' hook to enable debug mode and establish + a Playwright connection. +3. Sets up a 'before:spec' hook to initialize the Ethereum Wallet Mock before + each test spec runs. + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `on` | `PluginEvents` | Cypress plugin event handler | +| `config` | `PluginConfigOptions` | Cypress plugin configuration options | + +## Returns + +```ts +{ + "animationDistanceThreshold": number; + "arch": string; + "autoOpen": boolean; + "baseUrl": string | null; + "blockHosts": string | string[] | null; + "browser": Cypress.Browser; + "browserUrl": string; + "browsers": Cypress.Browser[]; + "chromeWebSecurity": boolean; + "clientCertificates": Cypress.ClientCertificate[]; + "clientRoute": string; + "component": Cypress.ComponentConfigOptions; + "configFile": string; + "cypressBinaryRoot": string; + "cypressEnv": string; + "defaultCommandTimeout": number; + "devServerPublicPathRoute": string; + "downloadsFolder": string; + "e2e": Cypress.EndToEndConfigOptions; + "env": {}; + "excludeSpecPattern": string | string[]; + "execTimeout": number; + "experimentalCspAllowList": boolean | Cypress.experimentalCspAllowedDirectives[]; + "experimentalFetchPolyfill": boolean; + "experimentalInteractiveRunEvents": boolean; + "experimentalMemoryManagement": boolean; + "experimentalModifyObstructiveThirdPartyCode": boolean; + "experimentalSkipDomainInjection": string[] | null; + "experimentalSourceRewriting": boolean; + "experimentalStudio": boolean; + "experimentalWebKitSupport": boolean; + "fileServerFolder": string; + "fixturesFolder": string | false; + "hideCommandLog": boolean; + "hideRunnerUi": boolean; + "hosts": {} | null; + "includeShadowDom": boolean; + "indexHtmlFile": string; + "isInteractive": boolean; + "isNewProject": boolean; + "isTextTerminal": boolean; + "modifyObstructiveCode": boolean; + "morgan": boolean; + "namespace": string; + "numTestsKeptInMemory": number; + "pageLoadTimeout": number; + "parentTestsFolder": string; + "parentTestsFolderDisplay": string; + "platform": "linux" | "darwin" | "win32"; + "port": number | null; + "projectId": string | null; + "projectName": string; + "projectRoot": string; + "protocolEnabled": boolean; + "proxyUrl": string; + "redirectionLimit": number; + "remote": Cypress.RemoteState; + "repoRoot": string | null; + "report": boolean; + "reporter": string; + "reporterOptions": {}; + "reporterRoute": string; + "reporterUrl": string; + "requestTimeout": number; + "resolvedNodePath": string; + "resolvedNodeVersion": string; + "responseTimeout": number; + "retries": Cypress.Nullable; + "runMode": Cypress.Nullable; + } | Cypress.RetryStrategyWithModeSpecs>; + "screenshotOnRunFailure": boolean; + "screenshotsFolder": string | false; + "scrollBehavior": Cypress.scrollBehaviorOptions; + "setupNodeEvents": (on, config) => void | Cypress.PluginConfigOptions | Promise; + "slowTestThreshold": number; + "socketId": string | null; + "socketIoCookie": string; + "socketIoRoute": string; + "spec": Cypress.Spec | null; + "specPattern": string | string[]; + "specs": Cypress.Spec[]; + "supportFile": string | false; + "supportFolder": string; + "taskTimeout": number; + "testIsolation": boolean; + "testingType": Cypress.TestingType; + "trashAssetsBeforeRuns": boolean; + "userAgent": string | null; + "version": string; + "video": boolean; + "videoCompression": number | boolean; + "videosFolder": string; + "viewportHeight": number; + "viewportWidth": number; + "waitForAnimations": boolean; + "watchForFileChanges": boolean; +} +``` + +Modified Cypress configuration + +| Member | Type | +| :------ | :------ | +| `animationDistanceThreshold` | `number` | +| `arch` | `string` | +| `autoOpen` | `boolean` | +| `baseUrl` | `string` \| `null` | +| `blockHosts` | `string` \| `string`[] \| `null` | +| `browser` | `Cypress.Browser` | +| `browserUrl` | `string` | +| `browsers` | `Cypress.Browser`[] | +| `chromeWebSecurity` | `boolean` | +| `clientCertificates` | `Cypress.ClientCertificate`[] | +| `clientRoute` | `string` | +| `component` | `Cypress.ComponentConfigOptions`\<`any`\> | +| `configFile` | `string` | +| `cypressBinaryRoot` | `string` | +| `cypressEnv` | `string` | +| `defaultCommandTimeout` | `number` | +| `devServerPublicPathRoute` | `string` | +| `downloadsFolder` | `string` | +| `e2e` | `Cypress.EndToEndConfigOptions` | +| `env` | \{\} | +| `excludeSpecPattern` | `string` \| `string`[] | +| `execTimeout` | `number` | +| `experimentalCspAllowList` | `boolean` \| `Cypress.experimentalCspAllowedDirectives`[] | +| `experimentalFetchPolyfill` | `boolean` | +| `experimentalInteractiveRunEvents` | `boolean` | +| `experimentalMemoryManagement` | `boolean` | +| `experimentalModifyObstructiveThirdPartyCode` | `boolean` | +| `experimentalSkipDomainInjection` | `string`[] \| `null` | +| `experimentalSourceRewriting` | `boolean` | +| `experimentalStudio` | `boolean` | +| `experimentalWebKitSupport` | `boolean` | +| `fileServerFolder` | `string` | +| `fixturesFolder` | `string` \| `false` | +| `hideCommandLog` | `boolean` | +| `hideRunnerUi` | `boolean` | +| `hosts` | \{\} \| `null` | +| `includeShadowDom` | `boolean` | +| `indexHtmlFile` | `string` | +| `isInteractive` | `boolean` | +| `isNewProject` | `boolean` | +| `isTextTerminal` | `boolean` | +| `modifyObstructiveCode` | `boolean` | +| `morgan` | `boolean` | +| `namespace` | `string` | +| `numTestsKeptInMemory` | `number` | +| `pageLoadTimeout` | `number` | +| `parentTestsFolder` | `string` | +| `parentTestsFolderDisplay` | `string` | +| `platform` | `"linux"` \| `"darwin"` \| `"win32"` | +| `port` | `number` \| `null` | +| `projectId` | `string` \| `null` | +| `projectName` | `string` | +| `projectRoot` | `string` | +| `protocolEnabled` | `boolean` | +| `proxyUrl` | `string` | +| `redirectionLimit` | `number` | +| `remote` | `Cypress.RemoteState` | +| `repoRoot` | `string` \| `null` | +| `report` | `boolean` | +| `reporter` | `string` | +| `reporterOptions` | \{\} | +| `reporterRoute` | `string` | +| `reporterUrl` | `string` | +| `requestTimeout` | `number` | +| `resolvedNodePath` | `string` | +| `resolvedNodeVersion` | `string` | +| `responseTimeout` | `number` | +| `retries` | `Cypress.Nullable`\<`number` \| \{ + `"openMode"`: `Cypress.Nullable`\<`number`\>; + `"runMode"`: `Cypress.Nullable`\<`number`\>; + \} \| `Cypress.RetryStrategyWithModeSpecs`\> | +| `screenshotOnRunFailure` | `boolean` | +| `screenshotsFolder` | `string` \| `false` | +| `scrollBehavior` | `Cypress.scrollBehaviorOptions` | +| `setupNodeEvents` | (`on`, `config`) => `void` \| `Cypress.PluginConfigOptions` \| `Promise`\<`void` \| `Cypress.PluginConfigOptions`\> | +| `slowTestThreshold` | `number` | +| `socketId` | `string` \| `null` | +| `socketIoCookie` | `string` | +| `socketIoRoute` | `string` | +| `spec` | `Cypress.Spec` \| `null` | +| `specPattern` | `string` \| `string`[] | +| `specs` | `Cypress.Spec`[] | +| `supportFile` | `string` \| `false` | +| `supportFolder` | `string` | +| `taskTimeout` | `number` | +| `testIsolation` | `boolean` | +| `testingType` | `Cypress.TestingType` | +| `trashAssetsBeforeRuns` | `boolean` | +| `userAgent` | `string` \| `null` | +| `version` | `string` | +| `video` | `boolean` | +| `videoCompression` | `number` \| `boolean` | +| `videosFolder` | `string` | +| `viewportHeight` | `number` | +| `viewportWidth` | `number` | +| `waitForAnimations` | `boolean` | +| `watchForFileChanges` | `boolean` | + +## Throws + +Error If no Chrome browser is found in the configuration diff --git a/docs/api/cypress/functions/configureSynpressForMetaMask.md b/docs/api/cypress/functions/configureSynpressForMetaMask.md new file mode 100644 index 000000000..c64912712 --- /dev/null +++ b/docs/api/cypress/functions/configureSynpressForMetaMask.md @@ -0,0 +1,350 @@ +# Function: configureSynpressForMetaMask() + +```ts +function configureSynpressForMetaMask( + on, + config, + importDefaultWallet?): { + "animationDistanceThreshold": number; + "arch": string; + "autoOpen": boolean; + "baseUrl": string | null; + "blockHosts": string | string[] | null; + "browser": Cypress.Browser; + "browserUrl": string; + "browsers": Cypress.Browser[]; + "chromeWebSecurity": boolean; + "clientCertificates": Cypress.ClientCertificate[]; + "clientRoute": string; + "component": Cypress.ComponentConfigOptions; + "configFile": string; + "cypressBinaryRoot": string; + "cypressEnv": string; + "defaultCommandTimeout": number; + "devServerPublicPathRoute": string; + "downloadsFolder": string; + "e2e": Cypress.EndToEndConfigOptions; + "env": {}; + "excludeSpecPattern": string | string[]; + "execTimeout": number; + "experimentalCspAllowList": boolean | Cypress.experimentalCspAllowedDirectives[]; + "experimentalFetchPolyfill": boolean; + "experimentalInteractiveRunEvents": boolean; + "experimentalMemoryManagement": boolean; + "experimentalModifyObstructiveThirdPartyCode": boolean; + "experimentalSkipDomainInjection": string[] | null; + "experimentalSourceRewriting": boolean; + "experimentalStudio": boolean; + "experimentalWebKitSupport": boolean; + "fileServerFolder": string; + "fixturesFolder": string | false; + "hideCommandLog": boolean; + "hideRunnerUi": boolean; + "hosts": {} | null; + "includeShadowDom": boolean; + "indexHtmlFile": string; + "isInteractive": boolean; + "isNewProject": boolean; + "isTextTerminal": boolean; + "modifyObstructiveCode": boolean; + "morgan": boolean; + "namespace": string; + "numTestsKeptInMemory": number; + "pageLoadTimeout": number; + "parentTestsFolder": string; + "parentTestsFolderDisplay": string; + "platform": "darwin" | "linux" | "win32"; + "port": number | null; + "projectId": string | null; + "projectName": string; + "projectRoot": string; + "protocolEnabled": boolean; + "proxyUrl": string; + "redirectionLimit": number; + "remote": Cypress.RemoteState; + "repoRoot": string | null; + "report": boolean; + "reporter": string; + "reporterOptions": {}; + "reporterRoute": string; + "reporterUrl": string; + "requestTimeout": number; + "resolvedNodePath": string; + "resolvedNodeVersion": string; + "responseTimeout": number; + "retries": Cypress.Nullable; + "runMode": Cypress.Nullable; + } | Cypress.RetryStrategyWithModeSpecs>; + "screenshotOnRunFailure": boolean; + "screenshotsFolder": string | false; + "scrollBehavior": Cypress.scrollBehaviorOptions; + "setupNodeEvents": (on, config) => void | Cypress.PluginConfigOptions | Promise; + "slowTestThreshold": number; + "socketId": string | null; + "socketIoCookie": string; + "socketIoRoute": string; + "spec": Cypress.Spec | null; + "specPattern": string | string[]; + "specs": Cypress.Spec[]; + "supportFile": string | false; + "supportFolder": string; + "taskTimeout": number; + "testIsolation": boolean; + "testingType": Cypress.TestingType; + "trashAssetsBeforeRuns": boolean; + "userAgent": string | null; + "version": string; + "video": boolean; + "videoCompression": number | boolean; + "videosFolder": string; + "viewportHeight": number; + "viewportWidth": number; + "waitForAnimations": boolean; + "watchForFileChanges": boolean; +} +``` + +Configures Synpress for use with MetaMask. + +This function sets up the necessary configurations and hooks for running +Cypress tests with MetaMask. + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `on` | `PluginEvents` | Cypress plugin event handler | +| `config` | `PluginConfigOptions` | Cypress plugin configuration options | +| `importDefaultWallet`? | `boolean` | Whether to import the default wallet | + +## Returns + +```ts +{ + "animationDistanceThreshold": number; + "arch": string; + "autoOpen": boolean; + "baseUrl": string | null; + "blockHosts": string | string[] | null; + "browser": Cypress.Browser; + "browserUrl": string; + "browsers": Cypress.Browser[]; + "chromeWebSecurity": boolean; + "clientCertificates": Cypress.ClientCertificate[]; + "clientRoute": string; + "component": Cypress.ComponentConfigOptions; + "configFile": string; + "cypressBinaryRoot": string; + "cypressEnv": string; + "defaultCommandTimeout": number; + "devServerPublicPathRoute": string; + "downloadsFolder": string; + "e2e": Cypress.EndToEndConfigOptions; + "env": {}; + "excludeSpecPattern": string | string[]; + "execTimeout": number; + "experimentalCspAllowList": boolean | Cypress.experimentalCspAllowedDirectives[]; + "experimentalFetchPolyfill": boolean; + "experimentalInteractiveRunEvents": boolean; + "experimentalMemoryManagement": boolean; + "experimentalModifyObstructiveThirdPartyCode": boolean; + "experimentalSkipDomainInjection": string[] | null; + "experimentalSourceRewriting": boolean; + "experimentalStudio": boolean; + "experimentalWebKitSupport": boolean; + "fileServerFolder": string; + "fixturesFolder": string | false; + "hideCommandLog": boolean; + "hideRunnerUi": boolean; + "hosts": {} | null; + "includeShadowDom": boolean; + "indexHtmlFile": string; + "isInteractive": boolean; + "isNewProject": boolean; + "isTextTerminal": boolean; + "modifyObstructiveCode": boolean; + "morgan": boolean; + "namespace": string; + "numTestsKeptInMemory": number; + "pageLoadTimeout": number; + "parentTestsFolder": string; + "parentTestsFolderDisplay": string; + "platform": "darwin" | "linux" | "win32"; + "port": number | null; + "projectId": string | null; + "projectName": string; + "projectRoot": string; + "protocolEnabled": boolean; + "proxyUrl": string; + "redirectionLimit": number; + "remote": Cypress.RemoteState; + "repoRoot": string | null; + "report": boolean; + "reporter": string; + "reporterOptions": {}; + "reporterRoute": string; + "reporterUrl": string; + "requestTimeout": number; + "resolvedNodePath": string; + "resolvedNodeVersion": string; + "responseTimeout": number; + "retries": Cypress.Nullable; + "runMode": Cypress.Nullable; + } | Cypress.RetryStrategyWithModeSpecs>; + "screenshotOnRunFailure": boolean; + "screenshotsFolder": string | false; + "scrollBehavior": Cypress.scrollBehaviorOptions; + "setupNodeEvents": (on, config) => void | Cypress.PluginConfigOptions | Promise; + "slowTestThreshold": number; + "socketId": string | null; + "socketIoCookie": string; + "socketIoRoute": string; + "spec": Cypress.Spec | null; + "specPattern": string | string[]; + "specs": Cypress.Spec[]; + "supportFile": string | false; + "supportFolder": string; + "taskTimeout": number; + "testIsolation": boolean; + "testingType": Cypress.TestingType; + "trashAssetsBeforeRuns": boolean; + "userAgent": string | null; + "version": string; + "video": boolean; + "videoCompression": number | boolean; + "videosFolder": string; + "viewportHeight": number; + "viewportWidth": number; + "waitForAnimations": boolean; + "watchForFileChanges": boolean; +} +``` + +Modified Cypress configuration + +| Member | Type | +| :------ | :------ | +| `animationDistanceThreshold` | `number` | +| `arch` | `string` | +| `autoOpen` | `boolean` | +| `baseUrl` | `string` \| `null` | +| `blockHosts` | `string` \| `string`[] \| `null` | +| `browser` | `Cypress.Browser` | +| `browserUrl` | `string` | +| `browsers` | `Cypress.Browser`[] | +| `chromeWebSecurity` | `boolean` | +| `clientCertificates` | `Cypress.ClientCertificate`[] | +| `clientRoute` | `string` | +| `component` | `Cypress.ComponentConfigOptions`\<`any`\> | +| `configFile` | `string` | +| `cypressBinaryRoot` | `string` | +| `cypressEnv` | `string` | +| `defaultCommandTimeout` | `number` | +| `devServerPublicPathRoute` | `string` | +| `downloadsFolder` | `string` | +| `e2e` | `Cypress.EndToEndConfigOptions` | +| `env` | \{\} | +| `excludeSpecPattern` | `string` \| `string`[] | +| `execTimeout` | `number` | +| `experimentalCspAllowList` | `boolean` \| `Cypress.experimentalCspAllowedDirectives`[] | +| `experimentalFetchPolyfill` | `boolean` | +| `experimentalInteractiveRunEvents` | `boolean` | +| `experimentalMemoryManagement` | `boolean` | +| `experimentalModifyObstructiveThirdPartyCode` | `boolean` | +| `experimentalSkipDomainInjection` | `string`[] \| `null` | +| `experimentalSourceRewriting` | `boolean` | +| `experimentalStudio` | `boolean` | +| `experimentalWebKitSupport` | `boolean` | +| `fileServerFolder` | `string` | +| `fixturesFolder` | `string` \| `false` | +| `hideCommandLog` | `boolean` | +| `hideRunnerUi` | `boolean` | +| `hosts` | \{\} \| `null` | +| `includeShadowDom` | `boolean` | +| `indexHtmlFile` | `string` | +| `isInteractive` | `boolean` | +| `isNewProject` | `boolean` | +| `isTextTerminal` | `boolean` | +| `modifyObstructiveCode` | `boolean` | +| `morgan` | `boolean` | +| `namespace` | `string` | +| `numTestsKeptInMemory` | `number` | +| `pageLoadTimeout` | `number` | +| `parentTestsFolder` | `string` | +| `parentTestsFolderDisplay` | `string` | +| `platform` | `"darwin"` \| `"linux"` \| `"win32"` | +| `port` | `number` \| `null` | +| `projectId` | `string` \| `null` | +| `projectName` | `string` | +| `projectRoot` | `string` | +| `protocolEnabled` | `boolean` | +| `proxyUrl` | `string` | +| `redirectionLimit` | `number` | +| `remote` | `Cypress.RemoteState` | +| `repoRoot` | `string` \| `null` | +| `report` | `boolean` | +| `reporter` | `string` | +| `reporterOptions` | \{\} | +| `reporterRoute` | `string` | +| `reporterUrl` | `string` | +| `requestTimeout` | `number` | +| `resolvedNodePath` | `string` | +| `resolvedNodeVersion` | `string` | +| `responseTimeout` | `number` | +| `retries` | `Cypress.Nullable`\<`number` \| \{ + `"openMode"`: `Cypress.Nullable`\<`number`\>; + `"runMode"`: `Cypress.Nullable`\<`number`\>; + \} \| `Cypress.RetryStrategyWithModeSpecs`\> | +| `screenshotOnRunFailure` | `boolean` | +| `screenshotsFolder` | `string` \| `false` | +| `scrollBehavior` | `Cypress.scrollBehaviorOptions` | +| `setupNodeEvents` | (`on`, `config`) => `void` \| `Cypress.PluginConfigOptions` \| `Promise`\<`void` \| `Cypress.PluginConfigOptions`\> | +| `slowTestThreshold` | `number` | +| `socketId` | `string` \| `null` | +| `socketIoCookie` | `string` | +| `socketIoRoute` | `string` | +| `spec` | `Cypress.Spec` \| `null` | +| `specPattern` | `string` \| `string`[] | +| `specs` | `Cypress.Spec`[] | +| `supportFile` | `string` \| `false` | +| `supportFolder` | `string` | +| `taskTimeout` | `number` | +| `testIsolation` | `boolean` | +| `testingType` | `Cypress.TestingType` | +| `trashAssetsBeforeRuns` | `boolean` | +| `userAgent` | `string` \| `null` | +| `version` | `string` | +| `video` | `boolean` | +| `videoCompression` | `number` \| `boolean` | +| `videosFolder` | `string` | +| `viewportHeight` | `number` | +| `viewportWidth` | `number` | +| `waitForAnimations` | `boolean` | +| `watchForFileChanges` | `boolean` | + +## Throws + +Error If no Chrome browser is found in the configuration + +## Remarks + +This function performs the following tasks: + +1. Filters the available browsers to ensure only Chrome is used. +2. Sets up a 'before:browser:launch' hook to enable debug mode, establish + a Playwright connection, and initialize MetaMask. +3. Sets up a 'before:spec' hook to import the MetaMask wallet before + each test spec runs. +4. Provides task handlers for various MetaMask-related operations. + +## Example + +```typescript +import { configureSynpress } from './configureSynpress'; + +export default (on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions) => { + return configureSynpress(on, config); +}; +``` diff --git a/docs/api/cypress/functions/initMetaMask.md b/docs/api/cypress/functions/initMetaMask.md new file mode 100644 index 000000000..f7b5a7078 --- /dev/null +++ b/docs/api/cypress/functions/initMetaMask.md @@ -0,0 +1,29 @@ +# Function: initMetaMask() + +```ts +function initMetaMask(): Promise<{ + "browserArgs": string[]; + "extensions": string[]; +}> +``` + +Initializes MetaMask for Cypress tests. + +This function prepares the MetaMask extension for use in Cypress tests. +It sets up the necessary browser arguments and extension paths. + +## Returns + +`Promise`\<\{ + `"browserArgs"`: `string`[]; + `"extensions"`: `string`[]; + \}\> + +An object containing the extension path and browser arguments. + +| Member | Type | +| :------ | :------ | +| `browserArgs` | `string`[] | +| `extensions` | `string`[] | + +## Async diff --git a/docs/api/cypress/index.md b/docs/api/cypress/index.md new file mode 100644 index 000000000..30ad88589 --- /dev/null +++ b/docs/api/cypress/index.md @@ -0,0 +1,10 @@ +# cypress + +## Index + +| Member | Description | +| :------ | :------ | +| [MetaMask](classes/MetaMask.md) | MetaMask class for interacting with the MetaMask extension in Cypress tests. | +| [configureSynpressForEthereumWalletMock](functions/configureSynpressForEthereumWalletMock.md) | Configures Synpress for use with the Ethereum Wallet Mock. | +| [configureSynpressForMetaMask](functions/configureSynpressForMetaMask.md) | Configures Synpress for use with MetaMask. | +| [initMetaMask](functions/initMetaMask.md) | Initializes MetaMask for Cypress tests. | diff --git a/docs/api/cypress/support/functions/mockEthereum.md b/docs/api/cypress/support/functions/mockEthereum.md new file mode 100644 index 000000000..c44407445 --- /dev/null +++ b/docs/api/cypress/support/functions/mockEthereum.md @@ -0,0 +1,36 @@ +# Function: mockEthereum() + +```ts +function mockEthereum(): void +``` + +Mock Ethereum Environment for Cypress Tests + +This module provides a function to set up a mocked Ethereum environment +for Cypress tests. It utilizes the Web3Mock library to simulate Ethereum +blockchain interactions and MetaMask wallet behavior. + +## Returns + +`void` + +## Remarks + +Key features: +- Mocks the Ethereum blockchain environment +- Simulates MetaMask wallet functionality +- Automatically applied before each test suite + +This function is typically called in the Cypress support file or test +setup to ensure all tests run in a controlled, mocked Ethereum environment. +It allows for consistent and predictable testing of Ethereum-based +applications without the need for a real blockchain or wallet. + +## Example + +```typescript +// In your Cypress support file +import { mockEthereum } from '@synthetixio/synpress'; + +mockEthereum(); +``` diff --git a/docs/api/cypress/support/functions/synpressCommandsForEthereumWalletMock.md b/docs/api/cypress/support/functions/synpressCommandsForEthereumWalletMock.md new file mode 100644 index 000000000..1dd0b0022 --- /dev/null +++ b/docs/api/cypress/support/functions/synpressCommandsForEthereumWalletMock.md @@ -0,0 +1,22 @@ +# Function: synpressCommandsForEthereumWalletMock() + +```ts +function synpressCommandsForEthereumWalletMock(): void +``` + +Initializes Synpress commands for the Ethereum Wallet Mock. + +This function adds custom Cypress commands for interacting with a mocked Ethereum wallet. +These commands include wallet import, account management, network operations, and dApp connections. + +## Returns + +`void` + +## Example + +```typescript +import { synpressCommandsForEthereumWalletMock } from '@synthetixio/synpress'; + +synpressCommandsForEthereumWalletMock(); +``` diff --git a/docs/api/cypress/support/functions/synpressCommandsForMetaMask.md b/docs/api/cypress/support/functions/synpressCommandsForMetaMask.md new file mode 100644 index 000000000..b79edc8be --- /dev/null +++ b/docs/api/cypress/support/functions/synpressCommandsForMetaMask.md @@ -0,0 +1,11 @@ +# Function: synpressCommandsForMetaMask() + +```ts +function synpressCommandsForMetaMask(): void +``` + +Initializes Synpress commands for MetaMask + +## Returns + +`void` diff --git a/docs/api/cypress/support/index.md b/docs/api/cypress/support/index.md new file mode 100644 index 000000000..5bc7d7cc1 --- /dev/null +++ b/docs/api/cypress/support/index.md @@ -0,0 +1,9 @@ +# cypress/support + +## Index + +| Member | Description | +| :------ | :------ | +| [mockEthereum](functions/mockEthereum.md) | Mock Ethereum Environment for Cypress Tests | +| [synpressCommandsForEthereumWalletMock](functions/synpressCommandsForEthereumWalletMock.md) | Initializes Synpress commands for the Ethereum Wallet Mock. | +| [synpressCommandsForMetaMask](functions/synpressCommandsForMetaMask.md) | Initializes Synpress commands for MetaMask | diff --git a/docs/api/index.md b/docs/api/index.md index ca49f8a49..af6738c51 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -2,5 +2,7 @@ | Member | Description | | :------ | :------ | -| [defineWalletSetup](functions/defineWalletSetup.md) | This function is used to define how a wallet should be set up. | -| [testWithSynpress](functions/testWithSynpress.md) | - | +| [cypress](cypress/index.md) | - | +| [cypress/support](cypress/support/index.md) | - | +| [index](index/index.md) | - | +| [playwright](playwright/index.md) | - | diff --git a/docs/api/functions/defineWalletSetup.md b/docs/api/index/functions/defineWalletSetup.md similarity index 100% rename from docs/api/functions/defineWalletSetup.md rename to docs/api/index/functions/defineWalletSetup.md diff --git a/docs/api/functions/testWithSynpress.md b/docs/api/index/functions/testWithSynpress.md similarity index 100% rename from docs/api/functions/testWithSynpress.md rename to docs/api/index/functions/testWithSynpress.md diff --git a/docs/api/index/index.md b/docs/api/index/index.md new file mode 100644 index 000000000..007b85964 --- /dev/null +++ b/docs/api/index/index.md @@ -0,0 +1,8 @@ +# index + +## Index + +| Member | Description | +| :------ | :------ | +| [defineWalletSetup](functions/defineWalletSetup.md) | This function is used to define how a wallet should be set up. | +| [testWithSynpress](functions/testWithSynpress.md) | - | diff --git a/docs/api/playwright/classes/EthereumWalletMock.md b/docs/api/playwright/classes/EthereumWalletMock.md new file mode 100644 index 000000000..217a83ec8 --- /dev/null +++ b/docs/api/playwright/classes/EthereumWalletMock.md @@ -0,0 +1,258 @@ +# Class: EthereumWalletMock + +Mock implementation of an Ethereum wallet for testing purposes. +Simulates wallet behavior in a controlled environment, allowing for consistent +and reproducible tests without relying on actual blockchain interactions. + +## Extends + +- `EthereumWalletMockAbstract` + +## Constructors + +### new EthereumWalletMock() + +```ts +new EthereumWalletMock(page, wallet?): EthereumWalletMock +``` + +Creates an instance of EthereumWalletMock. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `page` | `Page` | The Playwright Page object to interact with. | +| `wallet`? | `WalletMock` | The type of wallet to mock. | + +#### Returns + +[`EthereumWalletMock`](EthereumWalletMock.md) + +#### Overrides + +`EthereumWalletMockAbstract.constructor` + +## Properties + +| Property | Type | Description | Inherited from | +| :------ | :------ | :------ | :------ | +| `page` | `Page` | The Playwright Page object to interact with. | - | +| `seedPhrase` | `undefined` \| `string` | - | `EthereumWalletMockAbstract.seedPhrase` | +| `wallet` | `WalletMock` | - | `EthereumWalletMockAbstract.wallet` | + +## Methods + +### addNetwork() + +```ts +addNetwork(network): Promise +``` + +Adds a new network. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `network` | `Network` | The network object to use for adding the new network. | + +#### Returns + +`Promise`\<`void`\> + +A promise that resolves when the network is added. + +#### Overrides + +`EthereumWalletMockAbstract.addNetwork` + +*** + +### addNewAccount() + +```ts +addNewAccount(): Promise +``` + +Adds a new account based on the initially imported seed phrase. + +#### Returns + +`Promise`\<`void`\> + +A promise that resolves when the new account is added. + +#### Overrides + +`EthereumWalletMockAbstract.addNewAccount` + +*** + +### connectToDapp() + +```ts +connectToDapp(wallet?): Promise +``` + +Connects wallet to the dapp. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `wallet`? | `WalletMock` | The wallet to connect to the dapp. | + +#### Returns + +`Promise`\<`void`\> + +A promise that resolves when the wallet is connected to the dapp. + +#### Overrides + +`EthereumWalletMockAbstract.connectToDapp` + +*** + +### getAccountAddress() + +```ts +getAccountAddress(): Promise +``` + +Retrieves the current account address. + +#### Returns + +`Promise`\<`undefined` \| \`0x$\{string\}\`\> + +A promise that resolves to the current account address. + +#### Overrides + +`EthereumWalletMockAbstract.getAccountAddress` + +*** + +### getAllAccounts() + +```ts +getAllAccounts(): Promise +``` + +Retrieves all account addresses. + +#### Returns + +`Promise`\<`undefined` \| \`0x$\{string\}\`[]\> + +A promise that resolves to an array of account addresses. + +#### Overrides + +`EthereumWalletMockAbstract.getAllAccounts` + +*** + +### importWallet() + +```ts +importWallet(seedPhrase): Promise +``` + +Imports a wallet using the given seed phrase. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `seedPhrase` | `string` | The seed phrase to import. | + +#### Returns + +`Promise`\<`void`\> + +A promise that resolves when the wallet is imported. + +#### Overrides + +`EthereumWalletMockAbstract.importWallet` + +*** + +### importWalletFromPrivateKey() + +```ts +importWalletFromPrivateKey(privateKey): Promise +``` + +Imports a wallet using the given private key. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `privateKey` | \`0x$\{string\}\` | The private key to import. | + +#### Returns + +`Promise`\<`void`\> + +A promise that resolves when the wallet is imported. + +#### Overrides + +`EthereumWalletMockAbstract.importWalletFromPrivateKey` + +*** + +### switchAccount() + +```ts +switchAccount(accountAddress): Promise +``` + +Switches to the account with the given address. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `accountAddress` | `string` | The address of the account to switch to. | + +#### Returns + +`Promise`\<`void`\> + +A promise that resolves when the account switch is complete. + +#### Overrides + +`EthereumWalletMockAbstract.switchAccount` + +*** + +### switchNetwork() + +```ts +switchNetwork(networkName): Promise +``` + +Switches to the network with the given name. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `networkName` | `string` | The name of the network to switch to. | + +#### Returns + +`Promise`\<`void`\> + +A promise that resolves when the network switch is complete. + +#### Overrides + +`EthereumWalletMockAbstract.switchNetwork` diff --git a/docs/api/playwright/classes/MetaMask.md b/docs/api/playwright/classes/MetaMask.md new file mode 100644 index 000000000..5c706026e --- /dev/null +++ b/docs/api/playwright/classes/MetaMask.md @@ -0,0 +1,855 @@ +# Class: MetaMask + +MetaMask class for interacting with the MetaMask extension in Playwright tests. + +This class provides methods to perform various operations on the MetaMask extension, +such as importing wallets, switching networks, confirming transactions, and more. + +## Extends + +- `MetaMaskAbstract` + +## Constructors + +### new MetaMask() + +```ts +new MetaMask( + context, + page, + password, + extensionId?): MetaMask +``` + +Creates an instance of MetaMask. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `context` | `BrowserContext` | The Playwright BrowserContext in which the MetaMask extension is running. | +| `page` | `Page` | The Playwright Page object representing the MetaMask extension's main page. | +| `password` | `string` | The password for the MetaMask wallet. | +| `extensionId`? | `string` | The ID of the MetaMask extension. Optional if no interaction with dapps is required. | + +#### Returns + +[`MetaMask`](MetaMask.md) + +#### Overrides + +`MetaMaskAbstract.constructor` + +## Properties + +| Property | Modifier | Type | Description | Overrides | +| :------ | :------ | :------ | :------ | :------ | +| `context` | `readonly` | `BrowserContext` | - | - | +| `crashPage` | `readonly` | `CrashPage` | This property can be used to access selectors for the crash page. | - | +| `extensionId?` | `readonly` | `string` | - | `MetaMaskAbstract.extensionId` | +| `homePage` | `readonly` | `HomePage` | This property can be used to access selectors for the home page. | - | +| `lockPage` | `readonly` | `LockPage` | This property can be used to access selectors for the lock page. | - | +| `notificationPage` | `readonly` | `NotificationPage` | This property can be used to access selectors for the notification page. | - | +| `onboardingPage` | `readonly` | `OnboardingPage` | This property can be used to access selectors for the onboarding page. | - | +| `page` | `readonly` | `Page` | - | - | +| `password` | `readonly` | `string` | - | `MetaMaskAbstract.password` | +| `settingsPage` | `readonly` | `SettingsPage` | This property can be used to access selectors for the settings page. | - | + +## Methods + +### addNetwork() + +```ts +addNetwork(network): Promise +``` + +Adds a new network to MetaMask. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `network` | `object` | The network configuration to add. | +| `network.blockExplorerUrl`? | `string` | - | +| `network.chainId` | `number` | - | +| `network.name` | `string` | - | +| `network.rpcUrl` | `string` | - | +| `network.symbol` | `string` | - | + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.addNetwork` + +*** + +### addNewAccount() + +```ts +addNewAccount(accountName): Promise +``` + +Adds a new account with the given name. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `accountName` | `string` | The name for the new account. | + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.addNewAccount` + +*** + +### addNewToken() + +```ts +addNewToken(): Promise +``` + +Adds a new token. + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.addNewToken` + +#### Throws + +If extensionId is not set. + +*** + +### approveNewNetwork() + +```ts +approveNewNetwork(): Promise +``` + +Approves adding a new network. + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.approveNewNetwork` + +#### Throws + +If extensionId is not set. + +*** + +### approveSwitchNetwork() + +```ts +approveSwitchNetwork(): Promise +``` + +Approves switching to a new network. + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.approveSwitchNetwork` + +#### Throws + +If extensionId is not set. + +*** + +### approveTokenPermission() + +```ts +approveTokenPermission(options?): Promise +``` + +Approves a token permission request. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `options`? | `object` | Optional settings for the approval. | +| `options.gasSetting`? | \| `"low"` \| `"market"` \| `"aggressive"` \| `"site"` \| \{ `"gasLimit"`: `number`; `"maxBaseFee"`: `number`; `"priorityFee"`: `number`; \} | - | +| `options.spendLimit`? | `number` \| `"max"` | - | + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.approveTokenPermission` + +#### Throws + +If extensionId is not set. + +*** + +### closeTransactionDetails() + +```ts +closeTransactionDetails(): Promise +``` + +Closes the transaction details view. + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.closeTransactionDetails` + +*** + +### confirmSignature() + +```ts +confirmSignature(): Promise +``` + +Confirms a signature request. + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.confirmSignature` + +#### Throws + +If extensionId is not set. + +*** + +### confirmSignatureWithRisk() + +```ts +confirmSignatureWithRisk(): Promise +``` + +Confirms a signature request with risk. + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.confirmSignatureWithRisk` + +#### Throws + +If extensionId is not set. + +*** + +### confirmTransaction() + +```ts +confirmTransaction(options?): Promise +``` + +Confirms a transaction. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `options`? | `object` | Optional gas settings for the transaction. | +| `options.gasSetting`? | \| `"low"` \| `"market"` \| `"aggressive"` \| `"site"` \| \{ `"gasLimit"`: `number`; `"maxBaseFee"`: `number`; `"priorityFee"`: `number`; \} | - | + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.confirmTransaction` + +#### Throws + +If extensionId is not set. + +*** + +### confirmTransactionAndWaitForMining() + +```ts +confirmTransactionAndWaitForMining(options?): Promise +``` + +Confirms a transaction and waits for it to be mined. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `options`? | `object` | Optional gas settings for the transaction. | +| `options.gasSetting`? | \| `"low"` \| `"market"` \| `"aggressive"` \| `"site"` \| \{ `"gasLimit"`: `number`; `"maxBaseFee"`: `number`; `"priorityFee"`: `number`; \} | - | + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.confirmTransactionAndWaitForMining` + +#### Throws + +If extensionId is not set. + +*** + +### connectToDapp() + +```ts +connectToDapp(accounts?): Promise +``` + +Connects MetaMask to a dapp. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `accounts`? | `string`[] | Optional array of account addresses to connect. | + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.connectToDapp` + +#### Throws + +If extensionId is not set. + +*** + +### decrypt() + +```ts +decrypt(): Promise +``` + +Decrypts a message. + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.decrypt` + +#### Throws + +If extensionId is not set. + +*** + +### disableEthSign() + +```ts +disableEthSign(): Promise +``` + +Disables eth_sign. + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.disableEthSign` + +*** + +### getAccountAddress() + +```ts +getAccountAddress(): Promise +``` + +Gets the address of the currently selected account. + +#### Returns + +`Promise`\<`string`\> + +The account address. + +#### Overrides + +`MetaMaskAbstract.getAccountAddress` + +*** + +### goBackToHomePage() + +```ts +goBackToHomePage(): Promise +``` + +Navigates back to the home page. + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.goBackToHomePage` + +*** + +### importWallet() + +```ts +importWallet(seedPhrase): Promise +``` + +Imports a wallet using the given seed phrase. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `seedPhrase` | `string` | The seed phrase to import. | + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.importWallet` + +*** + +### importWalletFromPrivateKey() + +```ts +importWalletFromPrivateKey(privateKey): Promise +``` + +Imports a wallet using the given private key. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `privateKey` | `string` | The private key to import. | + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.importWalletFromPrivateKey` + +*** + +### lock() + +```ts +lock(): Promise +``` + +Locks the MetaMask wallet. + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.lock` + +*** + +### openSettings() + +```ts +openSettings(): Promise +``` + +Opens the settings page. + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.openSettings` + +*** + +### openSidebarMenu() + +```ts +openSidebarMenu(menu): Promise +``` + +Opens a specific sidebar menu in the settings. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `menu` | `SettingsSidebarMenus` | The menu to open. | + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.openSidebarMenu` + +*** + +### openTransactionDetails() + +```ts +openTransactionDetails(txIndex): Promise +``` + +Opens the details of a specific transaction. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `txIndex` | `number` | The index of the transaction to open. | + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.openTransactionDetails` + +*** + +### providePublicEncryptionKey() + +```ts +providePublicEncryptionKey(): Promise +``` + +Provides a public encryption key. + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.providePublicEncryptionKey` + +#### Throws + +If extensionId is not set. + +*** + +### rejectNewNetwork() + +```ts +rejectNewNetwork(): Promise +``` + +Rejects adding a new network. + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.rejectNewNetwork` + +#### Throws + +If extensionId is not set. + +*** + +### rejectSignature() + +```ts +rejectSignature(): Promise +``` + +Rejects a signature request. + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.rejectSignature` + +#### Throws + +If extensionId is not set. + +*** + +### rejectSwitchNetwork() + +```ts +rejectSwitchNetwork(): Promise +``` + +Rejects switching to a new network. + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.rejectSwitchNetwork` + +#### Throws + +If extensionId is not set. + +*** + +### rejectTokenPermission() + +```ts +rejectTokenPermission(): Promise +``` + +Rejects a token permission request. + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.rejectTokenPermission` + +#### Throws + +If extensionId is not set. + +*** + +### rejectTransaction() + +```ts +rejectTransaction(): Promise +``` + +Rejects a transaction. + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.rejectTransaction` + +#### Throws + +If extensionId is not set. + +*** + +### renameAccount() + +```ts +renameAccount(currentAccountName, newAccountName): Promise +``` + +Renames the currently selected account. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `currentAccountName` | `string` | The current account name. | +| `newAccountName` | `string` | The new name for the account. | + +#### Returns + +`Promise`\<`void`\> + +*** + +### resetAccount() + +```ts +resetAccount(): Promise +``` + +Resets the account. + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.resetAccount` + +*** + +### switchAccount() + +```ts +switchAccount(accountName): Promise +``` + +Switches to the account with the given name. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `accountName` | `string` | The name of the account to switch to. | + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.switchAccount` + +*** + +### switchNetwork() + +```ts +switchNetwork(networkName, isTestnet?): Promise +``` + +Switches to the specified network. + +#### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `networkName` | `string` | The name of the network to switch to. | +| `isTestnet`? | `boolean` | Whether the network is a testnet. Default is false. | + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.switchNetwork` + +*** + +### toggleDismissSecretRecoveryPhraseReminder() + +```ts +toggleDismissSecretRecoveryPhraseReminder(): Promise +``` + +Toggles the dismissal of the secret recovery phrase reminder. + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.toggleDismissSecretRecoveryPhraseReminder` + +*** + +### toggleShowTestNetworks() + +```ts +toggleShowTestNetworks(): Promise +``` + +Toggles the display of test networks. + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.toggleShowTestNetworks` + +*** + +### unlock() + +```ts +unlock(): Promise +``` + +Unlocks the MetaMask wallet. + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.unlock` + +*** + +### unsafe\_enableEthSign() + +```ts +unsafe_enableEthSign(): Promise +``` + +Enables eth_sign (unsafe). + +#### Returns + +`Promise`\<`void`\> + +#### Overrides + +`MetaMaskAbstract.unsafe_enableEthSign` diff --git a/docs/api/playwright/functions/ethereumWalletMockFixtures.md b/docs/api/playwright/functions/ethereumWalletMockFixtures.md new file mode 100644 index 000000000..9d626db5e --- /dev/null +++ b/docs/api/playwright/functions/ethereumWalletMockFixtures.md @@ -0,0 +1,181 @@ +# Function: ethereumWalletMockFixtures() + +## ethereumWalletMockFixtures(title, body) + +```ts +function ethereumWalletMockFixtures(title, body): void +``` + +Declares a test. +- `test(title, body)` +- `test(title, details, body)` + +**Usage** + +```js +import { test, expect } from '@playwright/test'; + +test('basic test', async ({ page }) => { + await page.goto('https://playwright.dev/'); + // ... +}); +``` + +**Tags** + +You can tag tests by providing additional test details. Alternatively, you can include tags in the test title. Note +that each tag must start with `@` symbol. + +```js +import { test, expect } from '@playwright/test'; + +test('basic test', { + tag: '@smoke', +}, async ({ page }) => { + await page.goto('https://playwright.dev/'); + // ... +}); + +test('another test @smoke', async ({ page }) => { + await page.goto('https://playwright.dev/'); + // ... +}); +``` + +Test tags are displayed in the test report, and are available to a custom reporter via `TestCase.tags` property. + +You can also filter tests by their tags during test execution: +- in the [command line](https://playwright.dev/docs/test-cli#reference); +- in the config with [testConfig.grep](https://playwright.dev/docs/api/class-testconfig#test-config-grep) and + [testProject.grep](https://playwright.dev/docs/api/class-testproject#test-project-grep); + +Learn more about [tagging](https://playwright.dev/docs/test-annotations#tag-tests). + +**Annotations** + +You can annotate tests by providing additional test details. + +```js +import { test, expect } from '@playwright/test'; + +test('basic test', { + annotation: { + type: 'issue', + description: 'https://github.com/microsoft/playwright/issues/23180', + }, +}, async ({ page }) => { + await page.goto('https://playwright.dev/'); + // ... +}); +``` + +Test annotations are displayed in the test report, and are available to a custom reporter via +`TestCase.annotations` property. + +You can also add annotations during runtime by manipulating +[testInfo.annotations](https://playwright.dev/docs/api/class-testinfo#test-info-annotations). + +Learn more about [test annotations](https://playwright.dev/docs/test-annotations). + +### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `title` | `string` | Test title. | +| `body` | (`args`, `testInfo`) => `void` \| `Promise`\<`void`\> | Test body that takes one or two arguments: an object with fixtures and optional TestInfo. | + +### Returns + +`void` + +## ethereumWalletMockFixtures(title, details, body) + +```ts +function ethereumWalletMockFixtures( + title, + details, + body): void +``` + +Declares a test. +- `test(title, body)` +- `test(title, details, body)` + +**Usage** + +```js +import { test, expect } from '@playwright/test'; + +test('basic test', async ({ page }) => { + await page.goto('https://playwright.dev/'); + // ... +}); +``` + +**Tags** + +You can tag tests by providing additional test details. Alternatively, you can include tags in the test title. Note +that each tag must start with `@` symbol. + +```js +import { test, expect } from '@playwright/test'; + +test('basic test', { + tag: '@smoke', +}, async ({ page }) => { + await page.goto('https://playwright.dev/'); + // ... +}); + +test('another test @smoke', async ({ page }) => { + await page.goto('https://playwright.dev/'); + // ... +}); +``` + +Test tags are displayed in the test report, and are available to a custom reporter via `TestCase.tags` property. + +You can also filter tests by their tags during test execution: +- in the [command line](https://playwright.dev/docs/test-cli#reference); +- in the config with [testConfig.grep](https://playwright.dev/docs/api/class-testconfig#test-config-grep) and + [testProject.grep](https://playwright.dev/docs/api/class-testproject#test-project-grep); + +Learn more about [tagging](https://playwright.dev/docs/test-annotations#tag-tests). + +**Annotations** + +You can annotate tests by providing additional test details. + +```js +import { test, expect } from '@playwright/test'; + +test('basic test', { + annotation: { + type: 'issue', + description: 'https://github.com/microsoft/playwright/issues/23180', + }, +}, async ({ page }) => { + await page.goto('https://playwright.dev/'); + // ... +}); +``` + +Test annotations are displayed in the test report, and are available to a custom reporter via +`TestCase.annotations` property. + +You can also add annotations during runtime by manipulating +[testInfo.annotations](https://playwright.dev/docs/api/class-testinfo#test-info-annotations). + +Learn more about [test annotations](https://playwright.dev/docs/test-annotations). + +### Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `title` | `string` | Test title. | +| `details` | `TestDetails` | Additional test details. | +| `body` | (`args`, `testInfo`) => `void` \| `Promise`\<`void`\> | Test body that takes one or two arguments: an object with fixtures and optional TestInfo. | + +### Returns + +`void` diff --git a/docs/api/playwright/functions/getExtensionId.md b/docs/api/playwright/functions/getExtensionId.md new file mode 100644 index 000000000..9b73d29c1 --- /dev/null +++ b/docs/api/playwright/functions/getExtensionId.md @@ -0,0 +1,24 @@ +# Function: getExtensionId() + +```ts +function getExtensionId(context, extensionName): Promise +``` + +Returns the extension ID for the given extension name. The ID is fetched from the `chrome://extensions` page. + +::: tip +This function soon will be removed to improve the developer experience! 😇 +::: + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `context` | `BrowserContext` | The browser context. | +| `extensionName` | `string` | The name of the extension, e.g., `MetaMask`. | + +## Returns + +`Promise`\<`string`\> + +The extension ID. diff --git a/docs/api/playwright/functions/metaMaskFixtures.md b/docs/api/playwright/functions/metaMaskFixtures.md new file mode 100644 index 000000000..2c825c29a --- /dev/null +++ b/docs/api/playwright/functions/metaMaskFixtures.md @@ -0,0 +1,19 @@ +# Function: metaMaskFixtures() + +```ts +function metaMaskFixtures(walletSetup, slowMo?): TestType +``` + +## Parameters + +| Parameter | Type | +| :------ | :------ | +| `walletSetup` | `object` | +| `walletSetup.fn` | `WalletSetupFunction` | +| `walletSetup.hash`? | `string` | +| `walletSetup.walletPassword`? | `string` | +| `slowMo`? | `number` | + +## Returns + +`TestType`\<`PlaywrightTestArgs` & `PlaywrightTestOptions` & `MetaMaskFixtures`, `PlaywrightWorkerArgs` & `PlaywrightWorkerOptions`\> diff --git a/docs/api/playwright/functions/mockEthereum.md b/docs/api/playwright/functions/mockEthereum.md new file mode 100644 index 000000000..174eabb21 --- /dev/null +++ b/docs/api/playwright/functions/mockEthereum.md @@ -0,0 +1,16 @@ +# Function: mockEthereum() + +```ts +function mockEthereum(wallet?, accounts?): void +``` + +## Parameters + +| Parameter | Type | +| :------ | :------ | +| `wallet`? | \| `"metamask"` \| `"coinbase"` \| `"phantom"` \| `"walletconnect"` \| `"walletlink"` | +| `accounts`? | \`0x$\{string\}\`[] | + +## Returns + +`void` diff --git a/docs/api/playwright/functions/unlockForFixture.md b/docs/api/playwright/functions/unlockForFixture.md new file mode 100644 index 000000000..42603d819 --- /dev/null +++ b/docs/api/playwright/functions/unlockForFixture.md @@ -0,0 +1,19 @@ +# Function: unlockForFixture() + +```ts +function unlockForFixture(page, password): Promise +``` + +A more advanced version of the `MetaMask.unlock()` function that incorporates various workarounds for MetaMask issues, among other things. + This function should be used instead of the `MetaMask.unlock()` when passing it to the `testWithSynpress` function. + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `page` | `Page` | The MetaMask tab page. | +| `password` | `string` | The password of the MetaMask wallet. | + +## Returns + +`Promise`\<`void`\> diff --git a/docs/api/playwright/index.md b/docs/api/playwright/index.md new file mode 100644 index 000000000..3349b2f0b --- /dev/null +++ b/docs/api/playwright/index.md @@ -0,0 +1,16 @@ +# playwright + +## Index + +| Member | Description | +| :------ | :------ | +| [EthereumWalletMock](classes/EthereumWalletMock.md) | Mock implementation of an Ethereum wallet for testing purposes. | +| [MetaMask](classes/MetaMask.md) | MetaMask class for interacting with the MetaMask extension in Playwright tests. | +| [OPTIMISM\_NETWORK\_ID](variables/OPTIMISM_NETWORK_ID.md) | The network ID (Optimism network by default). | +| [PRIVATE\_KEY](variables/PRIVATE_KEY.md) | The private key used for testing purposes. | +| [web3MockPath](variables/web3MockPath.md) | Relative path to the web3-mock bundle. | +| [ethereumWalletMockFixtures](functions/ethereumWalletMockFixtures.md) | Declares a test. | +| [getExtensionId](functions/getExtensionId.md) | Returns the extension ID for the given extension name. The ID is fetched from the `chrome://extensions` page. | +| [metaMaskFixtures](functions/metaMaskFixtures.md) | - | +| [mockEthereum](functions/mockEthereum.md) | - | +| [unlockForFixture](functions/unlockForFixture.md) | A more advanced version of the `MetaMask.unlock()` function that incorporates various workarounds for MetaMask issues, among other things. | diff --git a/docs/api/playwright/variables/OPTIMISM_NETWORK_ID.md b/docs/api/playwright/variables/OPTIMISM_NETWORK_ID.md new file mode 100644 index 000000000..03d95f06d --- /dev/null +++ b/docs/api/playwright/variables/OPTIMISM_NETWORK_ID.md @@ -0,0 +1,9 @@ +# Variable: OPTIMISM\_NETWORK\_ID + +```ts +const OPTIMISM_NETWORK_ID: "0xa" = "0xa"; +``` + +The network ID (Optimism network by default). + +## Constant diff --git a/docs/api/playwright/variables/PRIVATE_KEY.md b/docs/api/playwright/variables/PRIVATE_KEY.md new file mode 100644 index 000000000..20d53ea63 --- /dev/null +++ b/docs/api/playwright/variables/PRIVATE_KEY.md @@ -0,0 +1,9 @@ +# Variable: PRIVATE\_KEY + +```ts +const PRIVATE_KEY: "ea084c575a01e2bbefcca3db101eaeab1d8af15554640a510c73692db24d0a6a" = "ea084c575a01e2bbefcca3db101eaeab1d8af15554640a510c73692db24d0a6a"; +``` + +The private key used for testing purposes. + +## Constant diff --git a/docs/api/playwright/variables/web3MockPath.md b/docs/api/playwright/variables/web3MockPath.md new file mode 100644 index 000000000..ac2e8b804 --- /dev/null +++ b/docs/api/playwright/variables/web3MockPath.md @@ -0,0 +1,9 @@ +# Variable: web3MockPath + +```ts +const web3MockPath: string; +``` + +Relative path to the web3-mock bundle. + +## Constant diff --git a/docs/api/typedoc-sidebar.json b/docs/api/typedoc-sidebar.json index ed662c404..906e69cfd 100644 --- a/docs/api/typedoc-sidebar.json +++ b/docs/api/typedoc-sidebar.json @@ -1,4 +1,98 @@ [ - { "text": "defineWalletSetup", "link": "/api/functions/defineWalletSetup.md" }, - { "text": "testWithSynpress", "link": "/api/functions/testWithSynpress.md" } + { + "text": "cypress", + "link": "/api/cypress/", + "collapsed": true, + "items": [ + { + "text": "Classes", + "collapsed": true, + "items": [{ "text": "MetaMask", "link": "/api/cypress/classes/MetaMask.md" }] + }, + { + "text": "Functions", + "collapsed": true, + "items": [ + { + "text": "configureSynpressForEthereumWalletMock", + "link": "/api/cypress/functions/configureSynpressForEthereumWalletMock.md" + }, + { "text": "configureSynpressForMetaMask", "link": "/api/cypress/functions/configureSynpressForMetaMask.md" }, + { "text": "initMetaMask", "link": "/api/cypress/functions/initMetaMask.md" } + ] + }, + { + "text": "support", + "link": "/api/cypress/support/", + "collapsed": true, + "items": [ + { + "text": "Functions", + "collapsed": true, + "items": [ + { "text": "mockEthereum", "link": "/api/cypress/support/functions/mockEthereum.md" }, + { + "text": "synpressCommandsForEthereumWalletMock", + "link": "/api/cypress/support/functions/synpressCommandsForEthereumWalletMock.md" + }, + { + "text": "synpressCommandsForMetaMask", + "link": "/api/cypress/support/functions/synpressCommandsForMetaMask.md" + } + ] + } + ] + } + ] + }, + { + "text": "index", + "link": "/api/index/", + "collapsed": true, + "items": [ + { + "text": "Functions", + "collapsed": true, + "items": [ + { "text": "defineWalletSetup", "link": "/api/index/functions/defineWalletSetup.md" }, + { "text": "testWithSynpress", "link": "/api/index/functions/testWithSynpress.md" } + ] + } + ] + }, + { + "text": "playwright", + "link": "/api/playwright/", + "collapsed": true, + "items": [ + { + "text": "Classes", + "collapsed": true, + "items": [ + { "text": "EthereumWalletMock", "link": "/api/playwright/classes/EthereumWalletMock.md" }, + { "text": "MetaMask", "link": "/api/playwright/classes/MetaMask.md" } + ] + }, + { + "text": "Variables", + "collapsed": true, + "items": [ + { "text": "OPTIMISM_NETWORK_ID", "link": "/api/playwright/variables/OPTIMISM_NETWORK_ID.md" }, + { "text": "PRIVATE_KEY", "link": "/api/playwright/variables/PRIVATE_KEY.md" }, + { "text": "web3MockPath", "link": "/api/playwright/variables/web3MockPath.md" } + ] + }, + { + "text": "Functions", + "collapsed": true, + "items": [ + { "text": "ethereumWalletMockFixtures", "link": "/api/playwright/functions/ethereumWalletMockFixtures.md" }, + { "text": "getExtensionId", "link": "/api/playwright/functions/getExtensionId.md" }, + { "text": "metaMaskFixtures", "link": "/api/playwright/functions/metaMaskFixtures.md" }, + { "text": "mockEthereum", "link": "/api/playwright/functions/mockEthereum.md" }, + { "text": "unlockForFixture", "link": "/api/playwright/functions/unlockForFixture.md" } + ] + } + ] + } ] diff --git a/docs/tsconfig.json b/docs/tsconfig.json index bb0ba38bc..451ae0894 100644 --- a/docs/tsconfig.json +++ b/docs/tsconfig.json @@ -3,5 +3,11 @@ "compilerOptions": { "rootDir": "." }, - "include": [".vitepress/**/*.ts", "node_modules/@synthetixio/synpress/src/index.ts"] + "include": [ + ".vitepress/**/*.ts", + "node_modules/@synthetixio/synpress/src/index.ts", + "node_modules/@synthetixio/synpress/src/cypress/index.ts", + "node_modules/@synthetixio/synpress/src/cypress/support/index.ts", + "node_modules/@synthetixio/synpress/src/playwright/index.ts" + ] } diff --git a/docs/typedoc.json b/docs/typedoc.json index fdf4d00b9..4bed65f0e 100644 --- a/docs/typedoc.json +++ b/docs/typedoc.json @@ -1,7 +1,12 @@ { "$schema": "https://typedoc.org/schema.json", "out": "./api", - "entryPoints": ["node_modules/@synthetixio/synpress/src/index.ts"], + "entryPoints": [ + "node_modules/@synthetixio/synpress/src/index.ts", + "node_modules/@synthetixio/synpress/src/cypress/index.ts", + "node_modules/@synthetixio/synpress/src/cypress/support/index.ts", + "node_modules/@synthetixio/synpress/src/playwright/index.ts" + ], "plugin": ["typedoc-plugin-markdown", "typedoc-vitepress-theme"], "readme": "none", "hideGenerator": true, diff --git a/packages/core/src/testWithSynpress.ts b/packages/core/src/testWithSynpress.ts index 498a8a58e..930fb41f3 100644 --- a/packages/core/src/testWithSynpress.ts +++ b/packages/core/src/testWithSynpress.ts @@ -1,8 +1,29 @@ import type { Fixtures, TestType } from '@playwright/test' import { mergeTests, test as base } from '@playwright/test' +/** + * Creates a test environment with Synpress integration. + * + * This function merges the base Playwright test with custom fixtures, allowing for + * seamless integration of Synpress capabilities in Playwright tests. + * + * Synpress is a wrapper around Cypress that adds support for testing + * Web3 and blockchain applications, particularly those involving + * MetaMask interactions. + * + * @param customFixtures - Custom fixtures to be merged with the base test. + * @returns A merged test object that includes both Playwright and Synpress capabilities. + * + * @example + * ```typescript + * const test = testWithSynpress(myCustomFixtures); + * test('My Web3 test', async ({ page, synpress }) => { + * // Test implementation using Playwright and Synpress + * }); + * ``` + */ export default function testWithSynpress( customFixtures: TestType -) { +): TestType { return mergeTests(base, customFixtures) } diff --git a/release/src/cypress/index.ts b/release/src/cypress/index.ts index 82b03a60b..93cf88871 100644 --- a/release/src/cypress/index.ts +++ b/release/src/cypress/index.ts @@ -1,2 +1,6 @@ export { configureSynpress as configureSynpressForEthereumWalletMock } from '@synthetixio/ethereum-wallet-mock/cypress' -export { configureSynpress as configureSynpressForMetaMask } from '@synthetixio/synpress-metamask/cypress' +export { + configureSynpress as configureSynpressForMetaMask, + initMetaMask, + MetaMask +} from '@synthetixio/synpress-metamask/cypress' diff --git a/wallets/ethereum-wallet-mock/src/cypress/support/mockEthereum.ts b/wallets/ethereum-wallet-mock/src/cypress/support/mockEthereum.ts index a396f567b..142fa17c6 100644 --- a/wallets/ethereum-wallet-mock/src/cypress/support/mockEthereum.ts +++ b/wallets/ethereum-wallet-mock/src/cypress/support/mockEthereum.ts @@ -1,4 +1,31 @@ -export default function mockEthereum() { +/** + * Mock Ethereum Environment for Cypress Tests + * + * This module provides a function to set up a mocked Ethereum environment + * for Cypress tests. It utilizes the Web3Mock library to simulate Ethereum + * blockchain interactions and MetaMask wallet behavior. + * + * @remarks + * Key features: + * - Mocks the Ethereum blockchain environment + * - Simulates MetaMask wallet functionality + * - Automatically applied before each test suite + * + * This function is typically called in the Cypress support file or test + * setup to ensure all tests run in a controlled, mocked Ethereum environment. + * It allows for consistent and predictable testing of Ethereum-based + * applications without the need for a real blockchain or wallet. + * + * @example + * ```typescript + * // In your Cypress support file + * import { mockEthereum } from '@synthetixio/synpress'; + * + * mockEthereum(); + * ``` + */ + +export default function mockEthereum(): void { before(() => { cy.visit('/', { onBeforeLoad: (window) => { diff --git a/wallets/ethereum-wallet-mock/src/cypress/support/synpressCommands.ts b/wallets/ethereum-wallet-mock/src/cypress/support/synpressCommands.ts index 4d03cc4b9..f74cc06d7 100644 --- a/wallets/ethereum-wallet-mock/src/cypress/support/synpressCommands.ts +++ b/wallets/ethereum-wallet-mock/src/cypress/support/synpressCommands.ts @@ -53,49 +53,117 @@ declare global { } } -export default function synpressCommands() { - Cypress.Commands.add('importWallet', (seedPhrase) => { +/** + * Synpress Commands for Ethereum Wallet Mock + * + * This module extends Cypress with custom commands for interacting with a mocked Ethereum wallet. + * It provides functionalities for wallet management, account operations, and network interactions. + * + * Key features include: + * - Wallet: Import wallet from seed phrase or private key + * - Account: Add new accounts, get all accounts, switch between accounts + * - Network: Add new networks, switch between networks + * - dApp Interaction: Connect to dApps + * + * These commands enhance the testing capabilities for Ethereum-based applications, + * allowing for comprehensive end-to-end testing of dApps using a mocked Ethereum wallet. + * This approach provides a controlled environment for testing without the need for a real wallet, + * making tests more reliable and easier to set up. + * + * @module SynpressCommandsForEthereumWalletMock + */ + +/** + * Initializes Synpress commands for the Ethereum Wallet Mock. + * + * This function adds custom Cypress commands for interacting with a mocked Ethereum wallet. + * These commands include wallet import, account management, network operations, and dApp connections. + * + * @example + * ```typescript + * import { synpressCommandsForEthereumWalletMock } from '@synthetixio/synpress'; + * + * synpressCommandsForEthereumWalletMock(); + * ``` + */ +export default function synpressCommandsForEthereumWalletMock(): void { + /** + * Imports a wallet using a seed phrase. + * @param seedPhrase - The seed phrase to import the wallet. + */ + Cypress.Commands.add('importWallet', (seedPhrase: string) => { const ethereumWalletMock = getEthereumWalletMock() ethereumWalletMock.importWallet(seedPhrase) }) - Cypress.Commands.add('importWalletFromPrivateKey', (privateKey) => { + /** + * Imports a wallet using a private key. + * @param privateKey - The private key to import the wallet. + */ + Cypress.Commands.add('importWalletFromPrivateKey', (privateKey: `0x${string}`) => { const ethereumWalletMock = getEthereumWalletMock() ethereumWalletMock.importWalletFromPrivateKey(privateKey) }) + /** + * Adds a new account to the wallet. + * @returns A promise that resolves when the account is added. + */ Cypress.Commands.add('addNewAccount', () => { const ethereumWalletMock = getEthereumWalletMock() return ethereumWalletMock.addNewAccount() }) + /** + * Retrieves all accounts in the wallet. + * @returns A promise that resolves with an array of account addresses. + */ Cypress.Commands.add('getAllAccounts', () => { const ethereumWalletMock = getEthereumWalletMock() - return ethereumWalletMock.getAllAccounts() }) + /** + * Gets the current account address. + * @returns A promise that resolves with the current account address. + */ Cypress.Commands.add('getAccountAddress', () => { const ethereumWalletMock = getEthereumWalletMock() return ethereumWalletMock.getAccountAddress() }) - Cypress.Commands.add('switchAccount', (accountAddress) => { + /** + * Switches to a different account. + * @param accountAddress - The address of the account to switch to. + */ + Cypress.Commands.add('switchAccount', (accountAddress: string) => { const ethereumWalletMock = getEthereumWalletMock() ethereumWalletMock.switchAccount(accountAddress) }) - Cypress.Commands.add('addNetwork', (network) => { + /** + * Adds a new network to the wallet. + * @param network - The network configuration to add. + */ + Cypress.Commands.add('addNetwork', (network: Network) => { const ethereumWalletMock = getEthereumWalletMock() ethereumWalletMock.addNetwork(network) }) - Cypress.Commands.add('switchNetwork', (networkName) => { + /** + * Switches to a different network. + * @param networkName - The name of the network to switch to. + */ + Cypress.Commands.add('switchNetwork', (networkName: string) => { const ethereumWalletMock = getEthereumWalletMock() ethereumWalletMock.switchNetwork(networkName) }) - Cypress.Commands.add('connectToDapp', (wallet) => { + /** + * Connects the wallet to a dApp. + * @param wallet - Optional wallet configuration to use for the connection. + */ + Cypress.Commands.add('connectToDapp', (wallet?: WalletMock) => { const ethereumWalletMock = getEthereumWalletMock() ethereumWalletMock.connectToDapp(wallet) }) diff --git a/wallets/ethereum-wallet-mock/src/cypress/utils/configureSynpress.ts b/wallets/ethereum-wallet-mock/src/cypress/utils/configureSynpress.ts index 1a473c0d1..d8ac1a3cb 100644 --- a/wallets/ethereum-wallet-mock/src/cypress/utils/configureSynpress.ts +++ b/wallets/ethereum-wallet-mock/src/cypress/utils/configureSynpress.ts @@ -4,6 +4,24 @@ import { initEthereumWalletMock } from './initEthereumWalletMock' let port: number +/** + * Configures Synpress for use with the Ethereum Wallet Mock. + * + * This function sets up the necessary configurations and hooks for running + * Cypress tests with the Ethereum Wallet Mock. It performs the following tasks: + * + * 1. Filters the available browsers to ensure only Chrome is used. + * 2. Sets up a 'before:browser:launch' hook to enable debug mode and establish + * a Playwright connection. + * 3. Sets up a 'before:spec' hook to initialize the Ethereum Wallet Mock before + * each test spec runs. + * + * @param on - Cypress plugin event handler + * @param config - Cypress plugin configuration options + * @returns Modified Cypress configuration + * @throws Error If no Chrome browser is found in the configuration + */ + export default function configureSynpress(on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions) { const browsers = config.browsers.filter((b) => b.name === 'chrome') if (browsers.length === 0) { diff --git a/wallets/ethereum-wallet-mock/src/playwright/EthereumWalletMock.ts b/wallets/ethereum-wallet-mock/src/playwright/EthereumWalletMock.ts index d0bb3b047..7fe2e9b7a 100644 --- a/wallets/ethereum-wallet-mock/src/playwright/EthereumWalletMock.ts +++ b/wallets/ethereum-wallet-mock/src/playwright/EthereumWalletMock.ts @@ -6,9 +6,23 @@ import type { Network } from '../type/Network' import type { WalletMock } from '../type/WalletMock' import { OPTIMISM_NETWORK_ID } from './utils' +/** + * Mock implementation of an Ethereum wallet for testing purposes. + * Simulates wallet behavior in a controlled environment, allowing for consistent + * and reproducible tests without relying on actual blockchain interactions. + * + * @class + * @extends {EthereumWalletMockAbstract} + */ export default class EthereumWalletMock extends EthereumWalletMockAbstract { + /** The Playwright Page object to interact with. */ page: Page + /** + * Creates an instance of EthereumWalletMock. + * @param page - The Playwright Page object to interact with. + * @param wallet - The type of wallet to mock. + */ constructor(page: Page, wallet: WalletMock = 'metamask') { super(wallet) this.page = page @@ -17,10 +31,10 @@ export default class EthereumWalletMock extends EthereumWalletMockAbstract { /** * Imports a wallet using the given seed phrase. - * * @param seedPhrase - The seed phrase to import. + * @returns A promise that resolves when the wallet is imported. */ - importWallet(seedPhrase: string) { + importWallet(seedPhrase: string): Promise { this.seedPhrase = seedPhrase return this.page.evaluate( @@ -47,7 +61,8 @@ export default class EthereumWalletMock extends EthereumWalletMockAbstract { } /** - * Retrieves the current account address. + * Retrieves all account addresses. + * @returns A promise that resolves to an array of account addresses. */ async getAllAccounts(): Promise<`0x${string}`[] | undefined> { return this.page.evaluate(() => { @@ -56,9 +71,10 @@ export default class EthereumWalletMock extends EthereumWalletMockAbstract { } /** - * Adds a new account. This account is based on the initially imported seed phrase. + * Adds a new account based on the initially imported seed phrase. + * @returns A promise that resolves when the new account is added. */ - async addNewAccount() { + async addNewAccount(): Promise { const accounts = await this.getAllAccounts() const newAccount = mnemonicToAccount(this.seedPhrase || '', { @@ -81,10 +97,10 @@ export default class EthereumWalletMock extends EthereumWalletMockAbstract { /** * Imports a wallet using the given private key. - * * @param privateKey - The private key to import. + * @returns A promise that resolves when the wallet is imported. */ - async importWalletFromPrivateKey(privateKey: `0x${string}`) { + async importWalletFromPrivateKey(privateKey: `0x${string}`): Promise { const newAccount = privateKeyToAccount(privateKey) return this.page.evaluate( @@ -102,11 +118,11 @@ export default class EthereumWalletMock extends EthereumWalletMockAbstract { } /** - * Switches to the account with the given name. - * - * @param accountAddress - The name of the account to switch to. + * Switches to the account with the given address. + * @param accountAddress - The address of the account to switch to. + * @returns A promise that resolves when the account switch is complete. */ - async switchAccount(accountAddress: string) { + async switchAccount(accountAddress: string): Promise { return this.page.evaluate( ([blockchain, wallet, accountAddress]) => { return Web3Mock.mock({ @@ -123,10 +139,10 @@ export default class EthereumWalletMock extends EthereumWalletMockAbstract { /** * Adds a new network. - * * @param network - The network object to use for adding the new network. + * @returns A promise that resolves when the network is added. */ - async addNetwork(network: Network) { + async addNetwork(network: Network): Promise { const networkInfo = { chainId: network.chainId, chainName: network.name, @@ -151,6 +167,7 @@ export default class EthereumWalletMock extends EthereumWalletMockAbstract { /** * Retrieves the current account address. + * @returns A promise that resolves to the current account address. */ async getAccountAddress(): Promise<`0x${string}` | undefined> { return (await this.getAllAccounts())?.[0] @@ -158,10 +175,10 @@ export default class EthereumWalletMock extends EthereumWalletMockAbstract { /** * Switches to the network with the given name. - * * @param networkName - The name of the network to switch to. + * @returns A promise that resolves when the network switch is complete. */ - async switchNetwork(networkName: string) { + async switchNetwork(networkName: string): Promise { return this.page.evaluate( ([blockchain, wallet, networkName, chainId]) => { Web3Mock.mock({ @@ -184,10 +201,10 @@ export default class EthereumWalletMock extends EthereumWalletMockAbstract { /** * Connects wallet to the dapp. - * * @param wallet - The wallet to connect to the dapp. + * @returns A promise that resolves when the wallet is connected to the dapp. */ - connectToDapp(wallet: WalletMock = 'metamask') { + connectToDapp(wallet: WalletMock = 'metamask'): Promise { this.wallet = wallet return this.page.evaluate( diff --git a/wallets/ethereum-wallet-mock/src/playwright/constants.ts b/wallets/ethereum-wallet-mock/src/playwright/constants.ts index cefae7d5d..c947e62e9 100644 --- a/wallets/ethereum-wallet-mock/src/playwright/constants.ts +++ b/wallets/ethereum-wallet-mock/src/playwright/constants.ts @@ -1,9 +1,23 @@ import { createRequire } from 'node:module' const require = createRequire(import.meta.url) +/** + * The private key used for testing purposes. + * @constant + * @type {string} + */ export const PRIVATE_KEY = 'ea084c575a01e2bbefcca3db101eaeab1d8af15554640a510c73692db24d0a6a' +/** + * The network ID (Optimism network by default). + * @constant + * @type {string} + */ export const OPTIMISM_NETWORK_ID = '0xa' -// Relative path to the web3-mock bundle +/** + * Relative path to the web3-mock bundle. + * @constant + * @type {string} + */ export const web3MockPath = require.resolve('@depay/web3-mock/dist/umd/index.bundle.js') diff --git a/wallets/metamask/src/cypress/MetaMask.ts b/wallets/metamask/src/cypress/MetaMask.ts index 54f4412fd..0d9ce7544 100644 --- a/wallets/metamask/src/cypress/MetaMask.ts +++ b/wallets/metamask/src/cypress/MetaMask.ts @@ -1,5 +1,5 @@ import { type BrowserContext, type Page, expect } from '@playwright/test' -import { type CreateAnvilOptions, type Pool, createPool } from '@viem/anvil' +import { type Anvil, type CreateAnvilOptions, type Pool, createPool } from '@viem/anvil' import { MetaMask as MetaMaskPlaywright } from '../playwright/MetaMask' import { waitFor } from '../playwright/utils/waitFor' import HomePageSelectors from '../selectors/pages/HomePage' @@ -12,100 +12,155 @@ import getPlaywrightMetamask from './getPlaywrightMetamask' let pool: Pool +/** + * MetaMask class for interacting with the MetaMask extension in Cypress tests. + */ export default class MetaMask { + /** The MetaMask instance for Playwright */ readonly metamaskPlaywright: MetaMaskPlaywright + /** The MetaMask extension page */ readonly metamaskExtensionPage: Page + /** + * Creates an instance of MetaMask. + * @param context - The browser context + * @param metamaskExtensionPage - The MetaMask extension page + * @param metamaskExtensionId - The MetaMask extension ID + */ constructor(context: BrowserContext, metamaskExtensionPage: Page, metamaskExtensionId: string) { this.metamaskPlaywright = getPlaywrightMetamask(context, metamaskExtensionPage, metamaskExtensionId) this.metamaskExtensionPage = metamaskExtensionPage } - async getAccount() { + /** + * Gets the current account name. + * @returns The current account name + */ + async getAccount(): Promise { return await this.metamaskExtensionPage .locator(this.metamaskPlaywright.homePage.selectors.accountMenu.accountButton) .innerText() } - async getAccountAddress() { + /** + * Gets the current account address. + * @returns The current account address + */ + async getAccountAddress(): Promise { return await this.metamaskPlaywright.getAccountAddress() } - async getNetwork() { + /** + * Gets the current network name. + * @returns The current network name + */ + async getNetwork(): Promise { return await this.metamaskExtensionPage .locator(this.metamaskPlaywright.homePage.selectors.currentNetwork) .innerText() } - async connectToDapp(accounts?: string[]) { + /** + * Connects MetaMask to a dApp. + * @param accounts - Optional array of account addresses to connect + * @returns True if the connection was successful + */ + async connectToDapp(accounts?: string[]): Promise { await this.metamaskPlaywright.connectToDapp(accounts) - return true } - async importWallet(seedPhrase: string) { + /** + * Imports a wallet using a seed phrase. + * @param seedPhrase - The seed phrase to import + * @returns True if the import was successful + */ + async importWallet(seedPhrase: string): Promise { await this.metamaskPlaywright.importWallet(seedPhrase) - return true } - async importWalletFromPrivateKey(privateKey: string) { + /** + * Imports a wallet using a private key. + * @param privateKey - The private key to import + * @returns True if the import was successful + */ + async importWalletFromPrivateKey(privateKey: string): Promise { await this.metamaskPlaywright.importWalletFromPrivateKey(privateKey) - return true } - async addNewAccount(accountName: string) { + /** + * Adds a new account with the given name. + * @param accountName - The name for the new account + * @returns True if the account was added successfully + */ + async addNewAccount(accountName: string): Promise { await this.metamaskPlaywright.addNewAccount(accountName) - await expect( this.metamaskExtensionPage.locator(this.metamaskPlaywright.homePage.selectors.accountMenu.accountButton) ).toHaveText(accountName) - return true } - async switchAccount(accountName: string) { + /** + * Switches to the account with the given name. + * @param accountName - The name of the account to switch to + * @returns True if the switch was successful + */ + async switchAccount(accountName: string): Promise { await this.metamaskPlaywright.switchAccount(accountName) - await expect( this.metamaskExtensionPage.locator(this.metamaskPlaywright.homePage.selectors.accountMenu.accountButton) ).toHaveText(accountName) - return true } + /** + * Renames an account. + * @param options - Object containing the current and new account names + * @param options.currentAccountName - The current name of the account + * @param options.newAccountName - The new name for the account + * @returns True if the rename was successful + */ async renameAccount({ currentAccountName, newAccountName }: { currentAccountName: string newAccountName: string - }) { + }): Promise { await this.metamaskPlaywright.renameAccount(currentAccountName, newAccountName) - await this.metamaskExtensionPage.locator(HomePageSelectors.threeDotsMenu.accountDetailsCloseButton).click() - await expect( this.metamaskExtensionPage.locator(this.metamaskPlaywright.homePage.selectors.accountMenu.accountButton) ).toHaveText(newAccountName) - return true } - async resetAccount() { + /** + * Resets the current account. + * @returns True if the reset was successful + */ + async resetAccount(): Promise { await this.metamaskPlaywright.resetAccount() - return true } + /** + * Switches to the specified network. + * @param options - Object containing the network name and testnet flag + * @param options.networkName - The name of the network to switch to + * @param options.isTestnet - Whether the network is a testnet (default: false) + * @returns True if the switch was successful, false otherwise + */ async switchNetwork({ networkName, isTestnet = false }: { networkName: string isTestnet?: boolean - }) { + }): Promise { return await this.metamaskPlaywright .switchNetwork(networkName, isTestnet) .then(() => { @@ -115,33 +170,46 @@ export default class MetaMask { return false }) } + x - async createAnvilNode(options?: CreateAnvilOptions) { + /** + * Creates an Anvil node for testing. + * @param options - Optional Anvil node creation options + * @returns Object containing the Anvil instance, RPC URL, and chain ID + */ + async createAnvilNode(options?: CreateAnvilOptions): Promise<{ anvil: Anvil; rpcUrl: string; chainId: number }> { pool = createPool() - const nodeId = Array.from(pool.instances()).length const anvil = await pool.start(nodeId, options) - const rpcUrl = `http://${anvil.host}:${anvil.port}` - const DEFAULT_ANVIL_CHAIN_ID = 31337 const chainId = options?.chainId ?? DEFAULT_ANVIL_CHAIN_ID - return { anvil, rpcUrl, chainId } } - async emptyAnvilNode() { + /** + * Empties the Anvil node pool. + * @returns True if the operation was successful + */ + async emptyAnvilNode(): Promise { await pool.empty() return true } + /** + * Connects to an Anvil node. + * @param options - Object containing the RPC URL and chain ID + * @param options.rpcUrl - The RPC URL of the Anvil node + * @param options.chainId - The chain ID of the Anvil node + * @returns True if the connection was successful, false otherwise + */ async connectToAnvil({ rpcUrl, chainId }: { rpcUrl: string chainId: number - }) { + }): Promise { try { await this.metamaskPlaywright.addNetwork({ name: 'Anvil', @@ -150,7 +218,6 @@ export default class MetaMask { symbol: 'ETH', blockExplorerUrl: 'https://etherscan.io/' }) - await this.metamaskPlaywright.switchNetwork('Anvil') return true } catch (e) { @@ -159,47 +226,58 @@ export default class MetaMask { } } - async addNetwork(network: Network) { + /** + * Adds a new network to MetaMask. + * @param network - The network configuration to add + * @returns True if the network was added successfully + */ + async addNetwork(network: Network): Promise { await this.metamaskPlaywright.addNetwork(network) - await waitFor( () => this.metamaskExtensionPage.locator(HomePageSelectors.networkAddedPopover.switchToNetworkButton).isVisible(), 3_000, false ) - await this.metamaskExtensionPage.locator(HomePageSelectors.networkAddedPopover.switchToNetworkButton).click() - return true } - // Token - - async deployToken() { + /** + * Deploys a token. + * @returns True if the token was deployed successfully + */ + async deployToken(): Promise { await waitFor( () => this.metamaskExtensionPage.locator(TransactionPage.nftApproveAllConfirmationPopup.approveButton).isVisible(), 3_000, false ) - await this.metamaskPlaywright.confirmTransaction() - return true } - async addNewToken() { + /** + * Adds a new token to MetaMask. + * @returns True if the token was added successfully + */ + async addNewToken(): Promise { await this.metamaskPlaywright.addNewToken() - await expect(this.metamaskExtensionPage.locator(Selectors.portfolio.singleToken).nth(1)).toContainText('TST') - return true } + /** + * Approves token permission. + * @param options - Optional settings for token approval + * @param options.spendLimit - The spend limit for the token (number or 'max') + * @param options.gasSetting - Gas settings for the transaction + * @returns True if the permission was approved, false otherwise + */ async approveTokenPermission(options?: { spendLimit?: number | 'max' gasSetting?: GasSettings - }) { + }): Promise { return await this.metamaskPlaywright .approveTokenPermission(options) .then(() => { @@ -210,59 +288,78 @@ export default class MetaMask { }) } - async rejectTokenPermission() { + /** + * Rejects token permission. + * @returns True if the permission was rejected successfully + */ + async rejectTokenPermission(): Promise { await this.metamaskPlaywright.rejectTokenPermission() - return true } - // Network - - async approveNewNetwork() { + /** + * Approves adding a new network. + * @returns True if the new network was approved successfully + */ + async approveNewNetwork(): Promise { await this.metamaskPlaywright.approveNewNetwork() - return true } - async approveSwitchNetwork() { + /** + * Approves switching to a new network. + * @returns True if the network switch was approved successfully + */ + async approveSwitchNetwork(): Promise { await this.metamaskPlaywright.approveSwitchNetwork() - return true } - async rejectNewNetwork() { + /** + * Rejects adding a new network. + * @returns True if the new network was rejected successfully + */ + async rejectNewNetwork(): Promise { await this.metamaskPlaywright.rejectNewNetwork() - return true } - async rejectSwitchNetwork() { + /** + * Rejects switching to a new network. + * @returns True if the network switch was rejected successfully + */ + async rejectSwitchNetwork(): Promise { await this.metamaskPlaywright.rejectSwitchNetwork() - return true } - // Lock/Unlock - - async lock() { + /** + * Locks the MetaMask wallet. + * @returns True if the wallet was locked successfully + */ + async lock(): Promise { await this.metamaskPlaywright.lock() await expect( this.metamaskExtensionPage.locator(this.metamaskPlaywright.lockPage.selectors.submitButton) ).toBeVisible() - return true } - async unlock() { + /** + * Unlocks the MetaMask wallet. + * @returns True if the wallet was unlocked successfully + */ + async unlock(): Promise { await this.metamaskPlaywright.unlock() await expect(this.metamaskExtensionPage.locator(this.metamaskPlaywright.homePage.selectors.logo)).toBeVisible() - return true } - // Others - - async providePublicEncryptionKey() { + /** + * Provides a public encryption key. + * @returns True if the key was provided successfully, false otherwise + */ + async providePublicEncryptionKey(): Promise { return await this.metamaskPlaywright .providePublicEncryptionKey() .then(() => { @@ -273,7 +370,11 @@ export default class MetaMask { }) } - async decrypt() { + /** + * Decrypts a message. + * @returns True if the message was decrypted successfully, false otherwise + */ + async decrypt(): Promise { return await this.metamaskPlaywright .decrypt() .then(() => { @@ -284,7 +385,11 @@ export default class MetaMask { }) } - async confirmSignature() { + /** + * Confirms a signature request. + * @returns True if the signature was confirmed successfully, false otherwise + */ + async confirmSignature(): Promise { return await this.metamaskPlaywright .confirmSignature() .then(() => { @@ -295,39 +400,53 @@ export default class MetaMask { }) } - async rejectSignature() { + /** + * Rejects a signature request. + * @returns True if the signature was rejected successfully + */ + async rejectSignature(): Promise { await this.metamaskPlaywright.rejectSignature() - return true } - async confirmTransaction(options?: { gasSetting?: GasSettings }) { + /** + * Confirms a transaction. + * @param options - Optional gas settings for the transaction + * @returns True if the transaction was confirmed successfully + */ + async confirmTransaction(options?: { + gasSetting?: GasSettings + }): Promise { await waitFor( () => this.metamaskExtensionPage.locator(TransactionPage.nftApproveAllConfirmationPopup.approveButton).isVisible(), 5_000, false ) - await this.metamaskPlaywright.confirmTransaction(options) - return true } - async rejectTransaction() { + /** + * Rejects a transaction. + * @returns True if the transaction was rejected successfully + */ + async rejectTransaction(): Promise { await this.metamaskPlaywright.rejectTransaction() - return true } - async confirmTransactionAndWaitForMining() { + /** + * Confirms a transaction and waits for it to be mined. + * @returns True if the transaction was confirmed and mined successfully, false otherwise + */ + async confirmTransactionAndWaitForMining(): Promise { await waitFor( () => this.metamaskExtensionPage.locator(TransactionPage.nftApproveAllConfirmationPopup.approveButton).isVisible(), 5_000, false ) - return this.metamaskPlaywright .confirmTransactionAndWaitForMining() .then(() => { @@ -338,7 +457,12 @@ export default class MetaMask { }) } - async openTransactionDetails(txIndex: number) { + /** + * Opens the details of a specific transaction. + * @param txIndex - The index of the transaction to open + * @returns True if the transaction details were opened successfully, false otherwise + */ + async openTransactionDetails(txIndex: number): Promise { return this.metamaskPlaywright .openTransactionDetails(txIndex) .then(() => { @@ -349,7 +473,11 @@ export default class MetaMask { }) } - async closeTransactionDetails() { + /** + * Closes the transaction details view. + * @returns True if the transaction details were closed successfully, false otherwise + */ + async closeTransactionDetails(): Promise { return this.metamaskPlaywright .closeTransactionDetails() .then(() => { @@ -360,40 +488,53 @@ export default class MetaMask { }) } - async toggleShowTestNetworks() { + /** + * Toggles the display of test networks. + * @returns True if the toggle was successful + */ + async toggleShowTestNetworks(): Promise { await this.metamaskPlaywright.toggleShowTestNetworks() - return true } - async toggleDismissSecretRecoveryPhraseReminder() { + /** + * Toggles the dismissal of the secret recovery phrase reminder. + * @returns True if the toggle was successful + */ + async toggleDismissSecretRecoveryPhraseReminder(): Promise { await this.metamaskPlaywright.toggleDismissSecretRecoveryPhraseReminder() - return true } - async goBackToHomePage() { + /** + * Navigates back to the home page. + * @returns True if the navigation was successful + */ + async goBackToHomePage(): Promise { await this.metamaskPlaywright.openSettings() - await expect(this.metamaskExtensionPage.locator(HomePageSelectors.copyAccountAddressButton)).not.toBeVisible() - await this.metamaskPlaywright.goBackToHomePage() - await expect(this.metamaskExtensionPage.locator(HomePageSelectors.copyAccountAddressButton)).toBeVisible() - return true } - async openSettings() { + /** + * Opens the settings page. + * @returns True if the settings page was opened successfully + */ + async openSettings(): Promise { await this.metamaskPlaywright.openSettings() - return true } - async openSidebarMenu(menu: SettingsSidebarMenus) { + /** + * Opens a specific sidebar menu in the settings. + * @param menu - The menu to open + * @returns True if the menu was opened successfully + */ + async openSidebarMenu(menu: SettingsSidebarMenus): Promise { await this.metamaskPlaywright.openSidebarMenu(menu) await expect(this.metamaskExtensionPage.locator(HomePageSelectors.settings.sidebarMenu(menu))).toBeVisible() - return true } } diff --git a/wallets/metamask/src/cypress/configureSynpress.ts b/wallets/metamask/src/cypress/configureSynpress.ts index fbced67ca..8960e76de 100644 --- a/wallets/metamask/src/cypress/configureSynpress.ts +++ b/wallets/metamask/src/cypress/configureSynpress.ts @@ -20,6 +20,38 @@ let metamaskExtensionPage: Page // TODO: Implement if needed to change the focus between pages // let cypressPage: Page +/** + * Configures Synpress for use with MetaMask. + * + * This function sets up the necessary configurations and hooks for running + * Cypress tests with MetaMask. + * + * @param on - Cypress plugin event handler + * @param config - Cypress plugin configuration options + * @param importDefaultWallet - Whether to import the default wallet + * @returns Modified Cypress configuration + * @throws Error If no Chrome browser is found in the configuration + * + * @remarks + * This function performs the following tasks: + * + * 1. Filters the available browsers to ensure only Chrome is used. + * 2. Sets up a 'before:browser:launch' hook to enable debug mode, establish + * a Playwright connection, and initialize MetaMask. + * 3. Sets up a 'before:spec' hook to import the MetaMask wallet before + * each test spec runs. + * 4. Provides task handlers for various MetaMask-related operations. + * + * @example + * ```typescript + * import { configureSynpress } from './configureSynpress'; + * + * export default (on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions) => { + * return configureSynpress(on, config); + * }; + * ``` + */ + export default function configureSynpress( on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions, diff --git a/wallets/metamask/src/cypress/support/initMetaMask.ts b/wallets/metamask/src/cypress/support/initMetaMask.ts index 5266fb93b..ec7b13eef 100644 --- a/wallets/metamask/src/cypress/support/initMetaMask.ts +++ b/wallets/metamask/src/cypress/support/initMetaMask.ts @@ -1,10 +1,19 @@ import { prepareExtension } from '../../prepareExtension' -export async function initMetaMask() { +/** + * Initializes MetaMask for Cypress tests. + * + * This function prepares the MetaMask extension for use in Cypress tests. + * It sets up the necessary browser arguments and extension paths. + * + * @async + * @returns {Promise<{extensions: string[], browserArgs: string[]}>} An object containing the extension path and browser arguments. + */ +export async function initMetaMask(): Promise<{ extensions: string[]; browserArgs: string[] }> { const metamaskPath = await prepareExtension(false) const extensions = [metamaskPath] - const browserArgs = [] + const browserArgs: string[] = [] if (process.env.HEADLESS) { browserArgs.push('--headless=new') diff --git a/wallets/metamask/src/cypress/support/synpressCommands.ts b/wallets/metamask/src/cypress/support/synpressCommands.ts index e46a8a78f..3a4342e93 100644 --- a/wallets/metamask/src/cypress/support/synpressCommands.ts +++ b/wallets/metamask/src/cypress/support/synpressCommands.ts @@ -76,53 +76,135 @@ declare global { } } -export default function synpressCommands() { +/** + * Synpress Commands for MetaMask + * + * This module extends Cypress with custom commands for interacting with MetaMask and Ethereum networks. + * It provides a wide range of functionalities including wallet management, account operations, + * network interactions, token handling, transaction management, and MetaMask UI interactions. + * + * @module SynpressCommandsForMetaMask + * + * Key features: + * - Wallet: Import wallet, connect to dApps + * - Account: Add, switch, rename, reset accounts + * - Network: Switch networks, create and manage Anvil nodes, add custom networks + * - Tokens: Deploy tokens, add new tokens, approve token permissions + * - Transactions: Confirm, reject, and view transaction details + * - MetaMask UI: Lock/unlock, toggle settings, navigate UI + * + * These commands enhance the testing capabilities for Ethereum-based applications, + * allowing for comprehensive end-to-end testing of dApps integrated with MetaMask. + */ + +/** + * Initializes Synpress commands for MetaMask + */ +export default function synpressCommandsForMetaMask(): void { // Wallet + /** + * Imports a wallet using a seed phrase + * @param seedPhrase - The seed phrase to import + */ Cypress.Commands.add('importWallet', (seedPhrase: string) => { return cy.task('importWallet', seedPhrase) }) + /** + * Imports a wallet using a private key + * @param privateKey - The private key to import + */ Cypress.Commands.add('importWalletFromPrivateKey', (privateKey: string) => { return cy.task('importWalletFromPrivateKey', privateKey) }) + /** + * Connects to a dApp + */ Cypress.Commands.add('connectToDapp', () => { return cy.task('connectToDapp') }) // Account + /** + * Gets the current account + */ Cypress.Commands.add('getAccount', () => { return cy.task('getAccount') }) + + /** + * Adds a new account + * @param accountName - The name of the new account + */ Cypress.Commands.add('addNewAccount', (accountName: string) => { return cy.task('addNewAccount', accountName) }) + + /** + * Switches to a different account + * @param accountName - The name of the account to switch to + */ Cypress.Commands.add('switchAccount', (accountName: string) => { return cy.task('switchAccount', accountName) }) + + /** + * Renames an account + * @param currentAccountName - The current name of the account + * @param newAccountName - The new name for the account + */ Cypress.Commands.add('renameAccount', (currentAccountName: string, newAccountName: string) => { return cy.task('renameAccount', { currentAccountName, newAccountName }) }) + + /** + * Gets the address of the current account + * @returns The account address + */ Cypress.Commands.add('getAccountAddress', () => { return cy.task('getAccountAddress') }) + + /** + * Resets the current account + */ Cypress.Commands.add('resetAccount', () => { return cy.task('resetAccount') }) // Network + /** + * Gets the current network + */ Cypress.Commands.add('getNetwork', () => { return cy.task('getNetwork') }) + + /** + * Switches to a different network + * @param networkName - The name of the network to switch to + * @param isTestnet - Whether the network is a testnet + */ Cypress.Commands.add('switchNetwork', (networkName: string, isTestnet = false) => { return cy.task('switchNetwork', { networkName, isTestnet }) }) + + /** + * Creates an Anvil node + * @param options - Options for creating the Anvil node + * @returns An object containing the Anvil instance, RPC URL, and chain ID + */ Cypress.Commands.add('createAnvilNode', (options?: CreateAnvilOptions) => { return cy.task('createAnvilNode', options) }) + + /** + * Connects to an Anvil node + */ Cypress.Commands.add('connectToAnvil', () => { return cy.task('createAnvilNode').then((anvilNetwork) => { const anvilNetworkDetails = anvilNetwork as { @@ -142,33 +224,72 @@ export default function synpressCommands() { return cy.task('addNetwork', network) }) }) + + /** + * Empties the Anvil node + */ Cypress.Commands.add('emptyAnvilNode', () => { return cy.task('emptyAnvilNode') }) + + /** + * Adds a new network + * @param network - The network to add + */ Cypress.Commands.add('addNetwork', (network: Network) => { return cy.task('addNetwork', network) }) + + /** + * Approves adding a new network + */ Cypress.Commands.add('approveNewNetwork', () => { return cy.task('approveNewNetwork') }) + + /** + * Approves switching to a new network + */ Cypress.Commands.add('approveSwitchNetwork', () => { return cy.task('approveSwitchNetwork') }) + + /** + * Rejects adding a new network + */ Cypress.Commands.add('rejectNewNetwork', () => { return cy.task('rejectNewNetwork') }) + + /** + * Rejects switching to a new network + */ Cypress.Commands.add('rejectSwitchNetwork', () => { return cy.task('rejectSwitchNetwork') }) // Token + /** + * Deploys a token + */ Cypress.Commands.add('deployToken', () => { return cy.task('deployToken') }) + + /** + * Adds a new token + */ Cypress.Commands.add('addNewToken', () => { return cy.task('addNewToken') }) + + /** + * Approves token permission + * @param options - Options for approving token permission + * @param options.spendLimit - The spend limit for the token + * @param options.gasSetting - Gas settings for the transaction + */ Cypress.Commands.add( 'approveTokenPermission', (options?: { @@ -178,63 +299,132 @@ export default function synpressCommands() { return cy.task('approveTokenPermission', options) } ) + + /** + * Rejects token permission + */ Cypress.Commands.add('rejectTokenPermission', () => { return cy.task('rejectTokenPermission') }) // Lock/Unlock + /** + * Locks MetaMask + */ Cypress.Commands.add('lock', () => { return cy.task('lock') }) + + /** + * Unlocks MetaMask + */ Cypress.Commands.add('unlock', () => { return cy.task('unlock') }) // Toggles + /** + * Toggles showing test networks + */ Cypress.Commands.add('toggleShowTestNetworks', () => { return cy.task('toggleShowTestNetworks') }) + + /** + * Toggles dismissing the secret recovery phrase reminder + */ Cypress.Commands.add('toggleDismissSecretRecoveryPhraseReminder', () => { return cy.task('toggleDismissSecretRecoveryPhraseReminder') }) // Others + /** + * Provides a public encryption key + */ Cypress.Commands.add('providePublicEncryptionKey', () => { return cy.task('providePublicEncryptionKey') }) + + /** + * Decrypts a message + */ Cypress.Commands.add('decrypt', () => { return cy.task('decrypt') }) + + /** + * Confirms a signature + */ Cypress.Commands.add('confirmSignature', () => { return cy.task('confirmSignature') }) + + /** + * Rejects a signature + */ Cypress.Commands.add('rejectSignature', () => { return cy.task('rejectSignature') }) + + /** + * Confirms a transaction + * @param options - Options for confirming the transaction + * @param options.gasSetting - Gas settings for the transaction + */ Cypress.Commands.add('confirmTransaction', (options?: { gasSetting?: GasSettings }) => { return cy.task('confirmTransaction', options) }) + + /** + * Rejects a transaction + */ Cypress.Commands.add('rejectTransaction', () => { return cy.task('rejectTransaction') }) + + /** + * Confirms a transaction and waits for mining + */ Cypress.Commands.add('confirmTransactionAndWaitForMining', () => { return cy.task('confirmTransactionAndWaitForMining') }) + + /** + * Opens transaction details + * @param txIndex - The index of the transaction to open + */ Cypress.Commands.add('openTransactionDetails', (txIndex = 0) => { return cy.task('openTransactionDetails', txIndex) }) + + /** + * Closes transaction details + */ Cypress.Commands.add('closeTransactionDetails', () => { return cy.task('closeTransactionDetails') }) + + /** + * Goes back to the home page + */ Cypress.Commands.add('goBackToHomePage', () => { return cy.task('goBackToHomePage') }) + + /** + * Opens settings + */ Cypress.Commands.add('openSettings', () => { return cy.task('openSettings') }) + + /** + * Opens a sidebar menu + * @param menu - The menu to open + */ Cypress.Commands.add('openSidebarMenu', (menu: SettingsSidebarMenus) => { return cy.task('openSidebarMenu', menu) }) diff --git a/wallets/metamask/src/playwright/MetaMask.ts b/wallets/metamask/src/playwright/MetaMask.ts index 19f56f57e..b3120c7de 100644 --- a/wallets/metamask/src/playwright/MetaMask.ts +++ b/wallets/metamask/src/playwright/MetaMask.ts @@ -8,61 +8,81 @@ import { SettingsPage } from './pages/SettingsPage/page' const NO_EXTENSION_ID_ERROR = new Error('MetaMask extensionId is not set') +/** + * MetaMask class for interacting with the MetaMask extension in Playwright tests. + * + * This class provides methods to perform various operations on the MetaMask extension, + * such as importing wallets, switching networks, confirming transactions, and more. + * + * @class + * @extends MetaMaskAbstract + */ export class MetaMask extends MetaMaskAbstract { /** - * This property can be used to access selectors for a given page. + * This property can be used to access selectors for the crash page. * - * @group Selectors + * @public + * @readonly */ readonly crashPage: CrashPage + /** - * This property can be used to access selectors for a given page. + * This property can be used to access selectors for the onboarding page. * - * @group Selectors + * @public + * @readonly */ readonly onboardingPage: OnboardingPage + /** - * This property can be used to access selectors for a given page. + * This property can be used to access selectors for the lock page. * - * @group Selectors + * @public + * @readonly */ readonly lockPage: LockPage + /** - * This property can be used to access selectors for a given page. + * This property can be used to access selectors for the home page. * - * @group Selectors + * @public + * @readonly */ readonly homePage: HomePage + /** - * This property can be used to access selectors for a given page. + * This property can be used to access selectors for the notification page. * - * @group Selectors + * @public + * @readonly */ readonly notificationPage: NotificationPage + + /** + * This property can be used to access selectors for the settings page. + * + * @public + * @readonly + */ readonly settingsPage: SettingsPage + /** + * Creates an instance of MetaMask. + * + * @param context - The Playwright BrowserContext in which the MetaMask extension is running. + * @param page - The Playwright Page object representing the MetaMask extension's main page. + * @param password - The password for the MetaMask wallet. + * @param extensionId - The ID of the MetaMask extension. Optional if no interaction with dapps is required. + */ constructor( - /** - * The browser context. - */ readonly context: BrowserContext, - /** - * The MetaMask tab page. - */ readonly page: Page, - /** - * The password of the MetaMask wallet. - */ override readonly password: string, - /** - * The extension ID of the MetaMask extension. Optional if no interaction with the dapp is required. - */ override readonly extensionId?: string ) { super(password, extensionId) this.crashPage = new CrashPage() - this.onboardingPage = new OnboardingPage(page) this.lockPage = new LockPage(page) this.homePage = new HomePage(page) @@ -70,11 +90,21 @@ export class MetaMask extends MetaMaskAbstract { this.settingsPage = new SettingsPage(page) } - async importWallet(seedPhrase: string) { + /** + * Imports a wallet using the given seed phrase. + * + * @param seedPhrase - The seed phrase to import. + */ + async importWallet(seedPhrase: string): Promise { await this.onboardingPage.importWallet(seedPhrase, this.password) } - async addNewAccount(accountName: string) { + /** + * Adds a new account with the given name. + * + * @param accountName - The name for the new account. + */ + async addNewAccount(accountName: string): Promise { await this.homePage.addNewAccount(accountName) } @@ -84,7 +114,7 @@ export class MetaMask extends MetaMaskAbstract { * @param currentAccountName - The current account name. * @param newAccountName - The new name for the account. */ - async renameAccount(currentAccountName: string, newAccountName: string) { + async renameAccount(currentAccountName: string, newAccountName: string): Promise { await this.homePage.renameAccount(currentAccountName, newAccountName) } @@ -93,28 +123,54 @@ export class MetaMask extends MetaMaskAbstract { * * @param privateKey - The private key to import. */ - - async importWalletFromPrivateKey(privateKey: string) { + async importWalletFromPrivateKey(privateKey: string): Promise { await this.homePage.importWalletFromPrivateKey(privateKey) } - async switchAccount(accountName: string) { + /** + * Switches to the account with the given name. + * + * @param accountName - The name of the account to switch to. + */ + async switchAccount(accountName: string): Promise { await this.homePage.switchAccount(accountName) } - async addNetwork(network: Network) { + /** + * Adds a new network to MetaMask. + * + * @param network - The network configuration to add. + */ + async addNetwork(network: Network): Promise { await this.homePage.addNetwork(network) } - async getAccountAddress() { + /** + * Gets the address of the currently selected account. + * + * @returns The account address. + */ + async getAccountAddress(): Promise { return await this.homePage.getAccountAddress() } - async switchNetwork(networkName: string, isTestnet = false) { + /** + * Switches to the specified network. + * + * @param networkName - The name of the network to switch to. + * @param isTestnet - Whether the network is a testnet. Default is false. + */ + async switchNetwork(networkName: string, isTestnet = false): Promise { await this.homePage.switchNetwork(networkName, isTestnet) } - async connectToDapp(accounts?: string[]) { + /** + * Connects MetaMask to a dapp. + * + * @param accounts - Optional array of account addresses to connect. + * @throws {Error} If extensionId is not set. + */ + async connectToDapp(accounts?: string[]): Promise { if (!this.extensionId) { throw NO_EXTENSION_ID_ERROR } @@ -122,15 +178,26 @@ export class MetaMask extends MetaMaskAbstract { await this.notificationPage.connectToDapp(this.extensionId, accounts) } - async lock() { + /** + * Locks the MetaMask wallet. + */ + async lock(): Promise { await this.homePage.lock() } - async unlock() { + /** + * Unlocks the MetaMask wallet. + */ + async unlock(): Promise { await this.lockPage.unlock(this.password) } - async confirmSignature() { + /** + * Confirms a signature request. + * + * @throws {Error} If extensionId is not set. + */ + async confirmSignature(): Promise { if (!this.extensionId) { throw NO_EXTENSION_ID_ERROR } @@ -138,7 +205,12 @@ export class MetaMask extends MetaMaskAbstract { await this.notificationPage.signMessage(this.extensionId) } - async confirmSignatureWithRisk() { + /** + * Confirms a signature request with risk. + * + * @throws {Error} If extensionId is not set. + */ + async confirmSignatureWithRisk(): Promise { if (!this.extensionId) { throw NO_EXTENSION_ID_ERROR } @@ -146,7 +218,12 @@ export class MetaMask extends MetaMaskAbstract { await this.notificationPage.signMessageWithRisk(this.extensionId) } - async rejectSignature() { + /** + * Rejects a signature request. + * + * @throws {Error} If extensionId is not set. + */ + async rejectSignature(): Promise { if (!this.extensionId) { throw NO_EXTENSION_ID_ERROR } @@ -154,7 +231,12 @@ export class MetaMask extends MetaMaskAbstract { await this.notificationPage.rejectMessage(this.extensionId) } - async approveNewNetwork() { + /** + * Approves adding a new network. + * + * @throws {Error} If extensionId is not set. + */ + async approveNewNetwork(): Promise { if (!this.extensionId) { throw NO_EXTENSION_ID_ERROR } @@ -162,7 +244,12 @@ export class MetaMask extends MetaMaskAbstract { await this.notificationPage.approveNewNetwork(this.extensionId) } - async rejectNewNetwork() { + /** + * Rejects adding a new network. + * + * @throws {Error} If extensionId is not set. + */ + async rejectNewNetwork(): Promise { if (!this.extensionId) { throw NO_EXTENSION_ID_ERROR } @@ -170,7 +257,12 @@ export class MetaMask extends MetaMaskAbstract { await this.notificationPage.rejectNewNetwork(this.extensionId) } - async approveSwitchNetwork() { + /** + * Approves switching to a new network. + * + * @throws {Error} If extensionId is not set. + */ + async approveSwitchNetwork(): Promise { if (!this.extensionId) { throw NO_EXTENSION_ID_ERROR } @@ -178,7 +270,12 @@ export class MetaMask extends MetaMaskAbstract { await this.notificationPage.approveSwitchNetwork(this.extensionId) } - async rejectSwitchNetwork() { + /** + * Rejects switching to a new network. + * + * @throws {Error} If extensionId is not set. + */ + async rejectSwitchNetwork(): Promise { if (!this.extensionId) { throw NO_EXTENSION_ID_ERROR } @@ -186,7 +283,13 @@ export class MetaMask extends MetaMaskAbstract { await this.notificationPage.rejectSwitchNetwork(this.extensionId) } - async confirmTransaction(options?: { gasSetting?: GasSettings }) { + /** + * Confirms a transaction. + * + * @param options - Optional gas settings for the transaction. + * @throws {Error} If extensionId is not set. + */ + async confirmTransaction(options?: { gasSetting?: GasSettings }): Promise { if (!this.extensionId) { throw NO_EXTENSION_ID_ERROR } @@ -194,7 +297,12 @@ export class MetaMask extends MetaMaskAbstract { await this.notificationPage.confirmTransaction(this.extensionId, options) } - async rejectTransaction() { + /** + * Rejects a transaction. + * + * @throws {Error} If extensionId is not set. + */ + async rejectTransaction(): Promise { if (!this.extensionId) { throw NO_EXTENSION_ID_ERROR } @@ -202,10 +310,16 @@ export class MetaMask extends MetaMaskAbstract { await this.notificationPage.rejectTransaction(this.extensionId) } + /** + * Approves a token permission request. + * + * @param options - Optional settings for the approval. + * @throws {Error} If extensionId is not set. + */ async approveTokenPermission(options?: { spendLimit?: 'max' | number gasSetting?: GasSettings - }) { + }): Promise { if (!this.extensionId) { throw NO_EXTENSION_ID_ERROR } @@ -213,7 +327,12 @@ export class MetaMask extends MetaMaskAbstract { await this.notificationPage.approveTokenPermission(this.extensionId, options) } - async rejectTokenPermission() { + /** + * Rejects a token permission request. + * + * @throws {Error} If extensionId is not set. + */ + async rejectTokenPermission(): Promise { if (!this.extensionId) { throw NO_EXTENSION_ID_ERROR } @@ -221,41 +340,72 @@ export class MetaMask extends MetaMaskAbstract { await this.notificationPage.rejectTokenPermission(this.extensionId) } - async goBackToHomePage() { + /** + * Navigates back to the home page. + */ + async goBackToHomePage(): Promise { await this.homePage.goBackToHomePage() } - async openSettings() { + /** + * Opens the settings page. + */ + async openSettings(): Promise { await this.homePage.openSettings() } - async openSidebarMenu(menu: SettingsSidebarMenus) { + /** + * Opens a specific sidebar menu in the settings. + * + * @param menu - The menu to open. + */ + async openSidebarMenu(menu: SettingsSidebarMenus): Promise { await this.homePage.openSidebarMenu(menu) } - async toggleShowTestNetworks() { + /** + * Toggles the display of test networks. + */ + async toggleShowTestNetworks(): Promise { await this.homePage.toggleShowTestNetworks() } - async toggleDismissSecretRecoveryPhraseReminder() { + /** + * Toggles the dismissal of the secret recovery phrase reminder. + */ + async toggleDismissSecretRecoveryPhraseReminder(): Promise { await this.homePage.toggleDismissSecretRecoveryPhraseReminder() } - async resetAccount() { + /** + * Resets the account. + */ + async resetAccount(): Promise { await this.homePage.resetAccount() } - async unsafe_enableEthSign() { + /** + * Enables eth_sign (unsafe). + */ + async unsafe_enableEthSign(): Promise { await this.homePage.openSettings() await this.settingsPage.enableEthSign() } - async disableEthSign() { + /** + * Disables eth_sign. + */ + async disableEthSign(): Promise { await this.homePage.openSettings() await this.settingsPage.disableEthSign() } - async addNewToken() { + /** + * Adds a new token. + * + * @throws {Error} If extensionId is not set. + */ + async addNewToken(): Promise { if (!this.extensionId) { throw NO_EXTENSION_ID_ERROR } @@ -263,7 +413,12 @@ export class MetaMask extends MetaMaskAbstract { await this.notificationPage.addNewToken(this.extensionId) } - async providePublicEncryptionKey() { + /** + * Provides a public encryption key. + * + * @throws {Error} If extensionId is not set. + */ + async providePublicEncryptionKey(): Promise { if (!this.extensionId) { throw NO_EXTENSION_ID_ERROR } @@ -271,7 +426,12 @@ export class MetaMask extends MetaMaskAbstract { await this.notificationPage.providePublicEncryptionKey(this.extensionId) } - async decrypt() { + /** + * Decrypts a message. + * + * @throws {Error} If extensionId is not set. + */ + async decrypt(): Promise { if (!this.extensionId) { throw NO_EXTENSION_ID_ERROR } @@ -279,9 +439,15 @@ export class MetaMask extends MetaMaskAbstract { await this.notificationPage.decryptMessage(this.extensionId) } + /** + * Confirms a transaction and waits for it to be mined. + * + * @param options - Optional gas settings for the transaction. + * @throws {Error} If extensionId is not set. + */ async confirmTransactionAndWaitForMining(options?: { gasSetting?: GasSettings - }) { + }): Promise { if (!this.extensionId) { throw NO_EXTENSION_ID_ERROR } @@ -289,11 +455,19 @@ export class MetaMask extends MetaMaskAbstract { await this.notificationPage.confirmTransactionAndWaitForMining(this.extensionId, options) } - async openTransactionDetails(txIndex: number) { + /** + * Opens the details of a specific transaction. + * + * @param txIndex - The index of the transaction to open. + */ + async openTransactionDetails(txIndex: number): Promise { await this.homePage.openTransactionDetails(txIndex) } - async closeTransactionDetails() { + /** + * Closes the transaction details view. + */ + async closeTransactionDetails(): Promise { await this.homePage.closeTransactionDetails() } }