From bd127a35f43350aed932b46322d9f893db1e5f71 Mon Sep 17 00:00:00 2001 From: Rabi Siddique <60459172+rabi-siddique@users.noreply.github.com> Date: Thu, 7 Mar 2024 22:27:32 +0500 Subject: [PATCH] Adding Selecting Chain Interaction And Flow Improvements (#21) * chore: changing the flow of test cases; starting by creating a new wallet rather than importing * feature: adding behavior in import wallet flow to select a chain when importing/creating wallet * feature: adding helper methods to click elements in a reliable way * chore: using helper methods inside keplr.js * chore: handling edge case for grabbing token values when values are large numbers containing commas * chore: updating selector for getting wallet address and adding test cases to validate the behavior * chore: addressing PR comments * chore: addressing PR comments * chore: replacing Agoric local with Agoric localhost --- commands/keplr.js | 76 ++++++++++++++++++++++------- commands/playwright-keplr.js | 25 ++++++++++ pages/keplr/first-time-flow-page.js | 6 +++ pages/keplr/home-page.js | 2 + pages/keplr/notification-page.js | 6 +-- support/commands.js | 5 +- tests/e2e/specs/keplr/keplr-spec.js | 20 ++++++-- 7 files changed, 114 insertions(+), 26 deletions(-) diff --git a/commands/keplr.js b/commands/keplr.js index 7463c199e..0121b0c6f 100644 --- a/commands/keplr.js +++ b/commands/keplr.js @@ -158,10 +158,7 @@ const keplr = { await playwright.keplrWindow(), ); - await playwright.waitAndClick( - onboardingElements.submitChainButton, - await playwright.keplrWindow(), - ); + await module.exports.handleSelectChain(); await playwright.waitForByText( onboardingElements.phraseAccountCreated, @@ -170,6 +167,38 @@ const keplr = { return true; }, + async handleSelectChain() { + const chainNameExists = await playwright.waitForAndCheckElementExistence( + onboardingElements.chainNameSelector, + ); + + if (chainNameExists) { + await playwright.waitAndClickByText( + onboardingElements.chainName, + playwright.keplrWindow(), + ); + await playwright.waitAndClick( + onboardingElements.submitChainButton, + playwright.keplrWindow(), + ); + const importButtonExists = + await playwright.waitForAndCheckElementExistence( + onboardingElements.importButtonSelector, + ); + + if (importButtonExists) { + await playwright.waitAndClick( + onboardingElements.importButtonSelector, + playwright.keplrWindow(), + ); + } + } else { + await playwright.waitAndClick( + onboardingElements.submitChainButton, + playwright.keplrWindow(), + ); + } + }, async importWalletWithPhrase(secretWords) { await playwright.waitAndClickByText( onboardingElements.phraseCount24, @@ -238,12 +267,20 @@ const keplr = { return true; }, - async getWalletAddress() { - await playwright.switchToKeplrWindow(); + async getWalletAddress(chainName) { + playwright.switchToKeplrWindow(); await module.exports.goToHome(); - const page = playwright.keplrWindow(); + const newTokensSelctorExists = await playwright.waitForAndCheckElementExistence( + homePageElements.newTokensFoundSelector, + ); + + if (newTokensSelctorExists) { + await module.exports.addNewTokensFound(false); + } + await playwright.waitAndClickByText(notificationPageElements.copyAddress); - await page.click(notificationPageElements.copyWalletAddressSelector); + await playwright.waitAndClick(notificationPageElements.walletSelectors(chainName)) + walletAddress = clipboardy.readSync(); await playwright.switchToCypressWindow(); return walletAddress; @@ -287,14 +324,14 @@ const keplr = { return true; }, - - async addNewTokensFound() { - module.exports.switchToKeplrIfNotActive(); - await module.exports.goToHome(); + async addNewTokensFound(switchScreens = true) { + if (switchScreens) { + module.exports.switchToKeplrIfNotActive(); + await module.exports.goToHome(); + } await playwright.waitAndClickByText(homePageElements.newTokensFound); - await playwright.waitAndClick( + await playwright.waitAndClickWithRetry( homePageElements.selectAllTokensCheck, - playwright.keplrWindow(), { number: -1, force: true }, ); await playwright.waitAndClickByText( @@ -302,7 +339,10 @@ const keplr = { playwright.keplrWindow(), true, ); - await playwright.switchToCypressWindow(); + + if (switchScreens) { + await playwright.switchToCypressWindow(); + } return true; }, @@ -319,11 +359,11 @@ const keplr = { ); const innerTexts = await parentElement.allInnerTexts(); const textArray = innerTexts[0].split('\n'); - const tokenValue = Number(textArray[3]); + const tokenValue = textArray[3]; + const parsedTokenValue = Number(tokenValue.replace(/,/g, '')); await playwright.switchToCypressWindow(); - - return tokenValue; + return parsedTokenValue; }, }; diff --git a/commands/playwright-keplr.js b/commands/playwright-keplr.js index ba2ec17eb..0f1da1962 100644 --- a/commands/playwright-keplr.js +++ b/commands/playwright-keplr.js @@ -271,6 +271,7 @@ module.exports = { page = keplrWindow, ) { try { + await module.exports.waitUntilStable(page); await page.waitForSelector(selector, { timeout }); return true; } catch (error) { @@ -307,6 +308,30 @@ module.exports = { await element.type(value); await module.exports.waitUntilStable(page); }, + async waitAndClickWithRetry(selector, options) { + const maxRetries = 5; + let retries = 0; + + while (retries < maxRetries) { + try { + await module.exports.waitAndClick( + selector, + module.exports.keplrWindow(), + options, + ); + return; + } catch (error) { + retries++; + } + } + + throw new Error(`Failed to click element after ${maxRetries} attempts`); + }, + async waitAndClickWithDelay(selector, options, delay) { + const page = module.exports.keplrWindow() + await page.waitForTimeout(delay) + await module.exports.waitAndClick(selector, page, options); + }, async switchToKeplrNotification() { const keplrExtensionData = (await module.exports.getExtensionsData()).keplr; diff --git a/pages/keplr/first-time-flow-page.js b/pages/keplr/first-time-flow-page.js index 3d6e6337b..4b81860a0 100644 --- a/pages/keplr/first-time-flow-page.js +++ b/pages/keplr/first-time-flow-page.js @@ -14,12 +14,17 @@ const phraseAccountCreated = 'Account Created!'; const finishButton = 'button[type="button"]'; const textAreaSelector = 'textbox'; const submitPhraseButton = 'button[type="submit"]'; +const chainName = 'Agoric local' +const chainNameSelector = 'text=Agoric local' +const importButtonSelector = 'button:has-text("Import")' module.exports.onboardingElements = { existingWalletButton, createWalletButton, importRecoveryPhraseButton, useRecoveryPhraseButton, + chainNameSelector, + importButtonSelector, phraseCount24, phrasePrivateKey, walletInput, @@ -32,4 +37,5 @@ module.exports.onboardingElements = { finishButton, textAreaSelector, submitPhraseButton, + chainName }; diff --git a/pages/keplr/home-page.js b/pages/keplr/home-page.js index a0c339ca3..02baeed9c 100644 --- a/pages/keplr/home-page.js +++ b/pages/keplr/home-page.js @@ -3,6 +3,7 @@ const tokenParentSelector = '../../../..'; const selectAllTokensCheck = 'input[type="checkbox"]:enabled'; const newTokensFound = 'new token(s) found'; const addChainsButton = 'Add Chains'; +const newTokensFoundSelector = 'text=new token(s) found' module.exports.homePageElements = { tokenNameLabel, @@ -10,4 +11,5 @@ module.exports.homePageElements = { selectAllTokensCheck, newTokensFound, addChainsButton, + newTokensFoundSelector }; diff --git a/pages/keplr/notification-page.js b/pages/keplr/notification-page.js index e04726c24..bb5e8b1c5 100644 --- a/pages/keplr/notification-page.js +++ b/pages/keplr/notification-page.js @@ -1,9 +1,9 @@ const approveButton = `button`; const copyAddress = 'Copy Address'; -const copyWalletAddressSelector = 'div.sc-dkzDqf div.sc-hKMtZM.sc-kDDrLX.cyoEAq.dkJSBQ' +const walletSelectors = chainName => `img[alt="${chainName}"]`; module.exports.notificationPageElements = { approveButton, copyAddress, - copyWalletAddressSelector -}; \ No newline at end of file + walletSelectors +}; diff --git a/support/commands.js b/support/commands.js index a0ca6ecdc..d8399b5b4 100644 --- a/support/commands.js +++ b/support/commands.js @@ -455,11 +455,12 @@ Cypress.Commands.add('disconnectWalletFromDapp', () => { return cy.task('disconnectWalletFromDapp'); }); -Cypress.Commands.add('getWalletAddress', () => { - cy.task('getWalletAddress').then(address => { +Cypress.Commands.add('getWalletAddress', chainName => { + cy.task('getWalletAddress', chainName).then(address => { return address; }); }); + Cypress.Commands.add('switchWallet', walletName => { return cy.task('switchWallet', { walletName }); }); diff --git a/tests/e2e/specs/keplr/keplr-spec.js b/tests/e2e/specs/keplr/keplr-spec.js index a03522c30..8015d853e 100644 --- a/tests/e2e/specs/keplr/keplr-spec.js +++ b/tests/e2e/specs/keplr/keplr-spec.js @@ -75,6 +75,16 @@ describe('Keplr', () => { expect(setupFinished).to.be.true; }); }); + + it(`should get wallet address while running addNewTokensFound flow`, () => { + cy.getWalletAddress('Agoric localhost').then(walletAddress => { + expect(walletAddress.length).to.be.equal(45); + }); + + cy.getWalletAddress('Cosmos Hub').then(walletAddress => { + expect(walletAddress.length).to.be.equal(45); + }); + }); it(`should switch to new wallet by name`, () => { cy.switchWallet('My Wallet 2').then(taskCompleted => { expect(taskCompleted).to.be.true; @@ -99,10 +109,14 @@ describe('Keplr', () => { }); }); - it(`should get wallet address`, () => { - cy.getWalletAddress().then(walletAddress => { + it(`should get wallet address without running addNewTokensFound flow`, () => { + cy.getWalletAddress('Agoric localhost').then(walletAddress => { + expect(walletAddress.length).to.be.equal(45); + }); + + cy.getWalletAddress('Cosmos Hub').then(walletAddress => { expect(walletAddress.length).to.be.equal(45); }); }); }); -}); +}); \ No newline at end of file