From af8e4fb9f2140596411572fabb63df74d307f430 Mon Sep 17 00:00:00 2001 From: Michael <30682308+mike10ca@users.noreply.github.com> Date: Wed, 6 Mar 2024 16:33:16 +0100 Subject: [PATCH] Tests: add happy path flows for recovery v1 (#3394) * tests: add happy path flows for recovery v1 * tests: remove unused import * tests: fix failing tests * tests: update test folders * tests: update tests and balance fixture file --- .github/workflows/e2e-hp-ondemand.yml | 58 ++++++++++ .github/workflows/e2e-ondemand.yml | 5 +- cypress/e2e/happypath/recovery_hp_1.cy.js | 30 ++++++ cypress/e2e/happypath/recovery_hp_2.cy.js | 41 +++++++ cypress/e2e/happypath/recovery_hp_3.cy.js | 47 ++++++++ cypress/e2e/pages/address_book.page.js | 2 +- cypress/e2e/pages/create_tx.pages.js | 4 +- cypress/e2e/pages/create_wallet.pages.js | 3 +- cypress/e2e/pages/load_safe.pages.js | 2 +- cypress/e2e/pages/main.page.js | 4 + cypress/e2e/pages/recovery.pages.js | 100 ++++++++++++++++++ cypress/e2e/pages/safeapps.pages.js | 5 +- cypress/e2e/pages/transactions.page.js | 36 +++++++ .../e2e/safe-apps/drain_account.spec.cy.js | 6 +- cypress/fixtures/balances.json | 6 +- cypress/fixtures/txhistory_data_data.json | 34 +++--- cypress/support/constants.js | 7 +- .../CancelRecovery/CancelRecoveryOverview.tsx | 2 +- .../RecoverAccountFlowReview.tsx | 7 +- .../RecoverAccountFlowSetup.tsx | 2 +- .../RemoveRecoveryFlowOverview.tsx | 4 +- .../flows/SuccessScreen/StatusMessage.tsx | 2 +- .../UpsertRecoveryFlowIntro.tsx | 2 +- .../UpsertRecoveryFlowSettings.tsx | 11 +- .../tx/SignOrExecuteForm/ExecuteForm.tsx | 8 +- .../components/CancelRecoveryButton/index.tsx | 8 +- .../ExecuteRecoveryButton/index.tsx | 1 + .../RecoveryCards/RecoveryInProgressCard.tsx | 2 +- .../RecoveryCards/RecoveryProposalCard.tsx | 3 +- .../ChooseRecoveryMethodModal.tsx | 1 + .../RecoverySettings/DelayModifierRow.tsx | 2 +- .../components/RecoverySettings/index.tsx | 8 +- 32 files changed, 404 insertions(+), 49 deletions(-) create mode 100644 .github/workflows/e2e-hp-ondemand.yml create mode 100644 cypress/e2e/happypath/recovery_hp_1.cy.js create mode 100644 cypress/e2e/happypath/recovery_hp_2.cy.js create mode 100644 cypress/e2e/happypath/recovery_hp_3.cy.js create mode 100644 cypress/e2e/pages/recovery.pages.js create mode 100644 cypress/e2e/pages/transactions.page.js diff --git a/.github/workflows/e2e-hp-ondemand.yml b/.github/workflows/e2e-hp-ondemand.yml new file mode 100644 index 0000000000..42ce285ef1 --- /dev/null +++ b/.github/workflows/e2e-hp-ondemand.yml @@ -0,0 +1,58 @@ +name: Happy path on demand tests + +on: + workflow_dispatch: + schedule: + - cron: '0 4 * * 1,4' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + e2e: + runs-on: ubuntu-20.04 + name: Cypress Happy path on demand tests + strategy: + fail-fast: false + matrix: + containers: [1, 2, 3, 4, 5] + steps: + - uses: actions/checkout@v3 + + - uses: ./.github/workflows/cypress + with: + secrets: ${{ toJSON(secrets) }} + spec: | + cypress/e2e/happypath/*.cy.js + group: 'Happy path on demand tests' + + - name: Python setup + if: always() + uses: actions/setup-python@v3 + with: + python-version: '3.x' + + - name: Install junitparser + if: always() + run: | + pip install junitparser + + - name: Merge JUnit reports for TestRail + if: always() + run: | + junitparser merge --suite-name "Root Suite" --glob "reports/junit-*" "reports/junit-report.xml" + + - name: TestRail CLI upload results + if: always() + run: | + pip install trcli + trcli -y \ + -h https://gno.testrail.io/ \ + --project "Safe- Web App" \ + --username ${{ secrets.TESTRAIL_USERNAME }} \ + --password ${{ secrets.TESTRAIL_PASSWORD }} \ + parse_junit \ + --title "Happy path Tests, branch: ${GITHUB_REF_NAME}" \ + --run-description ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} \ + -f "reports/junit-report.xml" diff --git a/.github/workflows/e2e-ondemand.yml b/.github/workflows/e2e-ondemand.yml index 7982d3d9c7..7edbedb46e 100644 --- a/.github/workflows/e2e-ondemand.yml +++ b/.github/workflows/e2e-ondemand.yml @@ -23,7 +23,10 @@ jobs: - uses: ./.github/workflows/cypress with: secrets: ${{ toJSON(secrets) }} - spec: cypress/e2e/**/*.cy.js + spec: | + cypress/e2e/regression/*.cy.js + cypress/e2e/safe-apps/*.cy.js + cypress/e2e/smoke/*.cy.js group: 'Regression on demand tests' - name: Python setup diff --git a/cypress/e2e/happypath/recovery_hp_1.cy.js b/cypress/e2e/happypath/recovery_hp_1.cy.js new file mode 100644 index 0000000000..5965e255a3 --- /dev/null +++ b/cypress/e2e/happypath/recovery_hp_1.cy.js @@ -0,0 +1,30 @@ +import * as constants from '../../support/constants' +import * as main from '../pages/main.page' +import * as owner from '../pages/owners.pages' +import * as recovery from '../pages/recovery.pages' +import * as tx from '../pages/transactions.page' + +describe('Recovery happy path tests 1', () => { + beforeEach(() => { + cy.visit(constants.securityUrl + constants.SEPOLIA_TEST_SAFE_23_RECOVERY_1) + cy.clearLocalStorage() + main.acceptCookies() + }) + + // Check that recovery can be setup and removed + it('Recovery setup happy path 1', () => { + owner.waitForConnectionStatus() + recovery.clickOnSetupRecoveryBtn() + recovery.clickOnSetupRecoveryModalBtn() + recovery.clickOnNextBtn() + recovery.enterRecovererAddress(constants.SEPOLIA_OWNER_2) + recovery.agreeToTerms() + recovery.clickOnNextBtn() + tx.executeFlow_1() + recovery.verifyRecovererAdded([constants.SEPOLIA_OWNER_2_SHORT]) + recovery.removeRecoverer(0, constants.SEPOLIA_OWNER_2) + recovery.clickOnNextBtn() + tx.executeFlow_1() + recovery.getSetupRecoveryBtn() + }) +}) diff --git a/cypress/e2e/happypath/recovery_hp_2.cy.js b/cypress/e2e/happypath/recovery_hp_2.cy.js new file mode 100644 index 0000000000..ae24f22bd0 --- /dev/null +++ b/cypress/e2e/happypath/recovery_hp_2.cy.js @@ -0,0 +1,41 @@ +import * as constants from '../../support/constants' +import * as main from '../pages/main.page' +import * as owner from '../pages/owners.pages' +import * as recovery from '../pages/recovery.pages' +import * as addressbook from '../pages/address_book.page' + +describe('Recovery happy path tests 2', () => { + beforeEach(() => { + cy.visit(constants.setupUrl + constants.SEPOLIA_TEST_SAFE_24_RECOVERY_2) + cy.clearLocalStorage() + main.acceptCookies() + }) + + // Check that recoverer can start and complete the process if not cancelled by the owner + it('Recovery setup happy path 2', { defaultCommandTimeout: 300000 }, () => { + owner.waitForConnectionStatus() + recovery.postponeRecovery() + + main.getElementText(addressbook.tableContainer).then((text) => { + let owner = constants.SPENDING_LIMIT_ADDRESS_2 + if (text.includes(constants.SPENDING_LIMIT_ADDRESS_2)) { + owner = constants.SEPOLIA_OWNER_2 + } + + cy.visit(constants.homeUrl + constants.SEPOLIA_TEST_SAFE_24_RECOVERY_2) + recovery.clickOnStartRecoveryBtn() + recovery.enterOwnerAddress(owner) + recovery.clickOnNextBtn() + recovery.clickOnRecoveryExecuteBtn() + recovery.clickOnGoToQueueBtn() + recovery.clickOnRecoveryExecuteBtn() + recovery.verifyTxNotInQueue() + cy.visit(constants.setupUrl + constants.SEPOLIA_TEST_SAFE_24_RECOVERY_2) + main.verifyElementsCount(addressbook.tableContainer, 1) + cy.wait(10000) + main.getElementText(addressbook.tableContainer).then((text) => { + expect(text).to.contain(owner) + }) + }) + }) +}) diff --git a/cypress/e2e/happypath/recovery_hp_3.cy.js b/cypress/e2e/happypath/recovery_hp_3.cy.js new file mode 100644 index 0000000000..639a522c91 --- /dev/null +++ b/cypress/e2e/happypath/recovery_hp_3.cy.js @@ -0,0 +1,47 @@ +import * as constants from '../../support/constants' +import * as main from '../pages/main.page' +import * as owner from '../pages/owners.pages' +import * as recovery from '../pages/recovery.pages' +import * as addressbook from '../pages/address_book.page' +import * as tx from '../pages/transactions.page' + +describe('Recovery happy path tests 3', () => { + beforeEach(() => { + cy.visit(constants.setupUrl + constants.SEPOLIA_TEST_SAFE_25_RECOVERY_3) + cy.clearLocalStorage() + main.acceptCookies() + }) + // + // Check that an owner can cancel account recovery tx + it('Recovery setup happy path 3', { defaultCommandTimeout: 300000 }, () => { + owner.waitForConnectionStatus() + recovery.postponeRecovery() + + main.getElementText(addressbook.tableContainer).then((text) => { + let owner = constants.SPENDING_LIMIT_ADDRESS_2 + if (text.includes(constants.SPENDING_LIMIT_ADDRESS_2)) { + owner = constants.SEPOLIA_OWNER_2 + } + cy.visit(constants.homeUrl + constants.SEPOLIA_TEST_SAFE_25_RECOVERY_3) + recovery.clickOnStartRecoveryBtn() + recovery.enterOwnerAddress(owner) + recovery.clickOnNextBtn() + recovery.clickOnRecoveryExecuteBtn() + recovery.clickOnGoToQueueBtn() + recovery.cancelRecoveryTx() + + tx.selectExecuteNow() + tx.selectConnectedWalletOption() + recovery.clickOnExecuteRecoveryCancelBtn() + tx.waitForTxToComplete() + tx.clickOnFinishBtn() + + cy.visit(constants.setupUrl + constants.SEPOLIA_TEST_SAFE_25_RECOVERY_3) + main.verifyElementsCount(addressbook.tableContainer, 1) + cy.wait(1000) + main.getElementText(addressbook.tableContainer).then((text) => { + expect(text).to.contain(constants.DEFAULT_OWNER_ADDRESS) + }) + }) + }) +}) diff --git a/cypress/e2e/pages/address_book.page.js b/cypress/e2e/pages/address_book.page.js index eff18a543a..8d0b7f515c 100644 --- a/cypress/e2e/pages/address_book.page.js +++ b/cypress/e2e/pages/address_book.page.js @@ -10,7 +10,7 @@ const exportModalBtn = '[data-testid="export-modal-btn"]' export const editEntryBtn = 'button[aria-label="Edit entry"]' export const deleteEntryBtn = 'button[aria-label="Delete entry"]' export const deleteEntryModalBtnSection = '.MuiDialogActions-root' -const tableContainer = '[data-testid="table-container"]' +export const tableContainer = '[data-testid="table-container"]' const tableRow = '[data-testid="table-row"]' const importBtn = '[data-testid="import-btn"]' const cancelImportBtn = '[data-testid="cancel-btn"]' diff --git a/cypress/e2e/pages/create_tx.pages.js b/cypress/e2e/pages/create_tx.pages.js index 4f3ef98bdb..c822767f54 100644 --- a/cypress/e2e/pages/create_tx.pages.js +++ b/cypress/e2e/pages/create_tx.pages.js @@ -25,7 +25,7 @@ const txRowTitle = '[data-testid="tx-row-title"]' const advancedDetails = '[data-testid="tx-advanced-details"]' const baseGas = '[data-testid="tx-bas-gas"]' const requiredConfirmation = '[data-testid="required-confirmations"]' -const txDate = '[data-testid="tx-date"]' +export const txDate = '[data-testid="tx-date"]' const spamTokenWarningIcon = '[data-testid="warning"]' const untrustedTokenWarningModal = '[data-testid="untrusted-token-warning"]' const sendTokensBtn = '[data-testid="send-tokens-btn"]' @@ -351,7 +351,7 @@ export function clickOnNoLaterOption() { } export function clickOnSignTransactionBtn() { - cy.contains(signBtnStr).click() + cy.get('button').contains(signBtnStr).click() } export function waitForProposeRequest() { diff --git a/cypress/e2e/pages/create_wallet.pages.js b/cypress/e2e/pages/create_wallet.pages.js index 0c6ab0569e..0d7b5eab31 100644 --- a/cypress/e2e/pages/create_wallet.pages.js +++ b/cypress/e2e/pages/create_wallet.pages.js @@ -42,9 +42,8 @@ const welcomeToSafeStr = 'Welcome to Safe' export function verifyNewSafeDialogModal() { main.verifyElementsIsVisible([safeBackupAlert, dialogConfirmBtn]) } - +// export function verifyCFSafeCreated() { - sidebar.checkSafeAddressInHeader([constants.CF_SAFE_SHORT]) main.verifyElementsIsVisible([sidebar.pendingActivationIcon, safeActivationSection]) } diff --git a/cypress/e2e/pages/load_safe.pages.js b/cypress/e2e/pages/load_safe.pages.js index 39eb7be569..818cbd5578 100644 --- a/cypress/e2e/pages/load_safe.pages.js +++ b/cypress/e2e/pages/load_safe.pages.js @@ -28,7 +28,7 @@ const ownersConfirmationsStr = 'Owners and confirmations' const transactionStr = 'Transactions' const qrErrorMsg = 'The QR could not be read' const safeAddressError = 'Address given is not a valid Safe Account address' -const ownerNameLabel = 'Owner name' +const ownerNameLabel = 'Signer name' const mandatoryNetworks = [constants.networks.sepolia, constants.networks.polygon, constants.networks.ethereum] diff --git a/cypress/e2e/pages/main.page.js b/cypress/e2e/pages/main.page.js index dc6dba3370..cbf3264317 100644 --- a/cypress/e2e/pages/main.page.js +++ b/cypress/e2e/pages/main.page.js @@ -184,3 +184,7 @@ export function formatAddressInCaps(address) { return 'Invalid address format' } } + +export function getElementText(element) { + return cy.get(element).invoke('text') +} diff --git a/cypress/e2e/pages/recovery.pages.js b/cypress/e2e/pages/recovery.pages.js new file mode 100644 index 0000000000..fa55f5387e --- /dev/null +++ b/cypress/e2e/pages/recovery.pages.js @@ -0,0 +1,100 @@ +import * as constants from '../../support/constants' +import * as main from './main.page' +import * as safe from '../pages/load_safe.pages' +import { tableContainer } from '../pages/address_book.page' +import { txDate } from '../pages/create_tx.pages' + +const setupRecoveryBtn = '[data-testid="setup-recovery-btn"]' +const setupRecoveryModalBtn = '[data-testid="setup-btn"]' +const recoveryNextBtn = '[data-testid="next-btn"]' +const warningSection = '[data-testid="warning-section"]' +const termsCheckbox = 'input[type="checkbox"]' +const removeRecovererBtn = '[data-testid="remove-recoverer-btn"]' +const removeRecovererSection = '[data-testid="remove-recoverer-section"]' +const startRecoveryBtn = '[data-testid="start-recovery-btn"]' +const recoveryDelaySelect = '[data-testid="recovery-delay-select"]' +const postponeRecoveryBtn = '[data-testid="postpone-recovery-btn"]' +const goToQueueBtn = '[data-testid="queue-btn"]' +const executeBtn = '[data-testid="execute-btn"]' +const cancelRecoveryBtn = '[data-testid="cancel-recovery-btn"]' +const cancelProposalBtn = '[data-testid="cancel-proposal-btn"]' +const executeFormBtn = '[data-testid="execute-form-btn"]' + +export function clickOnExecuteRecoveryCancelBtn() { + cy.get(executeFormBtn).click() +} +export function cancelRecoveryTx() { + cy.get(txDate).click() + cy.get(cancelRecoveryBtn).click() + cy.get(cancelProposalBtn).click() +} +export function clickOnRecoveryExecuteBtn() { + cy.get(executeBtn, { timeout: 1200000 }).eq(0).should('be.enabled', { timeout: 1200000 }).click() +} +export function verifyTxNotInQueue() { + cy.get(txDate).should('have.length', 0) +} +export const recoveryDelayOptions = { + one_minute: '1 minute', +} + +export function setRecoveryDelay(option) { + cy.get(recoveryDelaySelect).click() + cy.contains(option).click() +} + +export function getSetupRecoveryBtn() { + return cy.get(setupRecoveryBtn).should('be.visible') +} + +export function clickOnSetupRecoveryBtn() { + getSetupRecoveryBtn().click() + cy.get(setupRecoveryModalBtn).should('be.visible') +} + +export function clickOnSetupRecoveryModalBtn() { + cy.get(setupRecoveryModalBtn).click() +} + +export function clickOnNextBtn() { + cy.get(recoveryNextBtn).click() +} + +export function clickOnGoToQueueBtn() { + cy.get(goToQueueBtn, { timeout: 120000 }).click() + cy.get(goToQueueBtn).should('not.exist') +} + +export function enterRecovererAddress(address) { + safe.inputOwnerAddress(0, address) +} + +export function agreeToTerms() { + cy.get(warningSection).within(() => { + main.verifyCheckboxeState(termsCheckbox, 0, constants.checkboxStates.unchecked) + cy.get(termsCheckbox).click() + main.verifyCheckboxeState(termsCheckbox, 0, constants.checkboxStates.checked) + }) +} + +export function verifyRecovererAdded(address) { + main.verifyValuesExist(tableContainer, address) +} + +export function removeRecoverer(index, recoverer) { + cy.get(removeRecovererBtn).eq(index).click() + cy.get(removeRecovererSection).contains(recoverer) +} + +export function clickOnStartRecoveryBtn() { + cy.get(startRecoveryBtn).click() +} + +export function enterOwnerAddress(address) { + safe.inputOwnerAddress(0, address) +} + +export function postponeRecovery() { + cy.get(postponeRecoveryBtn, { timeout: 1200000 }).click() + cy.get(postponeRecoveryBtn).should('not.exist') +} diff --git a/cypress/e2e/pages/safeapps.pages.js b/cypress/e2e/pages/safeapps.pages.js index 408ca17da8..81a760266f 100644 --- a/cypress/e2e/pages/safeapps.pages.js +++ b/cypress/e2e/pages/safeapps.pages.js @@ -62,8 +62,9 @@ export const transfer2AssetsStr = 'Transfer 2 assets' export const testTransfer1 = '1 transfer' export const testTransfer2 = '2 transfer' -export const testNativeTransfer2 = '2 native transfer' -export const testNativeTransfer1 = '1 native transfer' +export const nativeTransfer2 = '2 native transfer' +export const nativeTransfer1 = '1 native transfer' + export const testNativeTransfer = 'native transfer' export const newValueBool = 'newValue(bool):' diff --git a/cypress/e2e/pages/transactions.page.js b/cypress/e2e/pages/transactions.page.js new file mode 100644 index 0000000000..340f6da322 --- /dev/null +++ b/cypress/e2e/pages/transactions.page.js @@ -0,0 +1,36 @@ +const executeNowOption = '[data-testid="execute-checkbox"]' +const executeLaterOption = '[data-testid="sign-checkbox"]' +const connectedWalletExecutionMethod = '[data-testid="connected-wallet-execution-method"]' +const txStatus = '[data-testid="transaction-status"]' +const finishTransactionBtn = '[data-testid="finish-transaction-btn"]' + +const executeBtnStr = 'Execute' +const txCompletedStr = 'Transaction was successful' + +export function selectExecuteNow() { + cy.get(executeNowOption).click() +} + +export function selectConnectedWalletOption() { + cy.get(connectedWalletExecutionMethod).click() +} + +export function clickOnExecuteBtn() { + cy.get('button').contains(executeBtnStr).click() +} + +export function clickOnFinishBtn() { + cy.get(finishTransactionBtn).click() +} + +export function waitForTxToComplete() { + cy.get(txStatus, { timeout: 240000 }).should('contain', txCompletedStr) +} + +export function executeFlow_1() { + selectExecuteNow() + selectConnectedWalletOption() + clickOnExecuteBtn() + waitForTxToComplete() + clickOnFinishBtn() +} diff --git a/cypress/e2e/safe-apps/drain_account.spec.cy.js b/cypress/e2e/safe-apps/drain_account.spec.cy.js index a45d4b537b..07ada74d84 100644 --- a/cypress/e2e/safe-apps/drain_account.spec.cy.js +++ b/cypress/e2e/safe-apps/drain_account.spec.cy.js @@ -26,7 +26,7 @@ describe('Drain Account tests', { defaultCommandTimeout: 12000 }, () => { getBody().findAllByText(safeapps.transferEverythingStr).click() }) cy.findByRole('button', { name: safeapps.testTransfer1 }) - cy.findByRole('button', { name: safeapps.testNativeTransfer2 }) + cy.findByRole('button', { name: safeapps.nativeTransfer2 }) }) it('Verify partial drain can be created', () => { @@ -38,7 +38,7 @@ describe('Drain Account tests', { defaultCommandTimeout: 12000 }, () => { getBody().findAllByText(safeapps.transfer2AssetsStr).click() }) cy.findByRole('button', { name: safeapps.testTransfer2 }) - cy.findByRole('button', { name: safeapps.testNativeTransfer1 }) + cy.findByRole('button', { name: safeapps.nativeTransfer1 }) }) // TODO: ENS does not resolve @@ -48,7 +48,7 @@ describe('Drain Account tests', { defaultCommandTimeout: 12000 }, () => { getBody().findAllByText(safeapps.transferEverythingStr).click() }) cy.findByRole('button', { name: safeapps.testTransfer1 }) - cy.findByRole('button', { name: safeapps.testNativeTransfer2 }) + cy.findByRole('button', { name: safeapps.nativeTransfer2 }) }) it('Verify when cancelling a drain, previous data is preserved', () => { diff --git a/cypress/fixtures/balances.json b/cypress/fixtures/balances.json index ffcb4343b9..512dd142c1 100644 --- a/cypress/fixtures/balances.json +++ b/cypress/fixtures/balances.json @@ -19,9 +19,9 @@ "type": "NATIVE_TOKEN", "address": "0x0000000000000000000000000000000000000000", "decimals": 18, - "symbol": "GOR", - "name": "Görli Ether", - "logoUri": "https://safe-transaction-assets.staging.5afe.dev/chains/5/currency_logo.png" + "symbol": "ETH", + "name": "Sepolia Ether", + "logoUri": "https://safe-transaction-assets.staging.5afe.dev/chains/11155111/currency_logo.png" }, "balance": "21000000000000000", "fiatBalance": "35.14308", diff --git a/cypress/fixtures/txhistory_data_data.json b/cypress/fixtures/txhistory_data_data.json index bc62cd3f58..c0b15960a5 100644 --- a/cypress/fixtures/txhistory_data_data.json +++ b/cypress/fixtures/txhistory_data_data.json @@ -12,7 +12,7 @@ "accountCreation": { "actionsSummary": "Safe Account created by 0xC16D...6fED", "transactionSafehash": {}, - "summaryTime":"10:30 AM", + "summaryTime": "10:30 AM", "title": "Safe Account created", "creator": { "actionTitle": "Creator", @@ -39,7 +39,7 @@ "receivedFrom": "Received < 0.00001 ETH from:", "senderAddress": "sep:0x96D4c6fFC338912322813a77655fCC926b9A5aC5", "transactionHash": "0x4159...3e7d", - "transactionHashCopied":"0x415977f4e4912e22a5cabc4116f7e8f8984996e00a641dcccf8cbe1eb3db3e7d", + "transactionHashCopied": "0x415977f4e4912e22a5cabc4116f7e8f8984996e00a641dcccf8cbe1eb3db3e7d", "altImage": "Received", "altToken": "ETH" }, @@ -66,7 +66,7 @@ "summaryTxInfo": "2 actions", "summaryTime": "11:24 AM", "description": "MultiSend contract", - "altImage":"Safe: MultiSendCallOnly 1.3.0", + "altImage": "Safe: MultiSendCallOnly 1.3.0", "contractTitle": "Safe: MultiSendCallOnly 1.3.0", "contractAddress": "sep:0xA1dabEF33b3B82c7814B6D82A79e50F4AC44102B", "transactionHash": "0xa5dd...b064", @@ -79,8 +79,8 @@ "addOwner": { "title": "addOwnerWithThreshold", "summaryTime": "11:27 AM", - "description": "Add owner", - "altImage":"addOwnerWithThreshold", + "description": "Add signer", + "altImage": "addOwnerWithThreshold", "requiredConfirmationsTitle": "Required confirmations for new transactions", "ownerAddress": "sep:0x01A9F68e339da12565cfBc47fe7D6EdEcB11C46f", "transactionHash": "0x51d5...da62", @@ -89,8 +89,8 @@ "removeOwner": { "title": "removeOwner", "summaryTime": "11:46 AM", - "description": "Remove owner", - "altImage":"removeOwner", + "description": "Remove signer", + "altImage": "removeOwner", "requiredConfirmationsTitle": "Required confirmations for new transactions", "ownerAddress": "sep:0x8a39cE4E27C326B87B75AaFf820D442311CD8E4E", "transactionHash": "0xac66...a4b8", @@ -100,7 +100,7 @@ "title": "disableModule", "summaryTime": "7:37 AM", "description": "Disable module", - "altImage":"disableModule", + "altImage": "disableModule", "address": "sep:0xCFbFaC74C26F8647cBDb8c5caf80BB5b32E43134", "transactionHash": "0x8b39...adeb", "safeTxHash": "0xb820...bc4a" @@ -108,7 +108,7 @@ "changeThreshold": { "title": "changeThreshold", "summaryTime": "8:36 AM", - "altImage":"changeThreshold", + "altImage": "changeThreshold", "requiredConfirmationsTitle": "Required confirmations for new transactions", "transactionHash": "0xf3d2...26df", "safeTxHash": "0x46eb...e7d5" @@ -116,16 +116,16 @@ "swapOwner": { "title": "swapOwner", "summaryTime": "11:45 AM", - "description": "Swap owner", - "altImage":"swapOwner", + "description": "Swap signer", + "altImage": "swapOwner", "transactionHash": "0x8cf9...2f17", "safeTxHash": "0xd7a2...af6f", "newOwner": { - "actionTitile": "New owner", + "actionTitile": "New signer", "ownerAddress": "sep:0x8a39cE4E27C326B87B75AaFf820D442311CD8E4E" }, "oldOwner": { - "actionTitile": "Old owner", + "actionTitile": "Old signer", "ownerAddress": "sep:0x01A9F68e339da12565cfBc47fe7D6EdEcB11C46f" } }, @@ -134,7 +134,7 @@ "summaryTxInfo": "deleteAllowance", "summaryTime": "11:08 AM", "description": "Delete spending limit", - "altImage":"Contract interaction", + "altImage": "Contract interaction", "beneficiary": "Beneficiary", "beneficiaryAddress": "sep:0xC16Db0251654C0a72E91B190d81eAD367d2C6fED", "transactionHash": "0xd6e8...de8b", @@ -149,7 +149,7 @@ "summaryTxInfo": "3 actions", "summaryTime": "11:06 AM", "description": "MultiSend contract", - "altImage":"Safe: MultiSendCallOnly 1.3.0", + "altImage": "Safe: MultiSendCallOnly 1.3.0", "contractTitle": "Safe: MultiSendCallOnly 1.3.0", "contractAddress": "sep:0xA1dabEF33b3B82c7814B6D82A79e50F4AC44102B", "transactionHash": "0x69c3...bc37", @@ -185,9 +185,9 @@ "receivedFrom": "", "senderAddress": "sep:0x06373d5e45AD31BD354CeBfA8dB4eD2c75B8708e", "transactionHash": "0x54e7...2a7c", - "transactionHashCopied":"0x54e7e766b08d4210bc1cfcc84d84ca4782a0cc1efe9e7d9c032d305060ed2a7c", + "transactionHashCopied": "0x54e7e766b08d4210bc1cfcc84d84ca4782a0cc1efe9e7d9c032d305060ed2a7c", "altImage": "Received", "altToken": "" } } -} \ No newline at end of file +} diff --git a/cypress/support/constants.js b/cypress/support/constants.js index df883a2b38..b5bd41e4d8 100644 --- a/cypress/support/constants.js +++ b/cypress/support/constants.js @@ -35,6 +35,9 @@ export const SEPOLIA_TEST_SAFE_19_NONOWNER_NFT = 'sep:0x3e259dea1E317743Cb49CA93 export const SEPOLIA_TEST_SAFE_20_LOAD_SAFE = 'sep:0x027bBe128174F0e5e5d22ECe9623698E01cd3970' export const SEPOLIA_TEST_SAFE_21_LOAD_SAFE = 'eth:0x8675B754342754A30A2AeF474D114d8460bca19b' export const SEPOLIA_TEST_SAFE_22_IMPORT = 'sep:0xBc7e586D276e2da521DE8ff17255fd878621cc59' +export const SEPOLIA_TEST_SAFE_23_RECOVERY_1 = 'sep:0x702E067A0015F1b835d9c631Cb28A9F617314F27' +export const SEPOLIA_TEST_SAFE_24_RECOVERY_2 = 'sep:0xb791302040DB5Ab4Ade0b5295cecCaeF07AF07a1' +export const SEPOLIA_TEST_SAFE_25_RECOVERY_3 = 'sep:0xAE1E3f93fda95eEbb857Ee06325f6F1e45EF3CBE' export const SEPOLIA_CONTRACT_SHORT = '0x11AB...34aF' export const SEPOLIA_RECIPIENT_ADDR_SHORT = '0x4DD4...7bde' export const GNO_TEST_SAFE = 'gno:0xB8d760a90a5ed54D3c2b3EFC231277e99188642A' @@ -48,9 +51,9 @@ export const DEFAULT_OWNER_ADDRESS = '0xC16Db0251654C0a72E91B190d81eAD367d2C6fED // Below is also used in sidebar tests as a beneficiary export const SPENDING_LIMIT_ADDRESS_2 = '0x52835f11E348605E9D791Ec09380a3224526d538' export const SEPOLIA_OWNER_2 = '0x96D4c6fFC338912322813a77655fCC926b9A5aC5' +export const SEPOLIA_OWNER_2_SHORT = '0x96D4...5aC5' export const TEST_SAFE_2 = 'gor:0xE96C43C54B08eC528e9e815fC3D02Ea94A320505' export const SIDEBAR_ADDRESS = '0x04f8...1a91' -export const CF_SAFE_SHORT = '0x702E...4F27' //ENS_TEST_SEPOLIA resolves to 0xBf30F749FC027a5d79c4710D988F0D3C8e217A4F export const ENS_TEST_SEPOLIA = 'e2etestsafe.eth' export const ENS_TEST_GOERLI = 'goerli-safe-test.eth' @@ -200,7 +203,7 @@ export const addressBookErrrMsg = { alreadyAdded: 'Address already added', ownerAdded: 'Signer is already added', failedResolve: 'Failed to resolve the address', - emptyAddress: 'Signer', + emptyAddress: 'Owner', safeAlreadyAdded: 'Safe Account is already added', prefixMismatch: "doesn't match the current chain", invalidPrefix(prefix) { diff --git a/src/components/tx-flow/flows/CancelRecovery/CancelRecoveryOverview.tsx b/src/components/tx-flow/flows/CancelRecovery/CancelRecoveryOverview.tsx index e0d397fb03..8e128c2871 100644 --- a/src/components/tx-flow/flows/CancelRecovery/CancelRecoveryOverview.tsx +++ b/src/components/tx-flow/flows/CancelRecovery/CancelRecoveryOverview.tsx @@ -38,7 +38,7 @@ export function CancelRecoveryOverview({ onSubmit }: { onSubmit: () => void }): Go back - diff --git a/src/components/tx-flow/flows/RecoverAccount/RecoverAccountFlowReview.tsx b/src/components/tx-flow/flows/RecoverAccount/RecoverAccountFlowReview.tsx index b7002e6db1..4d78409375 100644 --- a/src/components/tx-flow/flows/RecoverAccount/RecoverAccountFlowReview.tsx +++ b/src/components/tx-flow/flows/RecoverAccount/RecoverAccountFlowReview.tsx @@ -177,7 +177,12 @@ export function RecoverAccountFlowReview({ params }: { params: RecoverAccountFlo {(isOk) => ( - )} diff --git a/src/components/tx-flow/flows/RecoverAccount/RecoverAccountFlowSetup.tsx b/src/components/tx-flow/flows/RecoverAccount/RecoverAccountFlowSetup.tsx index cec5338074..babd3d4a0a 100644 --- a/src/components/tx-flow/flows/RecoverAccount/RecoverAccountFlowSetup.tsx +++ b/src/components/tx-flow/flows/RecoverAccount/RecoverAccountFlowSetup.tsx @@ -200,7 +200,7 @@ export function RecoverAccountFlowSetup({ - diff --git a/src/components/tx-flow/flows/RemoveRecovery/RemoveRecoveryFlowOverview.tsx b/src/components/tx-flow/flows/RemoveRecovery/RemoveRecoveryFlowOverview.tsx index dc58ff6d13..94dd3951b4 100644 --- a/src/components/tx-flow/flows/RemoveRecovery/RemoveRecoveryFlowOverview.tsx +++ b/src/components/tx-flow/flows/RemoveRecovery/RemoveRecoveryFlowOverview.tsx @@ -22,7 +22,7 @@ export function RemoveRecoveryFlowOverview({ This Recoverer will not be able to initiate the recovery process once this transaction is executed. -
+
Removing Recoverer @@ -42,7 +42,7 @@ export function RemoveRecoveryFlowOverview({ - diff --git a/src/components/tx-flow/flows/SuccessScreen/StatusMessage.tsx b/src/components/tx-flow/flows/SuccessScreen/StatusMessage.tsx index 4632a14182..e365b66040 100644 --- a/src/components/tx-flow/flows/SuccessScreen/StatusMessage.tsx +++ b/src/components/tx-flow/flows/SuccessScreen/StatusMessage.tsx @@ -36,7 +36,7 @@ const StatusMessage = ({ status, error }: { status: PendingStatus; error?: Error <> - + {stepInfo.description} diff --git a/src/components/tx-flow/flows/UpsertRecovery/UpsertRecoveryFlowIntro.tsx b/src/components/tx-flow/flows/UpsertRecovery/UpsertRecoveryFlowIntro.tsx index 46663d2d24..0b23515ff1 100644 --- a/src/components/tx-flow/flows/UpsertRecovery/UpsertRecoveryFlowIntro.tsx +++ b/src/components/tx-flow/flows/UpsertRecovery/UpsertRecoveryFlowIntro.tsx @@ -59,7 +59,7 @@ export function UpsertRecoveryFlowIntro({ onSubmit }: { onSubmit: () => void }): - diff --git a/src/components/tx-flow/flows/UpsertRecovery/UpsertRecoveryFlowSettings.tsx b/src/components/tx-flow/flows/UpsertRecovery/UpsertRecoveryFlowSettings.tsx index 3093746494..0c470cd158 100644 --- a/src/components/tx-flow/flows/UpsertRecovery/UpsertRecoveryFlowSettings.tsx +++ b/src/components/tx-flow/flows/UpsertRecovery/UpsertRecoveryFlowSettings.tsx @@ -144,7 +144,13 @@ export function UpsertRecoveryFlowSettings({ control={formMethods.control} name={UpsertRecoveryFlowFields.delay} render={({ field: { ref, ...field } }) => ( - + {periods.delay.map(({ label, value }, index) => ( {label} @@ -200,6 +206,7 @@ export function UpsertRecoveryFlowSettings({ setUnderstandsRisk(checked)} />} sx={{ pl: 2 }} @@ -208,7 +215,7 @@ export function UpsertRecoveryFlowSettings({ - diff --git a/src/components/tx/SignOrExecuteForm/ExecuteForm.tsx b/src/components/tx/SignOrExecuteForm/ExecuteForm.tsx index f2452bb73d..b8ba08b34a 100644 --- a/src/components/tx/SignOrExecuteForm/ExecuteForm.tsx +++ b/src/components/tx/SignOrExecuteForm/ExecuteForm.tsx @@ -192,7 +192,13 @@ export const ExecuteForm = ({ {/* Submit button */} {(isOk) => ( - )} diff --git a/src/features/recovery/components/CancelRecoveryButton/index.tsx b/src/features/recovery/components/CancelRecoveryButton/index.tsx index 2fd06e9d3a..23c683311b 100644 --- a/src/features/recovery/components/CancelRecoveryButton/index.tsx +++ b/src/features/recovery/components/CancelRecoveryButton/index.tsx @@ -61,7 +61,13 @@ export function CancelRecoveryButton({ const isDisabled = isPending || (isOwner ? !isOk : !isOk || !isExpired) return ( - ) diff --git a/src/features/recovery/components/ExecuteRecoveryButton/index.tsx b/src/features/recovery/components/ExecuteRecoveryButton/index.tsx index 06831487ad..400b404a39 100644 --- a/src/features/recovery/components/ExecuteRecoveryButton/index.tsx +++ b/src/features/recovery/components/ExecuteRecoveryButton/index.tsx @@ -64,6 +64,7 @@ export function ExecuteRecoveryButton({ > diff --git a/src/features/recovery/components/RecoveryCards/RecoveryProposalCard.tsx b/src/features/recovery/components/RecoveryCards/RecoveryProposalCard.tsx index 8cfed37f00..72c08a5e48 100644 --- a/src/features/recovery/components/RecoveryCards/RecoveryProposalCard.tsx +++ b/src/features/recovery/components/RecoveryCards/RecoveryProposalCard.tsx @@ -60,7 +60,7 @@ export function _RecoveryProposalCard({ orientation = 'vertical', onClose, safe, ) const recoveryButton = ( - ) @@ -118,6 +118,7 @@ export function _RecoveryProposalCard({ orientation = 'vertical', onClose, safe,