diff --git a/wallets/metamask/cypress.config.ts b/wallets/metamask/cypress.config.ts index ba1e7f9f3..fb9e2c158 100644 --- a/wallets/metamask/cypress.config.ts +++ b/wallets/metamask/cypress.config.ts @@ -2,7 +2,8 @@ import { defineConfig } from 'cypress' import configureSynpress from './src/cypress/configureSynpress' export default defineConfig({ - chromeWebSecurity: false, + userAgent: 'synpress', + chromeWebSecurity: true, e2e: { baseUrl: 'http://localhost:9999', specPattern: 'test/cypress/**/*.cy.{js,jsx,ts,tsx}', diff --git a/wallets/metamask/src/cypress/configureSynpress.ts b/wallets/metamask/src/cypress/configureSynpress.ts index 654723260..59489a52d 100644 --- a/wallets/metamask/src/cypress/configureSynpress.ts +++ b/wallets/metamask/src/cypress/configureSynpress.ts @@ -1,8 +1,21 @@ +import type { BrowserContext, Page } from '@playwright/test' +import { expect } from '@playwright/test' import { ensureRdpPort } from '@synthetixio/synpress-core' +import getPlaywrightMetamask from './getPlaywrightMetamask' import importMetaMaskWallet from './support/importMetaMaskWallet' import { initMetaMask } from './support/initMetaMask' -let port: number +let metamaskInitialized = false + +let rdpPort: number + +let context: BrowserContext +let metamaskExtensionId: string + +let metamaskExtensionPage: Page + +// TODO: Implement if needed to change the focus between pages +// let cypressPage: Page export default function configureSynpress(on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions) { const browsers = config.browsers.filter((b) => b.name === 'chrome') @@ -10,18 +23,70 @@ export default function configureSynpress(on: Cypress.PluginEvents, config: Cypr throw new Error('No Chrome browser found in the configuration') } - on('before:browser:launch', async (_, launchOptions) => { + on('before:browser:launch', async (browser, launchOptions) => { // Enable debug mode to establish playwright connection const args = Array.isArray(launchOptions) ? launchOptions : launchOptions.args - port = ensureRdpPort(args) + rdpPort = ensureRdpPort(args) - args.push(...(await initMetaMask())) + if (browser.family === 'chromium') { + const { extensions, browserArgs } = await initMetaMask() + + launchOptions.extensions.push(...extensions) + args.push(...browserArgs) + } return launchOptions }) on('before:spec', async () => { - await importMetaMaskWallet(port) + if (!metamaskInitialized) { + const { + context: _context, + metamaskExtensionId: _metamaskExtensionId, + extensionPage: _extensionPage, + cypressPage: _cypressPage + } = await importMetaMaskWallet(rdpPort) + if (_extensionPage && _metamaskExtensionId) { + context = _context + metamaskExtensionId = _metamaskExtensionId + metamaskExtensionPage = _extensionPage + } + // TODO: Implement if needed to change the focus between pages + // if (_cypressPage) { + // cypressPage = _cypressPage + // } + metamaskInitialized = true + } + }) + + on('task', { + // Synpress API + async connectToDapp() { + const metamask = getPlaywrightMetamask(context, metamaskExtensionPage, metamaskExtensionId) + + return metamask + .connectToDapp() + .then(() => true) + .catch(() => false) + }, + + async addNewAccount(accountName: string) { + const metamask = getPlaywrightMetamask(context, metamaskExtensionPage, metamaskExtensionId) + + await metamask.addNewAccount(accountName) + + await expect(metamaskExtensionPage.locator(metamask.homePage.selectors.accountMenu.accountButton)).toHaveText( + accountName + ) + + return true + }, + + async getAccount() { + const metamask = getPlaywrightMetamask(context, metamaskExtensionPage, metamaskExtensionId) + + return await metamaskExtensionPage.locator(metamask.homePage.selectors.accountMenu.accountButton).innerText() + } }) return { diff --git a/wallets/metamask/src/cypress/getPlaywrightMetamask.ts b/wallets/metamask/src/cypress/getPlaywrightMetamask.ts new file mode 100644 index 000000000..b2cefcdc8 --- /dev/null +++ b/wallets/metamask/src/cypress/getPlaywrightMetamask.ts @@ -0,0 +1,15 @@ +import type { BrowserContext, Page } from '@playwright/test' +import { MetaMask } from '../playwright' + +let metamask: MetaMask | undefined + +export default function getPlaywrightMetamask( + context: BrowserContext, + metamaskExtensionPage: Page, + metamaskExtensionId: string +) { + if (!metamask) { + metamask = new MetaMask(context, metamaskExtensionPage, 'password', metamaskExtensionId) + } + return metamask +} diff --git a/wallets/metamask/src/cypress/support/e2e.ts b/wallets/metamask/src/cypress/support/e2e.ts index a1e60ea00..643103165 100644 --- a/wallets/metamask/src/cypress/support/e2e.ts +++ b/wallets/metamask/src/cypress/support/e2e.ts @@ -13,16 +13,15 @@ // https://on.cypress.io/configuration // *********************************************************** -// Import commands.js using ES2015 syntax: import synpressCommands from './synpressCommands' -before(() => { - cy.visit('/') -}) - Cypress.on('uncaught:exception', () => { // failing the test return false }) synpressCommands() + +before(() => { + cy.visit('/') +}) diff --git a/wallets/metamask/src/cypress/support/importMetaMaskWallet.ts b/wallets/metamask/src/cypress/support/importMetaMaskWallet.ts index 7a7dff271..b69ab35d3 100644 --- a/wallets/metamask/src/cypress/support/importMetaMaskWallet.ts +++ b/wallets/metamask/src/cypress/support/importMetaMaskWallet.ts @@ -1,6 +1,6 @@ import { type BrowserContext, type Page, chromium } from '@playwright/test' -import { importWallet } from '../../playwright/pages/OnboardingPage/actions' -import { onboardingPage } from '../../selectors' +import { getExtensionId } from '../../playwright' +import getPlaywrightMetamask from '../getPlaywrightMetamask' const SEED_PHRASE = 'test test test test test test test test test test test junk' @@ -17,12 +17,27 @@ export default async function importMetaMaskWallet(port: number) { await context.waitForEvent('response') - // First page (index equal 0) is the cypress page, second one (index equal 1) is the extension page - const extensionPage = context.pages()[1] as Page + let metamaskExtensionId: string | undefined + let extensionPage: Page | undefined + let cypressPage: Page | undefined - await extensionPage.waitForSelector(onboardingPage.GetStartedPageSelectors.termsOfServiceCheckbox) + const extensionPageIndex = context.pages().findIndex((page) => page.url().includes('chrome-extension://')) + if (extensionPageIndex !== -1) { + extensionPage = context.pages()[extensionPageIndex] as Page + metamaskExtensionId = await getExtensionId(context, 'MetaMask') - await importWallet(extensionPage, SEED_PHRASE, 'password') + const metamask = getPlaywrightMetamask(context, extensionPage, metamaskExtensionId) - await extensionPage.close() + await metamask.importWallet(SEED_PHRASE) + + cypressPage = context.pages()[extensionPageIndex === 1 ? 0 : 1] as Page + await cypressPage.bringToFront() + } + + return { + context, + extensionPage, + cypressPage, + metamaskExtensionId + } } diff --git a/wallets/metamask/src/cypress/support/initMetaMask.ts b/wallets/metamask/src/cypress/support/initMetaMask.ts index c64999192..5266fb93b 100644 --- a/wallets/metamask/src/cypress/support/initMetaMask.ts +++ b/wallets/metamask/src/cypress/support/initMetaMask.ts @@ -3,11 +3,12 @@ import { prepareExtension } from '../../prepareExtension' export async function initMetaMask() { const metamaskPath = await prepareExtension(false) - const browserArgs = [`--disable-extensions-except=${metamaskPath}`, `--load-extension=${metamaskPath}`] + const extensions = [metamaskPath] + const browserArgs = [] if (process.env.HEADLESS) { browserArgs.push('--headless=new') } - return browserArgs + return { extensions, browserArgs } } diff --git a/wallets/metamask/src/cypress/support/synpressCommands.ts b/wallets/metamask/src/cypress/support/synpressCommands.ts index 6e4ee34a6..3fc930e2d 100644 --- a/wallets/metamask/src/cypress/support/synpressCommands.ts +++ b/wallets/metamask/src/cypress/support/synpressCommands.ts @@ -9,12 +9,24 @@ // https://on.cypress.io/custom-commands // *********************************************** -// TODO: To be implemented -// declare global { -// namespace Cypress { -// interface Chainable { -// } -// } -// } +declare global { + namespace Cypress { + interface Chainable { + connectToDapp(): Chainable + addNewAccount(accountName: string): Chainable + getAccount(): Chainable + } + } +} -export default function synpressCommands() {} +export default function synpressCommands() { + Cypress.Commands.add('connectToDapp', () => { + return cy.task('connectToDapp') + }) + Cypress.Commands.add('addNewAccount', (accountName: string) => { + return cy.task('addNewAccount', accountName) + }) + Cypress.Commands.add('getAccount', () => { + return cy.task('getAccount') + }) +} diff --git a/wallets/metamask/test/cypress/addNewAccount.cy.ts b/wallets/metamask/test/cypress/addNewAccount.cy.ts new file mode 100644 index 000000000..f5bc382ca --- /dev/null +++ b/wallets/metamask/test/cypress/addNewAccount.cy.ts @@ -0,0 +1,7 @@ +it('should add a new account with a specified name', () => { + const accountName = 'Test Account 2' + + cy.addNewAccount(accountName).then(() => { + cy.getAccount().should('eq', accountName) + }) +}) diff --git a/wallets/metamask/test/cypress/connectToDapp.cy.ts b/wallets/metamask/test/cypress/connectToDapp.cy.ts new file mode 100644 index 000000000..a3f6f881a --- /dev/null +++ b/wallets/metamask/test/cypress/connectToDapp.cy.ts @@ -0,0 +1,6 @@ +it('should connect account to the app', () => { + cy.get('#connectButton').click() + cy.connectToDapp() + + cy.get('#accounts').should('contain', '0x') +})