synpress
synpress copied to clipboard
[π‘ Feature]: Synpress with fully parallel run with metamask windows
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: trueinto 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
Please guys make this post more popular, then I will create PR with this updates Thanks in advance!
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 :)
Great work @itev4n7! Would love to see this as a pull request. Cheers!
@drptbl I will create it soon :)