Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ feat: Test cases for network management and new tokens deployment #1193

Merged
merged 3 commits into from
Aug 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 96 additions & 1 deletion wallets/metamask/src/cypress/configureSynpress.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import type { BrowserContext, Page } from '@playwright/test'
import { expect } from '@playwright/test'
import { ensureRdpPort } from '@synthetixio/synpress-core'
import { type CreateAnvilOptions, createPool } from '@viem/anvil'
import { waitFor } from '../playwright/utils/waitFor'
import HomePageSelectors from '../selectors/pages/HomePage'
import Selectors from '../selectors/pages/HomePage'
import type { Network } from '../type/Network'
import getPlaywrightMetamask from './getPlaywrightMetamask'
import importMetaMaskWallet from './support/importMetaMaskWallet'
import { initMetaMask } from './support/initMetaMask'
Expand Down Expand Up @@ -118,7 +122,7 @@ export default function configureSynpress(on: Cypress.PluginEvents, config: Cypr

await metamask.renameAccount(currentAccountName, newAccountName)

await metamaskExtensionPage.locator(Selectors.threeDotsMenu.accountDetailsCloseButton).click()
await metamaskExtensionPage.locator(HomePageSelectors.threeDotsMenu.accountDetailsCloseButton).click()

await expect(metamaskExtensionPage.locator(metamask.homePage.selectors.accountMenu.accountButton)).toHaveText(
newAccountName
Expand Down Expand Up @@ -146,6 +150,84 @@ export default function configureSynpress(on: Cypress.PluginEvents, config: Cypr
})
},

async createAnvilNode(options?: CreateAnvilOptions) {
const 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 connectToAnvil({
rpcUrl,
chainId
}: {
rpcUrl: string
chainId: number
}) {
const metamask = getPlaywrightMetamask(context, metamaskExtensionPage, metamaskExtensionId)

try {
await metamask.addNetwork({
name: 'Anvil',
rpcUrl,
chainId,
symbol: 'ETH',
blockExplorerUrl: 'https://etherscan.io/'
})

await metamask.switchNetwork('Anvil')
return true
} catch (e) {
console.error('Error connecting to Anvil network', e)
return false
}
},

async addNetwork(network: Network) {
const metamask = getPlaywrightMetamask(context, metamaskExtensionPage, metamaskExtensionId)

await metamask.addNetwork(network)

await waitFor(
() => metamaskExtensionPage.locator(HomePageSelectors.networkAddedPopover.switchToNetworkButton).isVisible(),
3_000,
false
)

await metamaskExtensionPage.locator(HomePageSelectors.networkAddedPopover.switchToNetworkButton).click()

return true
},

// Token

async deployToken() {
const metamask = getPlaywrightMetamask(context, metamaskExtensionPage, metamaskExtensionId)

await metamask.confirmTransaction()

return true
},

async addNewToken() {
const metamask = getPlaywrightMetamask(context, metamaskExtensionPage, metamaskExtensionId)

await metamask.addNewToken()

await expect(metamaskExtensionPage.locator(Selectors.portfolio.singleToken).nth(1)).toContainText('TST')

return true
},

// Others

async providePublicEncryptionKey() {
const metamask = getPlaywrightMetamask(context, metamaskExtensionPage, metamaskExtensionId)

Expand Down Expand Up @@ -183,6 +265,19 @@ export default function configureSynpress(on: Cypress.PluginEvents, config: Cypr
.catch(() => {
return false
})
},

async confirmTransaction() {
const metamask = getPlaywrightMetamask(context, metamaskExtensionPage, metamaskExtensionId)

return await metamask
.confirmTransaction()
.then(() => {
return true
})
.catch(() => {
return false
})
}
})

Expand Down
59 changes: 59 additions & 0 deletions wallets/metamask/src/cypress/support/synpressCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
// https://on.cypress.io/custom-commands
// ***********************************************

import type { Anvil, CreateAnvilOptions } from '@viem/anvil'
import type { Network } from '../../type/Network'

declare global {
namespace Cypress {
interface Chainable {
Expand All @@ -22,9 +25,21 @@ declare global {
renameAccount(currentAccountName: string, newAccountName: string): Chainable<void>

switchNetwork(networkName: string, isTestnet?: boolean): Chainable<void>
createAnvilNode(options?: CreateAnvilOptions): Chainable<{
anvil: Anvil
rpcUrl: string
chainId: number
}>
connectToAnvil(): Chainable<void>
addNetwork(network: Network): Chainable<void>

deployToken(): Chainable<void>
addNewToken(): Chainable<void>

providePublicEncryptionKey(): Chainable<void>
decrypt(): Chainable<void>
confirmSignature(): Chainable<void>
confirmTransaction(): Chainable<void>
}
}
}
Expand All @@ -41,6 +56,8 @@ export default function synpressCommands() {
return cy.task('connectToDapp')
})

// Account

Cypress.Commands.add('addNewAccount', (accountName: string) => {
return cy.task('addNewAccount', accountName)
})
Expand All @@ -51,9 +68,48 @@ export default function synpressCommands() {
return cy.task('renameAccount', { currentAccountName, newAccountName })
})

// Network

Cypress.Commands.add('switchNetwork', (networkName: string, isTestnet = false) => {
return cy.task('switchNetwork', { networkName, isTestnet })
})
Cypress.Commands.add('createAnvilNode', (options?: CreateAnvilOptions) => {
return cy.task('createAnvilNode', options)
})
Cypress.Commands.add('connectToAnvil', () => {
return cy.task('createAnvilNode').then((anvilNetwork) => {
const anvilNetworkDetails = anvilNetwork as {
anvil: Anvil
rpcUrl: string
chainId: number
}

const network = {
name: 'Anvil',
rpcUrl: anvilNetworkDetails.rpcUrl,
chainId: anvilNetworkDetails.chainId,
symbol: 'ETH',
blockExplorerUrl: 'https://etherscan.io/'
}

return cy.task('addNetwork', network)
})
})
Cypress.Commands.add('addNetwork', (network: Network) => {
return cy.task('addNetwork', network)
})

// Token

Cypress.Commands.add('deployToken', () => {
return cy.task('deployToken')
})
Cypress.Commands.add('addNewToken', () => {
return cy.task('addNewToken')
})

// Others

Cypress.Commands.add('providePublicEncryptionKey', () => {
return cy.task('providePublicEncryptionKey')
})
Expand All @@ -63,4 +119,7 @@ export default function synpressCommands() {
Cypress.Commands.add('confirmSignature', () => {
return cy.task('confirmSignature')
})
Cypress.Commands.add('confirmTransaction', () => {
return cy.task('confirmTransaction')
})
}
2 changes: 1 addition & 1 deletion wallets/metamask/src/playwright/MetaMask.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { BrowserContext, Page } from '@playwright/test'
import { SettingsSidebarMenus } from '../selectors/pages/HomePage/settings'
import { MetaMaskAbstract } from '../type/MetaMaskAbstract'
import type { Network } from '../type/Network'
import { CrashPage, HomePage, LockPage, NotificationPage, OnboardingPage } from './pages'
import type { Network } from './pages/HomePage/actions'
import type { GasSetting } from './pages/NotificationPage/actions'
import { SettingsPage } from './pages/SettingsPage/page'

Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,11 @@
import type { Page } from '@playwright/test'
import { z } from 'zod'
import Selectors from '../../../../selectors/pages/HomePage'
import { type Network, NetworkValidation } from '../../../../type/Network'
import { waitFor } from '../../../utils/waitFor'
import { closeNetworkAddedPopover, closeNewNetworkInfoPopover } from './popups'

const Network = z.object({
name: z.string(),
rpcUrl: z.string(),
chainId: z.number(),
symbol: z.string(),
blockExplorerUrl: z.string().optional()
})

export type Network = z.infer<typeof Network>

