Skip to content

Commit

Permalink
feat: Add approveTokenPermission to Cypress API
Browse files Browse the repository at this point in the history
  • Loading branch information
matstyler committed Aug 27, 2024
1 parent 6f9fa5a commit dc65689
Show file tree
Hide file tree
Showing 11 changed files with 196 additions and 45 deletions.
25 changes: 25 additions & 0 deletions wallets/metamask/src/cypress/MetaMask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { MetaMask as MetaMaskPlaywright } from '../playwright/MetaMask'
import { waitFor } from '../playwright/utils/waitFor'
import HomePageSelectors from '../selectors/pages/HomePage'
import Selectors from '../selectors/pages/HomePage'
import TransactionPage from '../selectors/pages/NotificationPage/transactionPage'
import type { GasSettings } from '../type/GasSettings'
import type { Network } from '../type/Network'
import getPlaywrightMetamask from './getPlaywrightMetamask'

Expand Down Expand Up @@ -152,6 +154,13 @@ export default class MetaMask {
// Token

async deployToken() {
await waitFor(
() =>
this.metamaskExtensionPage.locator(TransactionPage.nftApproveAllConfirmationPopup.approveButton).isVisible(),
3_000,
false
)

await this.metamaskPlaywright.confirmTransaction()

return true
Expand All @@ -165,6 +174,22 @@ export default class MetaMask {
return true
}

async approveTokenPermission(options?: {
spendLimit?: number | 'max'
gasSetting?: GasSettings
}) {
return await this.metamaskPlaywright
.approveTokenPermission(options)
.then(() => {
return true
})
.catch(() => {
return false
})
}

// Network

async approveNewNetwork() {
await this.metamaskPlaywright.approveNewNetwork()

Expand Down
5 changes: 5 additions & 0 deletions wallets/metamask/src/cypress/configureSynpress.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { BrowserContext, Page } from '@playwright/test'
import { ensureRdpPort } from '@synthetixio/synpress-core'
import type { CreateAnvilOptions } from '@viem/anvil'
import type { GasSettings } from '../type/GasSettings'
import type { Network } from '../type/Network'
import MetaMask from './MetaMask'
import importMetaMaskWallet from './support/importMetaMaskWallet'
Expand Down Expand Up @@ -100,6 +101,10 @@ export default function configureSynpress(on: Cypress.PluginEvents, config: Cypr
// Token
deployToken: () => metamask?.deployToken(),
addNewToken: () => metamask?.addNewToken(),
approveTokenPermission: (options?: {
spendLimit?: number | 'max'
gasSetting?: GasSettings
}) => metamask?.approveTokenPermission(options),

// Encryption
providePublicEncryptionKey: () => metamask?.providePublicEncryptionKey(),
Expand Down
14 changes: 14 additions & 0 deletions wallets/metamask/src/cypress/support/synpressCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
// ***********************************************

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

declare global {
Expand Down Expand Up @@ -38,6 +39,10 @@ declare global {

deployToken(): Chainable<void>
addNewToken(): Chainable<void>
approveTokenPermission(options?: {
spendLimit?: number | 'max'
gasSetting?: GasSettings
}): Chainable<void>

providePublicEncryptionKey(): Chainable<void>
decrypt(): Chainable<void>
Expand Down Expand Up @@ -122,6 +127,15 @@ export default function synpressCommands() {
Cypress.Commands.add('addNewToken', () => {
return cy.task('addNewToken')
})
Cypress.Commands.add(
'approveTokenPermission',
(options?: {
spendLimit?: number | 'max'
gasSetting?: GasSettings
}) => {
return cy.task('approveTokenPermission', options)
}
)

// Others

Expand Down
8 changes: 4 additions & 4 deletions wallets/metamask/src/playwright/MetaMask.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { BrowserContext, Page } from '@playwright/test'
import { SettingsSidebarMenus } from '../selectors/pages/HomePage/settings'
import type { GasSettings } from '../type/GasSettings'
import { MetaMaskAbstract } from '../type/MetaMaskAbstract'
import type { Network } from '../type/Network'
import { CrashPage, HomePage, LockPage, NotificationPage, OnboardingPage } from './pages'
import type { GasSetting } from './pages/NotificationPage/actions'
import { SettingsPage } from './pages/SettingsPage/page'

const NO_EXTENSION_ID_ERROR = new Error('MetaMask extensionId is not set')
Expand Down Expand Up @@ -186,7 +186,7 @@ export class MetaMask extends MetaMaskAbstract {
await this.notificationPage.rejectSwitchNetwork(this.extensionId)
}

async confirmTransaction(options?: { gasSetting?: GasSetting }) {
async confirmTransaction(options?: { gasSetting?: GasSettings }) {
if (!this.extensionId) {
throw NO_EXTENSION_ID_ERROR
}
Expand All @@ -204,7 +204,7 @@ export class MetaMask extends MetaMaskAbstract {

async approveTokenPermission(options?: {
spendLimit?: 'max' | number
gasSetting?: GasSetting
gasSetting?: GasSettings
}) {
if (!this.extensionId) {
throw NO_EXTENSION_ID_ERROR
Expand Down Expand Up @@ -280,7 +280,7 @@ export class MetaMask extends MetaMaskAbstract {
}

async confirmTransactionAndWaitForMining(options?: {
gasSetting?: GasSetting
gasSetting?: GasSettings
}) {
if (!this.extensionId) {
throw NO_EXTENSION_ID_ERROR
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const editTokenPermission = async (notificationPage: Page, customSpendLimit: 'ma
.fill(customSpendLimit.toString())
}

const approveTokenPermission = async (notificationPage: Page, gasSetting: GasSetting) => {
const approveTokenPermission = async (notificationPage: Page, gasSetting: GasSettings) => {
// Click the "Next" button.
await notificationPage.locator(Selectors.ActionFooter.confirmActionButton).click()

Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,11 @@
import type { Page } from '@playwright/test'
import { z } from 'zod'
import HomePageSelectors from '../../../../selectors/pages/HomePage'
import Selectors from '../../../../selectors/pages/NotificationPage'
import { GasSettingValidation, type GasSettings } from '../../../../type/GasSettings'
import { waitFor } from '../../../utils/waitFor'

const GasSetting = z.union([
z.literal('low'),
z.literal('market'),
z.literal('aggressive'),
z.literal('site'),
z
.object({
maxBaseFee: z.number(),
priorityFee: z.number(),
// TODO: Add gasLimit range validation.
gasLimit: z.number().optional()
})
.superRefine(({ maxBaseFee, priorityFee }, ctx) => {
if (priorityFee > maxBaseFee) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'Max base fee cannot be lower than priority fee',
path: ['MetaMask', 'confirmTransaction', 'gasSetting', 'maxBaseFee']
})
}
})
])

export type GasSetting = z.input<typeof GasSetting>

const confirmTransaction = async (notificationPage: Page, options: GasSetting) => {
const gasSetting = GasSetting.parse(options)
const confirmTransaction = async (notificationPage: Page, options: GasSettings) => {
const gasSetting = GasSettingValidation.parse(options)

const handleNftSetApprovalForAll = async (page: Page) => {
try {
Expand Down Expand Up @@ -144,7 +119,7 @@ const confirmTransaction = async (notificationPage: Page, options: GasSetting) =
await handleNftSetApprovalForAll(notificationPage)
}

const confirmTransactionAndWaitForMining = async (walletPage: Page, notificationPage: Page, options: GasSetting) => {
const confirmTransactionAndWaitForMining = async (walletPage: Page, notificationPage: Page, options: GasSettings) => {
await walletPage.locator(HomePageSelectors.activityTab.activityTabButton).click()

const waitForUnapprovedTxs = async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { Page } from '@playwright/test'
import Selectors from '../../../selectors/pages/NotificationPage'
import type { GasSettings } from '../../../type/GasSettings'
import { getNotificationPageAndWaitForLoad } from '../../utils/getNotificationPageAndWaitForLoad'
import {
type GasSetting,
approvePermission,
connectToDapp,
decryptMessage,
Expand Down Expand Up @@ -99,7 +99,7 @@ export class NotificationPage {
await network.rejectSwitchNetwork(notificationPage)
}

async confirmTransaction(extensionId: string, options?: { gasSetting?: GasSetting }) {
async confirmTransaction(extensionId: string, options?: { gasSetting?: GasSettings }) {
const notificationPage = await getNotificationPageAndWaitForLoad(this.page.context(), extensionId)

await transaction.confirm(notificationPage, options?.gasSetting ?? 'site')
Expand All @@ -111,15 +111,15 @@ export class NotificationPage {
await transaction.reject(notificationPage)
}

async confirmTransactionAndWaitForMining(extensionId: string, options?: { gasSetting?: GasSetting }) {
async confirmTransactionAndWaitForMining(extensionId: string, options?: { gasSetting?: GasSettings }) {
const notificationPage = await getNotificationPageAndWaitForLoad(this.page.context(), extensionId)

await transaction.confirmAndWaitForMining(this.page, notificationPage, options?.gasSetting ?? 'site')
}

async approveTokenPermission(
extensionId: string,
options?: { spendLimit?: 'max' | number; gasSetting?: GasSetting }
options?: { spendLimit?: 'max' | number; gasSetting?: GasSettings }
) {
const notificationPage = await getNotificationPageAndWaitForLoad(this.page.context(), extensionId)

Expand Down
26 changes: 26 additions & 0 deletions wallets/metamask/src/type/GasSettings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { z } from 'zod'

export const GasSettingValidation = z.union([
z.literal('low'),
z.literal('market'),
z.literal('aggressive'),
z.literal('site'),
z
.object({
maxBaseFee: z.number(),
priorityFee: z.number(),
// TODO: Add gasLimit range validation.
gasLimit: z.number().optional()
})
.superRefine(({ maxBaseFee, priorityFee }, ctx) => {
if (priorityFee > maxBaseFee) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'Max base fee cannot be lower than priority fee',
path: ['MetaMask', 'confirmTransaction', 'gasSetting', 'maxBaseFee']
})
}
})
])

export type GasSettings = z.input<typeof GasSettingValidation>
8 changes: 4 additions & 4 deletions wallets/metamask/src/type/MetaMaskAbstract.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { GasSetting } from '../playwright/pages/NotificationPage/actions'
import type { GasSettings } from '../playwright/pages/NotificationPage/actions'
import { SettingsSidebarMenus } from '../selectors/pages/HomePage/settings'
import type { Network } from './Network'

Expand Down Expand Up @@ -132,7 +132,7 @@ export abstract class MetaMaskAbstract {
* @param options - The transaction options.
* @param options.gasSetting - The gas setting to use for the transaction.
*/
abstract confirmTransaction(options?: { gasSetting?: GasSetting }): void
abstract confirmTransaction(options?: { gasSetting?: GasSettings }): void

/**
* Rejects a transaction request.
Expand All @@ -152,7 +152,7 @@ export abstract class MetaMaskAbstract {
*/
abstract approveTokenPermission(options?: {
spendLimit?: 'max' | number
gasSetting?: GasSetting
gasSetting?: GasSettings
}): void

/**
Expand Down Expand Up @@ -239,7 +239,7 @@ export abstract class MetaMaskAbstract {
* @group Experimental Methods
*/
abstract confirmTransactionAndWaitForMining(options?: {
gasSetting?: GasSetting
gasSetting?: GasSettings
}): void

/**
Expand Down
3 changes: 0 additions & 3 deletions wallets/metamask/test/cypress/addNewToken.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ before(() => {
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)
Expand Down
Loading

0 comments on commit dc65689

Please sign in to comment.