Skip to content

Commit

Permalink
Tests: add happy path flows for recovery v1 (#3394)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
mike10ca authored Mar 6, 2024
1 parent cb4ec12 commit af8e4fb
Show file tree
Hide file tree
Showing 32 changed files with 404 additions and 49 deletions.
58 changes: 58 additions & 0 deletions .github/workflows/e2e-hp-ondemand.yml
Original file line number Diff line number Diff line change
@@ -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"
5 changes: 4 additions & 1 deletion .github/workflows/e2e-ondemand.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
30 changes: 30 additions & 0 deletions cypress/e2e/happypath/recovery_hp_1.cy.js
Original file line number Diff line number Diff line change
@@ -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()
})
})
41 changes: 41 additions & 0 deletions cypress/e2e/happypath/recovery_hp_2.cy.js
Original file line number Diff line number Diff line change
@@ -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)
})
})
})
})
47 changes: 47 additions & 0 deletions cypress/e2e/happypath/recovery_hp_3.cy.js
Original file line number Diff line number Diff line change
@@ -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)
})
})
})
})
2 changes: 1 addition & 1 deletion cypress/e2e/pages/address_book.page.js
Original file line number Diff line number Diff line change
Expand Up @@ -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"]'
Expand Down
4 changes: 2 additions & 2 deletions cypress/e2e/pages/create_tx.pages.js
Original file line number Diff line number Diff line change
Expand Up @@ -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"]'
Expand Down Expand Up @@ -351,7 +351,7 @@ export function clickOnNoLaterOption() {
}

export function clickOnSignTransactionBtn() {
cy.contains(signBtnStr).click()
cy.get('button').contains(signBtnStr).click()
}

export function waitForProposeRequest() {
Expand Down
3 changes: 1 addition & 2 deletions cypress/e2e/pages/create_wallet.pages.js
Original file line number Diff line number Diff line change
Expand Up @@ -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])
}

Expand Down
2 changes: 1 addition & 1 deletion cypress/e2e/pages/load_safe.pages.js
Original file line number Diff line number Diff line change
Expand Up @@ -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]

Expand Down
4 changes: 4 additions & 0 deletions cypress/e2e/pages/main.page.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,3 +184,7 @@ export function formatAddressInCaps(address) {
return 'Invalid address format'
}
}

export function getElementText(element) {
return cy.get(element).invoke('text')
}
100 changes: 100 additions & 0 deletions cypress/e2e/pages/recovery.pages.js
Original file line number Diff line number Diff line change
@@ -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')
}
5 changes: 3 additions & 2 deletions cypress/e2e/pages/safeapps.pages.js
Original file line number Diff line number Diff line change
Expand Up @@ -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):'
Expand Down
36 changes: 36 additions & 0 deletions cypress/e2e/pages/transactions.page.js
Original file line number Diff line number Diff line change
@@ -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()
}
Loading

0 comments on commit af8e4fb

Please sign in to comment.