From d8c4fe12e3ed3ed41a82511e9b3edef6d9296dc9 Mon Sep 17 00:00:00 2001 From: Michael <30682308+mike10ca@users.noreply.github.com> Date: Wed, 14 Feb 2024 19:02:31 +0100 Subject: [PATCH] Tests: add dashboard tests (#3256) * tests: add dashboard tests * tests: fix spelling error --- cypress/e2e/pages/create_tx.pages.js | 2 +- cypress/e2e/pages/dashboard.pages.js | 92 +++++++++++++++++++ cypress/e2e/pages/safeapps.pages.js | 5 + cypress/e2e/pages/sidebar.pages.js | 2 +- cypress/e2e/smoke/dashboard.cy.js | 55 ++++++++++- cypress/support/constants.js | 1 + .../PendingTxs/PendingTxListItem.tsx | 2 +- .../dashboard/PendingTxs/PendingTxsList.tsx | 6 +- .../SafeAppsDashboardSection.tsx | 2 +- src/components/dashboard/styled.tsx | 2 +- .../safe-apps/SafeAppActionButtons/index.tsx | 2 +- .../safe-apps/SafeAppList/index.tsx | 2 +- src/pages/transactions/tx.tsx | 2 +- 13 files changed, 162 insertions(+), 13 deletions(-) diff --git a/cypress/e2e/pages/create_tx.pages.js b/cypress/e2e/pages/create_tx.pages.js index 84888d03ce..331be07a17 100644 --- a/cypress/e2e/pages/create_tx.pages.js +++ b/cypress/e2e/pages/create_tx.pages.js @@ -12,7 +12,7 @@ const nonceInput = 'input[name="nonce"]' const nonceTxValue = '[data-testid="nonce"]' const gasLimitInput = '[name="gasLimit"]' const rotateLeftIcon = '[data-testid="RotateLeftIcon"]' -const transactionItem = '[data-testid="transaction-item"]' +export const transactionItem = '[data-testid="transaction-item"]' const connectedWalletExecMethod = '[data-testid="connected-wallet-execution-method"]' const addToBatchBtn = '[data-track="batching: Add to batch"]' const accordionDetails = '[data-testid="accordion-details"]' diff --git a/cypress/e2e/pages/dashboard.pages.js b/cypress/e2e/pages/dashboard.pages.js index a36d6d16c3..188f2c0ccb 100644 --- a/cypress/e2e/pages/dashboard.pages.js +++ b/cypress/e2e/pages/dashboard.pages.js @@ -1,4 +1,7 @@ import * as constants from '../../support/constants' +import * as safeapps from '../pages/safeapps.pages' +import * as main from '../pages/main.page' +import * as createtx from '../../e2e/pages/create_tx.pages' const connectAndTransactStr = 'Connect & transact' const transactionQueueStr = 'Pending transactions' @@ -10,9 +13,98 @@ const viewAllStr = 'View all' const transactionBuilderStr = 'Use Transaction Builder' const safeAppStr = 'Safe Apps' const exploreSafeApps = 'Explore Safe Apps' +export const copiedAppUrl = 'share/safe-app?appUrl' const txBuilder = 'a[href*="tx-builder"]' const safeSpecificLink = 'a[href*="&appUrl=http"]' +const copyShareBtn = '[data-testid="copy-btn-icon"]' +const exploreAppsBtn = '[data-testid="explore-apps-btn"]' +const viewAllLink = '[data-testid="view-all-link"]' +const noTxIcon = '[data-testid="no-tx-icon"]' +const noTxText = '[data-testid="no-tx-text"]' +const pendingTxWidget = '[data-testid="pending-tx-widget"]' +const pendingTxItem = '[data-testid="tx-pending-item"]' +const singleTxDetailsHeader = '[data-testid="tx-details"]' + +export function clickOnTxByIndex(index) { + cy.get(pendingTxItem).eq(index).click() + cy.get(singleTxDetailsHeader).should('be.visible') +} + +export function verifySingleTxItem(data) { + main.checkTextsExistWithinElement(createtx.transactionItem, data) +} + +export function verifyDataInPendingTx(data) { + main.checkTextsExistWithinElement(pendingTxWidget, data) +} + +export function verifyTxItemInPendingTx(data) { + let matchFound = false + + cy.get(pendingTxItem) + .each(($item) => { + const itemText = $item.text() + const isMatch = data.every((tx) => itemText.includes(tx)) + + if (isMatch) { + matchFound = true + return false + } + }) + .then(() => { + expect(matchFound).to.be.true + }) +} + +export function verifyEmptyTxSection() { + main.verifyElementsIsVisible([noTxIcon, noTxText]) +} + +export function clickOnViewAllBtn() { + cy.get(viewAllLink).click() +} + +export function pinAppByIndex(index) { + return cy + .get('[aria-label*="Pin"]') + .eq(index) + .click() + .then(() => { + cy.wait(1000) + return cy.get('[aria-label*="Unpin"]').eq(0).invoke('attr', 'aria-label') + }) +} + +export function clickOnPinBtnByName(name) { + cy.get(`[aria-label="${name}"]`).click() +} + +export function verifyPinnedAppsCount(count) { + cy.get(`[aria-label*="Unpin"]`).should('have.length', count) +} + +export function clickOnExploreAppsBtn() { + cy.get(exploreAppsBtn).click() + cy.get(safeapps.safeAppsList) + .should('exist') + .within(() => { + cy.get('li').should('have.length.at.least', 1) + }) +} + +export function verifyShareBtnWorks(index, data) { + cy.get(copyShareBtn) + .eq(index) + .click() + .then(() => + cy.window().then((win) => { + win.navigator.clipboard.readText().then((text) => { + expect(text).to.contain(data) + }) + }), + ) +} export function verifyConnectTransactStrIsVisible() { cy.contains(connectAndTransactStr).should('be.visible') diff --git a/cypress/e2e/pages/safeapps.pages.js b/cypress/e2e/pages/safeapps.pages.js index 1466092230..eb0f647813 100644 --- a/cypress/e2e/pages/safeapps.pages.js +++ b/cypress/e2e/pages/safeapps.pages.js @@ -8,6 +8,7 @@ export const saveToLibraryBtn = 'button[title="Save to Library"]' export const downloadBatchBtn = 'button[title="Download batch"]' export const deleteBatchBtn = 'button[title="Delete Batch"]' const appModal = '[data-testid="app-info-modal"]' +export const safeAppsList = '[data-testid="apps-list"]' const addBtnStr = /add/i const noAppsStr = /no Safe Apps found/i @@ -279,3 +280,7 @@ export function uncheckAllPermissions(element) { export function checkAllPermissions(element) { cy.wrap(element).findByText(allowAllPermissions).click() } + +export function verifyPinnedApp(name) { + cy.get(`[aria-label="${name}"]`) +} diff --git a/cypress/e2e/pages/sidebar.pages.js b/cypress/e2e/pages/sidebar.pages.js index 003e324c39..4c540b9ffa 100644 --- a/cypress/e2e/pages/sidebar.pages.js +++ b/cypress/e2e/pages/sidebar.pages.js @@ -11,7 +11,7 @@ const openSafesIcon = '[data-testid="open-safes-icon"]' const qrModalBtn = '[data-testid="qr-modal-btn"]' const copyAddressBtn = '[data-testid="copy-address-btn"]' const explorerBtn = '[data-testid="explorer-btn"]' -const sideBarListItem = '[data-testid="sidebar-list-item"]' +export const sideBarListItem = '[data-testid="sidebar-list-item"]' const sideBarListItemWhatsNew = '[data-testid="list-item-whats-new"]' const sideBarListItemNeedHelp = '[data-testid="list-item-need-help"]' const sideSafeListItem = '[data-testid="safe-list-item"]' diff --git a/cypress/e2e/smoke/dashboard.cy.js b/cypress/e2e/smoke/dashboard.cy.js index 03b239c733..17d2224d88 100644 --- a/cypress/e2e/smoke/dashboard.cy.js +++ b/cypress/e2e/smoke/dashboard.cy.js @@ -1,13 +1,19 @@ import * as constants from '../../support/constants' import * as dashboard from '../pages/dashboard.pages' import * as main from '../pages/main.page' +import * as safeapps from '../pages/safeapps.pages' +import * as createTx from '../pages/create_tx.pages' + +const txData = ['14', 'Send', '-0.00002 ETH', '1 out of 1'] +const txaddOwner = ['5', 'addOwnerWithThreshold', '1 out of 2'] +const txMultiSendCall3 = ['4', 'Safe: MultiSendCallOnly 1.3.0', '3 actions', '1 out of 2'] +const txMultiSendCall2 = ['6', 'Safe: MultiSendCallOnly 1.3.0', '2 actions', '1 out of 2'] describe('[SMOKE] Dashboard tests', () => { beforeEach(() => { cy.clearLocalStorage() - cy.visit(constants.BALANCE_URL + constants.SEPOLIA_TEST_SAFE_5) + cy.visit(constants.homeUrl + constants.SEPOLIA_TEST_SAFE_5) main.acceptCookies() - main.clickOnSideMenuItem(constants.mainSideMenuOptions.home) dashboard.verifyConnectTransactStrIsVisible() }) @@ -26,4 +32,49 @@ describe('[SMOKE] Dashboard tests', () => { it('[SMOKE] Verify the Safe Apps Section is displayed', () => { dashboard.verifySafeAppsSection() }) + + it('[SMOKE] Verify clicking on the share icon copies the app URL to the clipboard', () => { + dashboard.verifyShareBtnWorks(0, dashboard.copiedAppUrl) + }) + + it('[SMOKE] Verify clicking on Explore Safe apps button opens list of all apps', () => { + dashboard.clickOnExploreAppsBtn() + }) + + it('[SMOKE] Verify that pinned in dashboard, an app keeps its status on apps page', () => { + dashboard.pinAppByIndex(0).then((pinnedApp) => { + cy.visit(constants.appsUrlGeneral + constants.SEPOLIA_TEST_SAFE_5) + safeapps.verifyPinnedApp(pinnedApp) + cy.visit(constants.homeUrl + constants.SEPOLIA_TEST_SAFE_5) + dashboard.clickOnPinBtnByName(pinnedApp) + dashboard.verifyPinnedAppsCount(0) + }) + }) + + it('[SMOKE] Verify clicking on View All button directs to list of all queued txs', () => { + dashboard.clickOnViewAllBtn() + createTx.verifyNumberOfTransactions(2) + }) + + it('[SMOKE] Verify there is empty tx string and image when there are no tx queued', () => { + cy.visit(constants.homeUrl + constants.SEPOLIA_TEST_SAFE_14) + dashboard.verifyEmptyTxSection() + }) + + it('[SMOKE] Verify that the last created tx in conflicting tx is showed in the widget', () => { + dashboard.verifyDataInPendingTx(txData) + }) + + it('[SMOKE] Verify that tx are displayed correctly in Pending tx section', () => { + cy.visit(constants.homeUrl + constants.SEPOLIA_TEST_SAFE_18_PENDING_TX) + cy.wait(1000) + dashboard.verifyTxItemInPendingTx(txMultiSendCall3) + dashboard.verifyTxItemInPendingTx(txaddOwner) + dashboard.verifyTxItemInPendingTx(txMultiSendCall2) + }) + + it('[SMOKE] Verify clicking on any tx takes the user to Transactions > Queue tab', () => { + dashboard.clickOnTxByIndex(0) + dashboard.verifySingleTxItem(txData) + }) }) diff --git a/cypress/support/constants.js b/cypress/support/constants.js index ffd84749aa..a8e420b324 100644 --- a/cypress/support/constants.js +++ b/cypress/support/constants.js @@ -30,6 +30,7 @@ export const SEPOLIA_TEST_SAFE_14 = 'sep:0xC23e061252BFc7967203D054136d8fA7c7df2 export const SEPOLIA_TEST_SAFE_15_TOKEN = 'sep:0xfC0A7ac73Fde7547ac0792Cca1D8A50CE0AFC4Df' export const SEPOLIA_TEST_SAFE_16_CREATE_TX = 'sep:0xc2F3645bfd395516d1a18CA6ad9298299d328C01' export const SEPOLIA_TEST_SAFE_17_SIDEBAR_NONOWNER = 'sep:0x10B45a24640E2170B6AA63ea3A289D723a0C9cba' +export const SEPOLIA_TEST_SAFE_18_PENDING_TX = 'sep:0xFFfaC243A24EecE6553f0Da278322aCF1Fb6CeF1' export const SEPOLIA_CONTRACT_SHORT = '0x11AB...34aF' export const SEPOLIA_RECIPIENT_ADDR_SHORT = '0x4DD4...7bde' export const GNO_TEST_SAFE = 'gno:0xB8d760a90a5ed54D3c2b3EFC231277e99188642A' diff --git a/src/components/dashboard/PendingTxs/PendingTxListItem.tsx b/src/components/dashboard/PendingTxs/PendingTxListItem.tsx index a0aba462bd..f58b651db5 100644 --- a/src/components/dashboard/PendingTxs/PendingTxListItem.tsx +++ b/src/components/dashboard/PendingTxs/PendingTxListItem.tsx @@ -34,7 +34,7 @@ const PendingTx = ({ transaction }: PendingTxType): ReactElement => { ) return ( - + {isMultisigExecutionInfo(transaction.executionInfo) && transaction.executionInfo.nonce} diff --git a/src/components/dashboard/PendingTxs/PendingTxsList.tsx b/src/components/dashboard/PendingTxs/PendingTxsList.tsx index 7c8c6c0524..ce6e96bc1a 100644 --- a/src/components/dashboard/PendingTxs/PendingTxsList.tsx +++ b/src/components/dashboard/PendingTxs/PendingTxsList.tsx @@ -25,9 +25,9 @@ const EmptyState = () => { return ( - + - + This Safe Account has no queued transactions @@ -103,7 +103,7 @@ const PendingTxsList = (): ReactElement | null => { ) return ( - +
Pending transactions diff --git a/src/components/dashboard/SafeAppsDashboardSection/SafeAppsDashboardSection.tsx b/src/components/dashboard/SafeAppsDashboardSection/SafeAppsDashboardSection.tsx index eb45258ca2..8d297c895a 100644 --- a/src/components/dashboard/SafeAppsDashboardSection/SafeAppsDashboardSection.tsx +++ b/src/components/dashboard/SafeAppsDashboardSection/SafeAppsDashboardSection.tsx @@ -62,7 +62,7 @@ const ExploreSafeAppsCard = () => { - diff --git a/src/components/dashboard/styled.tsx b/src/components/dashboard/styled.tsx index f08a0f34b1..14de0b75d9 100644 --- a/src/components/dashboard/styled.tsx +++ b/src/components/dashboard/styled.tsx @@ -49,7 +49,7 @@ const StyledLink = styled(Link)` export const ViewAllLink = ({ url, text }: { url: LinkProps['href']; text?: string }): ReactElement => ( - + {text || 'View all'} diff --git a/src/components/safe-apps/SafeAppActionButtons/index.tsx b/src/components/safe-apps/SafeAppActionButtons/index.tsx index cf924d22c9..40fd557ec5 100644 --- a/src/components/safe-apps/SafeAppActionButtons/index.tsx +++ b/src/components/safe-apps/SafeAppActionButtons/index.tsx @@ -58,7 +58,7 @@ const SafeAppActionButtons = ({ onCopy={handleCopyShareSafeAppUrl} text={shareSafeAppUrl} > - + diff --git a/src/components/safe-apps/SafeAppList/index.tsx b/src/components/safe-apps/SafeAppList/index.tsx index 1dceec9535..c9a7daf84e 100644 --- a/src/components/safe-apps/SafeAppList/index.tsx +++ b/src/components/safe-apps/SafeAppList/index.tsx @@ -54,7 +54,7 @@ const SafeAppList = ({ {/* Safe Apps List */} -
    +
      {/* Add Custom Safe App Card */} {addCustomApp && (
    • diff --git a/src/pages/transactions/tx.tsx b/src/pages/transactions/tx.tsx index cc89616eea..e60e093ebe 100644 --- a/src/pages/transactions/tx.tsx +++ b/src/pages/transactions/tx.tsx @@ -12,7 +12,7 @@ const SingleTransaction: NextPage = () => {
      - + Transaction details