export async function addNetwork(page: Page, network: Network) {
const { name, rpcUrl, chainId, symbol, blockExplorerUrl } = Network.parse(network)
const { name, rpcUrl, chainId, symbol, blockExplorerUrl } = NetworkValidation.parse(network)

await page.locator(Selectors.networkDropdown.dropdownButton).click()
await page.locator(Selectors.networkDropdown.addNetworkButton).click()
Expand Down
2 changes: 1 addition & 1 deletion wallets/metamask/src/playwright/pages/HomePage/page.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Page } from '@playwright/test'
import Selectors from '../../../selectors/pages/HomePage'
import type { SettingsSidebarMenus } from '../../../selectors/pages/HomePage/settings'
import type { Network } from '../../../type/Network'
import {
addNetwork,
addNewAccount,
Expand All @@ -14,7 +15,6 @@ import {
toggleShowTestNetworks,
transactionDetails
} from './actions'
import type { Network } from './actions'

export class HomePage {
static readonly selectors = Selectors
Expand Down
2 changes: 1 addition & 1 deletion wallets/metamask/src/selectors/pages/HomePage/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const popover = {
}

const networkAddedPopover = {
switchToNetworkButton: '.home__new-network-added button.btn-primary',
switchToNetworkButton: '.home__new-network-added__switch-to-button',
dismissButton: '.home__new-network-added button.btn-secondary'
}

Expand Down
2 changes: 1 addition & 1 deletion wallets/metamask/src/type/MetaMaskAbstract.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Network } from '../playwright/pages/HomePage/actions'
import type { GasSetting } from '../playwright/pages/NotificationPage/actions'
import { SettingsSidebarMenus } from '../selectors/pages/HomePage/settings'
import type { Network } from './Network'

export abstract class MetaMaskAbstract {
/**
Expand Down
11 changes: 11 additions & 0 deletions wallets/metamask/src/type/Network.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { z } from 'zod'

export const NetworkValidation = z.object({
name: z.string(),
rpcUrl: z.string(),
chainId: z.number(),
symbol: z.string(),
blockExplorerUrl: z.string().optional()
})

export type Network = z.infer<typeof NetworkValidation>
31 changes: 31 additions & 0 deletions wallets/metamask/test/cypress/addNetwork.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
it('should add network and close network added popup', () => {
cy.createAnvilNode().then(({ rpcUrl, chainId }) => {
const network = {
name: 'Anvil',
rpcUrl,
chainId,
symbol: 'ETH',
blockExplorerUrl: 'https://etherscan.io/'
}

cy.addNetwork(network).then(() => cy.getNetwork().should('eq', 'Anvil'))
})
})

it('should add network without block explorer', () => {
cy.createAnvilNode().then(({ rpcUrl, chainId }) => {
const network = {
name: 'Anvil2',
rpcUrl,
chainId,
symbol: 'ETH',
blockExplorerUrl: undefined
}

cy.addNetwork(network).then(() => cy.getNetwork().should('eq', 'Anvil2'))
})
})

after(() => {
cy.switchNetwork('Anvil', true)
})
42 changes: 42 additions & 0 deletions wallets/metamask/test/cypress/addNewToken.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
before(() => {
cy.getNetwork().then((network) => {
console.log(network)
if (network !== 'Anvil') {
cy.switchNetwork('Anvil')
}
})

cy.get('#connectButton').click()

cy.connectToDapp()
})

it('should add new token to MetaMask', () => {
cy.get('#createToken').click()

// wait for the blockchain - todo: replace with an event handler
cy.wait(5000)

cy.deployToken().then(() => {
// wait for the blockchain - todo: replace with an event handler
cy.wait(5000)

cy.get('#tokenAddresses').should('have.text', '0x7ef8E99980Da5bcEDcF7C10f41E55f759F6A174B')

cy.get('#watchAssets').click()

cy.addNewToken()
})
})

it('should add new token using EIP747', () => {
cy.get('#eip747ContractAddress').type('0x5FbDB2315678afecb367f032d93F642f64180aa3')
cy.get('#eip747Symbol').type('TST')
cy.get('#eip747Decimals').type('4')

cy.get('#eip747WatchButton').click()

cy.addNewToken().then(() => {
cy.get('#eip747Status').should('have.text', 'NFT added successfully')
})
})
Loading
Loading