Skip to content

Commit

Permalink
✨ feat: Implemented connectToDapp, addNewAccount in Cypress (#1181)
Browse files Browse the repository at this point in the history
* feat: MetaMask setup in Cypress part 1

* feat: wallet setup is working as expected

* fix: gitignore cleanup

* fix: clean imports

* fix: export from metamask package

* fix: dependencies issues

* fix: cleanup

* fix: test scripts

* fix: format

* fix: renamed configureBeforeSynpress.ts to configureSynpress.ts

* fix: improve metamask/cypress stability

* fix: format

* fix: cleanup

* feat: Implemented getPlaywrightMetamask and addNewAccount

* fix: cleanup
  • Loading branch information
matstyler authored Jul 25, 2024
1 parent 5544f21 commit c04c809
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 28 deletions.
3 changes: 2 additions & 1 deletion wallets/metamask/cypress.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}',
Expand Down
75 changes: 70 additions & 5 deletions wallets/metamask/src/cypress/configureSynpress.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,92 @@
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')
if (browsers.length === 0) {
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 {
Expand Down
15 changes: 15 additions & 0 deletions wallets/metamask/src/cypress/getPlaywrightMetamask.ts
Original file line number Diff line number Diff line change
@@ -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
}
9 changes: 4 additions & 5 deletions wallets/metamask/src/cypress/support/e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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('/')
})
29 changes: 22 additions & 7 deletions wallets/metamask/src/cypress/support/importMetaMaskWallet.ts
Original file line number Diff line number Diff line change
@@ -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'

Expand All @@ -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
}
}
5 changes: 3 additions & 2 deletions wallets/metamask/src/cypress/support/initMetaMask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
}
28 changes: 20 additions & 8 deletions wallets/metamask/src/cypress/support/synpressCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<void>
addNewAccount(accountName: string): Chainable<void>
getAccount(): Chainable<string>
}
}
}

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')
})
}
7 changes: 7 additions & 0 deletions wallets/metamask/test/cypress/addNewAccount.cy.ts
Original file line number Diff line number Diff line change
@@ -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)
})
})
6 changes: 6 additions & 0 deletions wallets/metamask/test/cypress/connectToDapp.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
it('should connect account to the app', () => {
cy.get('#connectButton').click()
cy.connectToDapp()

cy.get('#accounts').should('contain', '0x')
})

0 comments on commit c04c809

Please sign in to comment.