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

[💡 Feature]: Synpress with fully parallel run with metamask windows #832

Open
itev4n7 opened this issue Aug 15, 2023 · 4 comments
Open

Comments

@itev4n7
Copy link

itev4n7 commented Aug 15, 2023

Is your feature request related to a problem?

📦 The problem
Due to hardcoded line await browser.contexts()[0].pages(); in assignWindows function that placed in commands/playwright.js
you not able to run tests with metamask in parallel mode, because context always assigned to the first context during tests run, and all operations with metamask using this first instance.

Describe the solution you'd like.

💡 Idea already implemented and in personal use
@noahlitvin @maxhoheiser @r3kt-eth @drptbl @neuodev

📃 Solution (Game changer)
The main idea to set through initialSetup and init functions the context you want to run each matamask separately.

The code follow backward compatibility (e.g previous usage of updated methods is not ruin a code)
📝 Implementation:

📋 commands/metamask.js

...
  //"context" parameter added by Oleksii_Kvasov
  async initialSetup(
    playwrightInstance,
    context,
    {
      secretWordsOrPrivateKey,
      network,
      password,
      enableAdvancedSettings,
      enableExperimentalSettings,
    },
  ) {
    //"context" as a parameter added into "init" by Oleksii_Kvasov
    if (playwrightInstance) {
      await playwright.init(playwrightInstance, context);
    } else {
      await playwright.init(undefined, context);
    }
...

📋commands/playwright.js

...
  //"playwrightContext" (game changer for parralel run) added by Oleksii_Kvasov
  let playwrightContext;
  let retries = 0;
  module.exports = {
...
  //"context" parameter added by Oleksii_Kvasov
  async init(playwrightInstance, context) {
    ...
    //context initializing added by Oleksii_Kvasov
    if(context) {
      playwrightContext = context;
    } else {
      playwrightContext = browser.contexts()[0] //default first context
    }
    return browser.isConnected();
  },
...
  async assignWindows( ) {
    //context pages changed added by Oleksii_Kvasov
    let pages = playwrightContext.pages();
...
  async switchToMetamaskNotification() {
    //context pages changed added by Oleksii_Kvasov
    let pages = playwrightContext.pages();
...

In case if new functions will be added - and another functions that use context for navigation.

Also need to update cypress functions in synpress to use it with cypress commands

Example of use the implemented idea:

  • You need to run 5 different tests with different metamask wallets in parallel
  • After updating commands that described above
  • Add fullyParallel: true into playwright config file
  • Run your tests with parallel logic
  • You will have 5 different contexts(browser instances) and 5 different metamask wallets that will run parallel
  • Green checkmark for passed tests

Note: if you adding new network into metamask make sure that for each parallel wallet you have unique rpc url, either you will get 429 error in metamask.

Please make this post more popular, then I will create PR with this updates
Thanks in advance!

Just to simplify search in google:
Parallelisation for synpress using playwright
Parallel run of metamask in synpress

Describe alternatives you've considered.

No response

Additional context

No response

@itev4n7
Copy link
Author

itev4n7 commented Aug 15, 2023

Please guys make this post more popular, then I will create PR with this updates
Thanks in advance!

@itev4n7
Copy link
Author

itev4n7 commented Aug 15, 2023

I've created simple test example for public demonstration:

import { test } from '../src/common/fixtures'
import { initialSetup, acceptAccess } from '@synthetixio/synpress/commands/metamask'
import { Browser, BrowserContext } from '@playwright/test'
import * as playwright from '@synthetixio/synpress/commands/playwright'
import { generateMnemonic } from '@e2eUtils'

test.describe('Connect wallet opensea', function () {
  async function metamaskSetupWithContext(context: BrowserContext, browser: Browser, rpc: string) {
    await context.pages()[0].waitForTimeout(3000)
    const network = {
      networkName: process.env.NETWORK_NAME,
      rpcUrl: rpc,
      chainId: process.env.CHAIN_ID,
      symbol: process.env.SYMBOL,
      isTestnet: process.env.IS_TESTNET,
    }
    const playwrightInstance = browser.browserType()
    const mnemonic = generateMnemonic()
    await initialSetup(playwrightInstance, context, {
      secretWordsOrPrivateKey: mnemonic,
      network,
      password: process.env.METAMASK_PASSWORD,
      enableAdvancedSettings: true,
      enableExperimentalSettings: false,
    })
    await playwright.waitUntilStable()
  }

  test.beforeEach(async function({ context, browser }, testInfo) {
    if (testInfo.title.includes("1")) {
      const rpc = "<rpc_url1>"
      await metamaskSetupWithContext(context, browser, rpc)
    } else {
      const rpc = "<rpc_url2>"
      await metamaskSetupWithContext(context, browser, rpc)
    }
  })

  test('test 1', async function({ page, accountMenuPage, context, browser }) {
    await page.goto('https://testnets.opensea.io/')
    await page.locator('//*[@type="button" and contains(.,"Connect wallet")]').click()
    await page.locator('//li/button[contains(.,"MetaMask")]').click()
    //await page.locator('//button[contains(.,"Accept and sign")]').click()
    await acceptAccess(
      {
        signInSignature: true,
      },
    )
  })
  test('test 2', async function({ page, accountMenuPage, context, browser }) {
    await page.goto('https://testnets.opensea.io/')
    await page.locator('//*[@type="button" and contains(.,"Connect wallet")]').click()
    await page.locator('//li/button[contains(.,"MetaMask")]').click()
    //await page.locator('//button[contains(.,"Accept and sign")]').click()
    await acceptAccess(
      {
        signInSignature: true,
      },
    )
  })
})

each test will fail on "Access denied" error from opensea after acceptAccess, but in parallel mode :)

@drptbl
Copy link
Member

drptbl commented Aug 15, 2023

Great work @itev4n7! Would love to see this as a pull request. Cheers!

@itev4n7
Copy link
Author

itev4n7 commented Aug 16, 2023

@drptbl I will create it soon :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants