From 9fa3eccace86c93eba13734346ca093dccef92e1 Mon Sep 17 00:00:00 2001 From: rabi-siddique Date: Mon, 4 Mar 2024 08:13:20 +0500 Subject: [PATCH 1/6] chore: organize code in playwright.keplr.js and remove not used states --- commands/playwright-keplr.js | 315 +++++++++++++++-------------------- 1 file changed, 134 insertions(+), 181 deletions(-) diff --git a/commands/playwright-keplr.js b/commands/playwright-keplr.js index 4f1aeea12..5b34130db 100644 --- a/commands/playwright-keplr.js +++ b/commands/playwright-keplr.js @@ -7,8 +7,6 @@ let browser; let mainWindow; let keplrWindow; let keplrNotificationWindow; -let keplrRegistrationWindow; -let keplrPermissionWindow; let activeTabName; let extensionsData = {}; let retries = 0; @@ -21,12 +19,50 @@ module.exports = { keplrWindow = undefined; activeTabName = undefined; keplrNotificationWindow = undefined; - keplrRegistrationWindow = undefined; - keplrPermissionWindow = undefined; retries = 0; extensionsData = {}; }, - + mainWindow() { + return mainWindow; + }, + keplrWindow() { + return keplrWindow; + }, + keplrNotificationWindow() { + return keplrNotificationWindow; + }, + async assignActiveTabName(tabName) { + activeTabName = tabName; + return true; + }, + async isKeplrWindowActive() { + return activeTabName === 'keplr'; + }, + async isCypressWindowActive() { + return activeTabName === 'cypress'; + }, + async switchToKeplrWindow() { + await keplrWindow.bringToFront(); + await module.exports.assignActiveTabName('keplr'); + return true; + }, + async switchToCypressWindow() { + if (mainWindow) { + await mainWindow.bringToFront(); + await module.exports.assignActiveTabName('cypress'); + } + return true; + }, + async clear() { + browser = null; + return true; + }, + async clearWindows() { + mainWindow = null; + keplrWindow = null; + keplrNotificationWindow = null; + return true; + }, async init(playwrightInstance) { const chromium = playwrightInstance ? playwrightInstance @@ -49,7 +85,52 @@ module.exports = { } return browser.isConnected(); }, + async getExtensionsData() { + if (!_.isEmpty(extensionsData)) { + return extensionsData; + } + + const context = await browser.contexts()[0]; + const page = await context.newPage(); + + await page.goto('chrome://extensions'); + await page.waitForLoadState('load'); + await page.waitForLoadState('domcontentloaded'); + + const devModeButton = page.locator('#devMode'); + await devModeButton.waitFor(); + await devModeButton.focus(); + await devModeButton.click(); + + const extensionDataItems = await page.locator('extensions-item').all(); + for (const extensionData of extensionDataItems) { + const extensionName = ( + await extensionData + .locator('#name-and-version') + .locator('#name') + .textContent() + ).toLowerCase(); + + const extensionVersion = ( + await extensionData + .locator('#name-and-version') + .locator('#version') + .textContent() + ).replace(/(\n| )/g, ''); + + const extensionId = ( + await extensionData.locator('#extension-id').textContent() + ).replace('ID: ', ''); + + extensionsData[extensionName] = { + version: extensionVersion, + id: extensionId, + }; + } + await page.close(); + return extensionsData; + }, async assignWindows() { const keplrExtensionData = (await module.exports.getExtensionsData()).keplr; @@ -68,40 +149,64 @@ module.exports = { } return true; }, - async assignActiveTabName(tabName) { - activeTabName = tabName; - return true; - }, - - async isKeplrWindowActive() { - return activeTabName === 'keplr'; - }, + async waitUntilStable(page) { + const keplrExtensionData = (await module.exports.getExtensionsData()).keplr; + if ( + page && + page + .url() + .includes(`chrome-extension://${keplrExtensionData.id}/register.html`) + ) { + await page.waitForLoadState('load'); + await page.waitForLoadState('domcontentloaded'); + await page.waitForLoadState('networkidle'); + } + await keplrWindow.waitForLoadState('load'); + await keplrWindow.waitForLoadState('domcontentloaded'); + await keplrWindow.waitForLoadState('networkidle'); - keplrNotificationWindow() { - return keplrNotificationWindow; + if (mainWindow) { + await mainWindow.waitForLoadState('load'); + await mainWindow.waitForLoadState('domcontentloaded'); + // todo: this may slow down tests and not be necessary but could improve stability + // await mainWindow.waitForLoadState('networkidle'); + } }, - - keplrPermissionWindow() { - return keplrPermissionWindow; + async waitFor(selector, page = keplrWindow, number = 0) { + await module.exports.waitUntilStable(page); + await page.waitForSelector(selector, { strict: false }); + const element = page.locator(selector).nth(number); + await element.waitFor(); + await element.focus(); + if (process.env.STABLE_MODE) { + if (!isNaN(process.env.STABLE_MODE)) { + await page.waitForTimeout(Number(process.env.STABLE_MODE)); + } else { + await page.waitForTimeout(300); + } + } + return element; }, - - async switchToKeplrPermissionWindow() { - const keplrExtensionData = (await module.exports.getExtensionsData()).keplr; - const browserContext = await browser.contexts()[0]; - keplrPermissionWindow = await browserContext.newPage(); - await keplrPermissionWindow.goto( - `chrome-extension://${keplrExtensionData.id}/popup.html#/setting/security/permission`, - ); - return true; + async waitForByText(text, page = keplrWindow) { + await module.exports.waitUntilStable(page); + const element = page.getByText(text).first(); + await element.waitFor(); + await element.focus(); + if (process.env.STABLE_MODE) { + if (!isNaN(process.env.STABLE_MODE)) { + await page.waitForTimeout(Number(process.env.STABLE_MODE)); + } else { + await page.waitForTimeout(300); + } + } + return element; }, - async waitAndClickByText(text, page = keplrWindow, exact = false) { await module.exports.waitForByText(text, page); const element = `:is(:text-is("${text}")${exact ? '' : `, :text("${text}")`})`; await page.click(element); await module.exports.waitUntilStable(); }, - async waitAndSetValue(text, selector, page = keplrWindow) { const element = await module.exports.waitFor(selector, page); await element.fill(''); @@ -109,7 +214,6 @@ module.exports = { await element.fill(text); await module.exports.waitUntilStable(page); }, - async waitAndGetValue(selector, page = keplrWindow) { const expect = expectInstance ? expectInstance @@ -122,7 +226,6 @@ module.exports = { const value = await element.innerText(); return value; }, - async waitAndClick(selector, page = keplrWindow, args = {}) { const element = await module.exports.waitFor( selector, @@ -157,80 +260,6 @@ module.exports = { await module.exports.waitUntilStable(); return element; }, - - async switchToCypressWindow() { - if (mainWindow) { - await mainWindow.bringToFront(); - await module.exports.assignActiveTabName('cypress'); - } - return true; - }, - - async clear() { - browser = null; - return true; - }, - - async clearWindows() { - mainWindow = null; - keplrWindow = null; - return true; - }, - - async isCypressWindowActive() { - return activeTabName === 'cypress'; - }, - - async switchToKeplrWindow() { - await keplrWindow.bringToFront(); - await module.exports.assignActiveTabName('keplr'); - return true; - }, - - async waitUntilStable(page) { - const keplrExtensionData = (await module.exports.getExtensionsData()).keplr; - - if ( - page && - page - .url() - .includes(`chrome-extension://${keplrExtensionData.id}/register.html`) - ) { - await page.waitForLoadState('load'); - await page.waitForLoadState('domcontentloaded'); - await page.waitForLoadState('networkidle'); - } - await keplrWindow.waitForLoadState('load'); - await keplrWindow.waitForLoadState('domcontentloaded'); - await keplrWindow.waitForLoadState('networkidle'); - - if (mainWindow) { - await mainWindow.waitForLoadState('load'); - await mainWindow.waitForLoadState('domcontentloaded'); - // todo: this may slow down tests and not be necessary but could improve stability - // await mainWindow.waitForLoadState('networkidle'); - } - }, - - keplrWindow() { - return keplrWindow; - }, - - async waitFor(selector, page = keplrWindow, number = 0) { - await module.exports.waitUntilStable(page); - await page.waitForSelector(selector, { strict: false }); - const element = page.locator(selector).nth(number); - await element.waitFor(); - await element.focus(); - if (process.env.STABLE_MODE) { - if (!isNaN(process.env.STABLE_MODE)) { - await page.waitForTimeout(Number(process.env.STABLE_MODE)); - } else { - await page.waitForTimeout(300); - } - } - return element; - }, async doesElementExist(selector, timeout = 1000, page = keplrWindow) { try { await page.waitForSelector(selector, { timeout }); @@ -239,22 +268,6 @@ module.exports = { return false; } }, - async waitForByText(text, page = keplrWindow) { - await module.exports.waitUntilStable(page); - // await page.waitForSelector(selector, { strict: false }); - const element = page.getByText(text).first(); - await element.waitFor(); - await element.focus(); - if (process.env.STABLE_MODE) { - if (!isNaN(process.env.STABLE_MODE)) { - await page.waitForTimeout(Number(process.env.STABLE_MODE)); - } else { - await page.waitForTimeout(300); - } - } - return element; - }, - async waitAndClick(selector, page = keplrWindow, args = {}) { const element = await module.exports.waitFor( selector, @@ -289,7 +302,6 @@ module.exports = { await module.exports.waitUntilStable(); return element; }, - async waitForByRole(role, number = 0, page = keplrWindow) { await module.exports.waitUntilStable(page); const element = page.getByRole(role).nth(number); @@ -304,7 +316,6 @@ module.exports = { } return element; }, - async waitAndType(selector, value, page = keplrWindow) { if (typeof value === 'number') { value = value.toString(); @@ -313,7 +324,6 @@ module.exports = { await element.type(value); await module.exports.waitUntilStable(page); }, - async waitAndTypeByLocator(selector, value, number = 0, page = keplrWindow) { if (typeof value === 'number') { value = value.toString(); @@ -322,63 +332,6 @@ module.exports = { await element.type(value); await module.exports.waitUntilStable(page); }, - - async getExtensionsData() { - if (!_.isEmpty(extensionsData)) { - return extensionsData; - } - - const context = await browser.contexts()[0]; - const page = await context.newPage(); - - await page.goto('chrome://extensions'); - await page.waitForLoadState('load'); - await page.waitForLoadState('domcontentloaded'); - - const devModeButton = page.locator('#devMode'); - await devModeButton.waitFor(); - await devModeButton.focus(); - await devModeButton.click(); - - const extensionDataItems = await page.locator('extensions-item').all(); - for (const extensionData of extensionDataItems) { - const extensionName = ( - await extensionData - .locator('#name-and-version') - .locator('#name') - .textContent() - ).toLowerCase(); - - const extensionVersion = ( - await extensionData - .locator('#name-and-version') - .locator('#version') - .textContent() - ).replace(/(\n| )/g, ''); - - const extensionId = ( - await extensionData.locator('#extension-id').textContent() - ).replace('ID: ', ''); - - extensionsData[extensionName] = { - version: extensionVersion, - id: extensionId, - }; - } - await page.close(); - - return extensionsData; - }, - - async switchToKeplrRegistrationWindow() { - const keplrExtensionData = (await module.exports.getExtensionsData()).keplr; - const browserContext = await browser.contexts()[0]; - keplrRegistrationWindow = await browserContext.newPage(); - await keplrRegistrationWindow.goto( - `chrome-extension://${keplrExtensionData.id}/register.html`, - ); - return true; - }, async switchToKeplrNotification() { const keplrExtensionData = (await module.exports.getExtensionsData()).keplr; From c0f3d2bab4f783bdcbdf99928780f80299448831 Mon Sep 17 00:00:00 2001 From: rabi-siddique Date: Mon, 4 Mar 2024 12:00:04 +0500 Subject: [PATCH 2/6] chore: resolve merge conflicts with dev branch --- commands/keplr.js | 48 +++++++++++++++++++++++------ commands/playwright-keplr.js | 3 ++ support/commands.js | 8 ----- tests/e2e/specs/keplr/keplr-spec.js | 31 +++++++------------ 4 files changed, 53 insertions(+), 37 deletions(-) diff --git a/commands/keplr.js b/commands/keplr.js index 10c26612a..dc917f6a2 100644 --- a/commands/keplr.js +++ b/commands/keplr.js @@ -7,41 +7,76 @@ const { let extensionId; let extensionVersion; +let registrationUrl; +let permissionsUrl; const keplr = { async resetState() { log('Resetting state of keplr'); extensionId = undefined; extensionVersion = undefined; + registrationUrl = undefined; + permissionsUrl = undefined; }, extensionId: () => { return extensionId; }, extensionUrls: () => { return { - extensionImportAccountUrl, + registrationUrl, + permissionsUrl, }; }, - + async goTo(url) { + await Promise.all([ + playwright.keplrWindow().waitForNavigation(), + playwright.keplrWindow().goto(url), + ]); + await playwright.waitUntilStable(); + }, + async goToRegistration() { + await module.exports.goTo(registrationUrl); + }, + async goToPermissions() { + await module.exports.goTo(permissionsUrl); + }, + async switchToKeplrIfNotActive() { + if (await playwright.isCypressWindowActive()) { + await playwright.switchToKeplrWindow(); + switchBackToCypressWindow = true; + } + return switchBackToCypressWindow; + }, async getExtensionDetails() { const keplrExtensionData = (await playwright.getExtensionsData()).keplr; extensionId = keplrExtensionData.id; extensionVersion = keplrExtensionData.version; + registrationUrl = `chrome-extension://${extensionId}/register.html`; + permissionsUrl = `chrome-extension://${extensionId}/popup.html#/setting/security/permission`; return { extensionId, extensionVersion, + registrationUrl, + permissionsUrl, }; }, async disconnectWalletFromDapp() { + await module.exports.goToPermissions(); await playwright.waitAndClickByText( 'Disconnect All', - playwright.keplrPermissionWindow(), + playwright.keplrWindow(), ); return true; }, async importWallet(secretWordsOrPrivateKey, password, newAccount) { + const keplrWindow = playwright.keplrWindow(); + const currentUrl = await keplrWindow.url(); + if (!currentUrl.includes('registr')) { + await module.exports.goToRegistration(); + } + await playwright.waitAndClickByText( newAccount ? onboardingElements.createWalletButton @@ -112,12 +147,7 @@ const keplr = { await playwright.keplrWindow(), ); - await playwright.waitAndClick( - onboardingElements.finishButton, - await playwright.keplrWindow(), - { dontWait: true }, - ); - + await playwright.switchToCypressWindow(); return true; }, async importWalletWithPhrase(secretWords) { diff --git a/commands/playwright-keplr.js b/commands/playwright-keplr.js index 5b34130db..88228c815 100644 --- a/commands/playwright-keplr.js +++ b/commands/playwright-keplr.js @@ -22,6 +22,9 @@ module.exports = { retries = 0; extensionsData = {}; }, + browser() { + return browser; + }, mainWindow() { return mainWindow; }, diff --git a/support/commands.js b/support/commands.js index 8961b6d85..7cf288e4f 100644 --- a/support/commands.js +++ b/support/commands.js @@ -445,14 +445,6 @@ Cypress.Commands.add('switchToExtensionWindow', () => { return cy.task('switchToExtensionWindow'); }); -Cypress.Commands.add('switchToExtensionRegistrationWindow', () => { - return cy.task('switchToExtensionRegistrationWindow'); -}); - -Cypress.Commands.add('switchToExtensionPermissionWindow', () => { - return cy.task('switchToExtensionPermissionWindow'); -}); - Cypress.Commands.add('disconnectWalletFromDapp', () => { return cy.task('disconnectWalletFromDapp'); }); diff --git a/tests/e2e/specs/keplr/keplr-spec.js b/tests/e2e/specs/keplr/keplr-spec.js index 7afb6a698..2046f095a 100644 --- a/tests/e2e/specs/keplr/keplr-spec.js +++ b/tests/e2e/specs/keplr/keplr-spec.js @@ -7,7 +7,7 @@ describe('Keplr', () => { }); cy.visit('/'); }); - it(`should reject connect with wallet`, () => { + it(`should reject connection with wallet`, () => { const alertShown = cy.stub().as('alertShown'); cy.on('window:alert', alertShown); @@ -40,35 +40,19 @@ describe('Keplr', () => { 'Offer accepted', ); }); - it(`should complete Keplr connect with wallet, and confirm transaction after creating a new wallet using 24 word phrase`, () => { - cy.switchToExtensionRegistrationWindow().then(() => { + it(`should create a new wallet using 24 word phrase`, () => { + cy.switchToExtensionWindow().then(() => { cy.setupWallet( 'orbit bench unit task food shock brand bracket domain regular warfare company announce wheel grape trust sphere boy doctor half guard ritual three ecology', 'Test1234', true, ).then(setupFinished => { expect(setupFinished).to.be.true; - - cy.visit('/'); - cy.contains('Connect Wallet').click(); - cy.contains('Make an Offer').click(); - cy.confirmTransaction().then(taskCompleted => { - expect(taskCompleted).to.be.true; - }); - }); - }); - }); - - it(`should disconnect the wallet from all the connected DAPPs`, () => { - cy.switchToExtensionPermissionWindow().then(() => { - cy.disconnectWalletFromDapp().then(taskCompleted => { - expect(taskCompleted).to.be.true; }); }); }); - it(`should complete Keplr setup by importing the wallet using private key`, () => { - cy.switchToExtensionRegistrationWindow().then(() => { + cy.switchToExtensionWindow().then(() => { cy.setupWallet( 'A9C09B6E4AF70DE1F1B621CB1AA66CFD0B4AA977E4C18497C49132DD9E579485', ).then(setupFinished => { @@ -76,5 +60,12 @@ describe('Keplr', () => { }); }); }); + it(`should disconnect the wallet from all the connected DAPPs`, () => { + cy.switchToExtensionWindow().then(() => { + cy.disconnectWalletFromDapp().then(taskCompleted => { + expect(taskCompleted).to.be.true; + }); + }); + }); }); }); From 8f476ebfc053a0614ab81cf2701a358eadb477dc Mon Sep 17 00:00:00 2001 From: rabi-siddique Date: Mon, 4 Mar 2024 09:14:07 +0500 Subject: [PATCH 3/6] chore: using a consistent and more intention revealing name for a helper function --- commands/keplr.js | 2 +- commands/playwright-keplr.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/commands/keplr.js b/commands/keplr.js index dc917f6a2..ef90f0126 100644 --- a/commands/keplr.js +++ b/commands/keplr.js @@ -114,7 +114,7 @@ const keplr = { onboardingElements.walletName, ); - const passwordFieldExists = await playwright.doesElementExist( + const passwordFieldExists = await playwright.waitForAndCheckElementExistence( onboardingElements.passwordInput, ); diff --git a/commands/playwright-keplr.js b/commands/playwright-keplr.js index 88228c815..9ebafc484 100644 --- a/commands/playwright-keplr.js +++ b/commands/playwright-keplr.js @@ -263,7 +263,7 @@ module.exports = { await module.exports.waitUntilStable(); return element; }, - async doesElementExist(selector, timeout = 1000, page = keplrWindow) { + async waitForAndCheckElementExistence(selector, timeout = 1000, page = keplrWindow) { try { await page.waitForSelector(selector, { timeout }); return true; From 72bedd2fa572be7d9a1ddba9c0fc942679c5a8ef Mon Sep 17 00:00:00 2001 From: rabi-siddique Date: Mon, 4 Mar 2024 09:24:06 +0500 Subject: [PATCH 4/6] chore: adding a test case for validating the switchToExtensionWindow function --- tests/e2e/specs/keplr/playwright-spec.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/e2e/specs/keplr/playwright-spec.js b/tests/e2e/specs/keplr/playwright-spec.js index 46bad8fdf..6d0bc67b4 100644 --- a/tests/e2e/specs/keplr/playwright-spec.js +++ b/tests/e2e/specs/keplr/playwright-spec.js @@ -28,5 +28,14 @@ describe('Playwright', () => { expect(isActive).to.be.false; }); }); + it(`switchToExtensionWindow should properly switch active tab to keplr window`, () => { + cy.switchToExtensionWindow(); + cy.isExtensionWindowActive().then(isActive => { + expect(isActive).to.be.true; + }); + cy.isCypressWindowActive().then(isActive => { + expect(isActive).to.be.false; + }); + }); }); }); \ No newline at end of file From 7c42815b44ef20b969405bcd6433c001932c8ea4 Mon Sep 17 00:00:00 2001 From: rabi-siddique Date: Mon, 4 Mar 2024 11:11:49 +0500 Subject: [PATCH 5/6] chore: change selector for Approve button on connecting with wallet UI --- pages/keplr/notification-page.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/keplr/notification-page.js b/pages/keplr/notification-page.js index 639ba0ae2..e5e59a883 100644 --- a/pages/keplr/notification-page.js +++ b/pages/keplr/notification-page.js @@ -1,4 +1,4 @@ -const approveButton = `button[type="button"]`; +const approveButton = `button`; module.exports.notificationPageElements = { approveButton, From 9d8db98b57cd48db03e0e8ea0474fca4d7f17b6e Mon Sep 17 00:00:00 2001 From: rabi-siddique Date: Mon, 4 Mar 2024 17:17:18 +0500 Subject: [PATCH 6/6] chore: addressing PR comments --- commands/keplr.js | 8 ++------ commands/metamask.js | 1 + tests/e2e/specs/keplr/keplr-spec.js | 6 ++---- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/commands/keplr.js b/commands/keplr.js index ef90f0126..000d970c6 100644 --- a/commands/keplr.js +++ b/commands/keplr.js @@ -9,6 +9,7 @@ let extensionId; let extensionVersion; let registrationUrl; let permissionsUrl; +let switchBackToCypressWindow; const keplr = { async resetState() { @@ -71,12 +72,7 @@ const keplr = { return true; }, async importWallet(secretWordsOrPrivateKey, password, newAccount) { - const keplrWindow = playwright.keplrWindow(); - const currentUrl = await keplrWindow.url(); - if (!currentUrl.includes('registr')) { - await module.exports.goToRegistration(); - } - + await module.exports.goToRegistration(); await playwright.waitAndClickByText( newAccount ? onboardingElements.createWalletButton diff --git a/commands/metamask.js b/commands/metamask.js index c7b34357a..f1721f861 100644 --- a/commands/metamask.js +++ b/commands/metamask.js @@ -582,6 +582,7 @@ const metamask = { return true; }, async disconnectWalletFromDapp() { + await playwright.switchToKeplrWindow(); await switchToMetamaskIfNotActive(); await playwright.waitAndClick(mainPageElements.optionsMenu.button); await playwright.waitAndClick( diff --git a/tests/e2e/specs/keplr/keplr-spec.js b/tests/e2e/specs/keplr/keplr-spec.js index 2046f095a..9756036dd 100644 --- a/tests/e2e/specs/keplr/keplr-spec.js +++ b/tests/e2e/specs/keplr/keplr-spec.js @@ -61,10 +61,8 @@ describe('Keplr', () => { }); }); it(`should disconnect the wallet from all the connected DAPPs`, () => { - cy.switchToExtensionWindow().then(() => { - cy.disconnectWalletFromDapp().then(taskCompleted => { - expect(taskCompleted).to.be.true; - }); + cy.disconnectWalletFromDapp().then(taskCompleted => { + expect(taskCompleted).to.be.true; }); }); });