Skip to content

Commit

Permalink
Tests: Add proposers tests (#4542)
Browse files Browse the repository at this point in the history
  • Loading branch information
mike10ca authored Nov 20, 2024
1 parent abdae72 commit 436f99e
Show file tree
Hide file tree
Showing 14 changed files with 194 additions and 47 deletions.
29 changes: 19 additions & 10 deletions cypress/e2e/happypath_2/proposers.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,50 @@ import { getSafes, CATEGORIES } from '../../support/safes/safesHandler.js'
import * as wallet from '../../support/utils/wallet.js'
import * as navigation from '../pages/navigation.page.js'
import * as proposer from '../pages/proposers.pages.js'
import { getSafeDelegates } from '../../support/utils/cgw.js'

let staticSafes = []
const walletCredentials = JSON.parse(Cypress.env('CYPRESS_WALLET_CREDENTIALS'))
const signer = walletCredentials.OWNER_4_PRIVATE_KEY
const signer3 = walletCredentials.OWNER_3_PRIVATE_KEY
const addedProposer = walletCredentials.OWNER_3_WALLET_ADDRESS
const proposerAddress = 'sep:0xC16D...6fED'
const proposerAddress2 = '0x8eeC...2a3b'
const proposerName2 = 'Proposer 2'
const proposerName = 'Proposer 1'
const changedProposerName = 'Changed proposer name'

describe('Happy path Proposers tests', () => {
before(async () => {
staticSafes = await getSafes(CATEGORIES.static)
})

beforeEach(() => {
//TODO: Flaky due to UI retrieval issue - wip
it.skip('Verify that editing a proposer is only possible for the proposer created by the creator', () => {
cy.visit(constants.setupUrl + staticSafes.SEP_STATIC_SAFE_31)
cy.contains(owner.safeAccountNonceStr, { timeout: 10000 })
wallet.connectSigner(signer)
})

it('Verify that editing a proposer is only possible for the proposer created by the creator', () => {
navigation.clickOnWalletExpandMoreIcon()
navigation.clickOnDisconnectBtn()
wallet.connectSigner(signer3)
cy.contains(owner.safeAccountNonceStr, { timeout: 10000 })
proposer.verifyEditProposerBtnDisabled(proposerAddress)

proposer.clickOnEditProposerBtn(proposerAddress2)
proposer.enterProposerName(changedProposerName)
proposer.clickOnSubmitProposerBtn()
proposer.checkProposerData(0, [changedProposerName])
proposer.checkProposerData([changedProposerName])

proposer.clickOnEditProposerBtn(proposerAddress2)
proposer.enterProposerName(proposerName2)
proposer.clickOnSubmitProposerBtn()
proposer.checkProposerData(0, [proposerName2])
proposer.checkProposerData([proposerName2])
})

it('Verify a proposer can be added', () => {
cy.visit(constants.setupUrl + staticSafes.SEP_STATIC_SAFE_32)
wallet.connectSigner(signer)
cy.contains(owner.safeAccountNonceStr, { timeout: 10000 })
proposer.deleteAllProposers()
proposer.clickOnAddProposerBtn()
proposer.enterProposerData(addedProposer, proposerName)
proposer.clickOnSubmitProposerBtn()
proposer.verifyProposerSuccessMsgDisplayed()
})
})
10 changes: 10 additions & 0 deletions cypress/e2e/pages/create_tx.pages.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ const radioSelector = 'div[role="radiogroup"]'
const rejectTxBtn = '[data-testid="reject-btn"]'
const deleteTxModalBtn = '[data-testid="delete-tx-btn"]'
const toggleUntrustedBtn = '[data-testid="toggle-untrusted"]'
const simulateTxBtn = '[data-testid="simulate-btn"]'
const simulateSuccess = '[data-testid="simulation-success-msg"]'

const viewTransactionBtn = 'View transaction'
const transactionDetailsTitle = 'Transaction details'
Expand Down Expand Up @@ -629,3 +631,11 @@ export function verifyBulkExecuteBtnIsDisabled() {
export function toggleUntrustedTxs() {
cy.get(toggleUntrustedBtn).click()
}

export function clickOnSimulateTxBtn() {
cy.get(simulateTxBtn).click()
}

export function verifySuccessfulSimulation() {
cy.get(simulateSuccess).should('exist')
}
1 change: 0 additions & 1 deletion cypress/e2e/pages/nfts.pages.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ const modalHeader = '[data-testid="modal-header"]'
const modalSelectedNFTs = '[data-testid="selected-nfts"]'
const nftItemList = '[data-testid="nft-item-list"]'
const nftItemNane = '[data-testid="nft-item-name"]'
const signBtn = '[data-testid="sign-btn"]'
const txDetailsSummary = '[data-testid="decoded-tx-summary"]'
const txAccordionDetails = '[data-testid="decoded-tx-details"]'
const accordionActionItem = '[data-testid="action-item"]'
Expand Down
77 changes: 53 additions & 24 deletions cypress/e2e/pages/proposers.pages.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as navigation from './navigation.page'
import * as addressBook from './address_book.page'
import * as batch from './batches.pages'
import * as create_tx from './create_tx.pages'
import { getSafeDelegates } from '../../support/utils/cgw.js'

export const proposersSection = '[data-testid="proposer-section"]'
const addProposerBtn = '[data-testid="add-proposer-btn"]'
Expand All @@ -18,6 +19,7 @@ const submitProposerBtn = '[data-testid="submit-proposer-btn"]'
const safeAsProposerMessage = 'Cannot add Safe Account itself as proposer'
const proposedTxMessage =
'This transaction was created by a Proposer. Please review and either confirm or reject it. Once confirmed, it can be finalized and executed'
const proposerAddedMsg = 'Proposer added successfully!'

export function verifyPropsalStatusExists() {
cy.get(create_tx.proposalStatus).should('exist')
Expand All @@ -37,10 +39,6 @@ export function verifyProposedTxMsgVisible() {
cy.contains(proposedTxMessage).should('be.visible')
}

export function verifyDeleteProposerBtnIsDisabled() {
cy.get(deleteProposerBtn).should('exist').and('be.disabled')
}

export function clickOnAddProposerBtn() {
cy.get(addProposerBtn).click()
}
Expand All @@ -57,27 +55,48 @@ export function clickOnSubmitProposerBtn() {
cy.get(submitProposerBtn).click()
}

export function checkCreatorAddress(index, data) {
export function checkCreatorAddress(data) {
cy.get(proposersSection).within(() => {
cy.get(addressBook.tableRow)
.eq(index)
.within(() => {
Object.entries(data).forEach(([key, value], i) => {
cy.get('td').eq(1).should('contain.text', value)
Object.entries(data).forEach(([key, value]) => {
let found = false
cy.get(addressBook.tableRow)
.each(($row) => {
cy.wrap($row)
.find('td')
.eq(1)
.then(($cell) => {
if ($cell.text().includes(value)) {
found = true
}
})
})
})
.then(() => {
expect(found, `Value "${value}" should be found in td:eq(1) within proposersSection`).to.be.true
})
})
})
}

export function checkProposerData(index, data) {
export function checkProposerData(data) {
cy.get(proposersSection).within(() => {
cy.get(addressBook.tableRow)
.eq(index)
.within(() => {
Object.entries(data).forEach(([key, value], i) => {
cy.get('td').eq(0).should('contain.text', value)
Object.entries(data).forEach(([key, value]) => {
let found = false

cy.get(addressBook.tableRow)
.each(($row) => {
cy.wrap($row)
.find('td')
.eq(0)
.then(($cell) => {
if ($cell.text().includes(value)) {
found = true
}
})
})
})
.then(() => {
expect(found, `Value "${value}" should be found in td:eq(0) within proposersSection`).to.be.true
})
})
})
}

Expand All @@ -87,12 +106,6 @@ export function clickOnEditProposerBtn(address) {
})
}

export function verifyEditProposerBtnDisabled(address) {
cy.get(proposersSection).within(() => {
cy.get(addressBook.tableRow).contains(address).parents('tr').find(editProposerBtn).should('be.disabled')
})
}

export function confirmProposerDeletion(index) {
cy.get(confrimDeleteProposerBtn).eq(index).click()
}
Expand Down Expand Up @@ -122,3 +135,19 @@ export function checkSafeAsProposerErrorMessage() {
export function verifyBatchDoesNotExist() {
main.verifyElementsCount(batch.batchTxTopBar, 0)
}

export function verifyProposerSuccessMsgDisplayed() {
cy.contains(proposerAddedMsg).should('exist')
}

export function verifyEditProposerBtnDisabled(address) {
cy.get(proposersSection).within(() => {
cy.get(addressBook.tableRow).contains(address).parents('tr').find(editProposerBtn).should('be.disabled')
})
}

export function verifyDeleteProposerBtnIsDisabled(address) {
cy.get(proposersSection).within(() => {
cy.get(addressBook.tableRow).contains(address).parents('tr').find(deleteProposerBtn).should('be.disabled')
})
}
3 changes: 2 additions & 1 deletion cypress/e2e/pages/sidebar.pages.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ const signersNotConsistentMsg3 =
'To manage your account easier and to prevent lose of funds, we recommend keeping the same signers'
const signersNotConsistentConfirmTxViewMsg = (network) =>
`Signers are not consistent across networks on this account. Changing signers will only affect the account on ${network}`
const activateStr = 'You need to activate your Safe first'

export const addedSafesEth = ['0x8675...a19b']
export const addedSafesSepolia = ['0x6d0b...6dC1', '0x5912...fFdb', '0x0637...708e', '0xD157...DE9a']
Expand Down Expand Up @@ -187,7 +188,7 @@ export function verifyTxCounter(counter) {
}

export function verifyNavItemDisabled(item) {
cy.get(sideBarListItem).contains(item).parents('li').invoke('attr', 'class').should('include', 'disabled')
cy.get(`div[aria-label*="${activateStr}"]`).contains(item).should('exist')
}

export function verifySafeCount(count) {
Expand Down
10 changes: 10 additions & 0 deletions cypress/e2e/pages/transactions.page.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,21 @@ const connectedWalletExecutionMethod = '[data-testid="connected-wallet-execution
const txStatus = '[data-testid="transaction-status"]'
const finishTransactionBtn = '[data-testid="finish-transaction-btn"]'
const executeFormBtn = '[data-testid="execute-form-btn"]'
const signBtn = '[data-testid="sign-btn"]'
const txConfirmBtn = '[data-track="tx-list: Confirm transaction"] > button'

const executeBtnStr = 'Execute'
const txCompletedStr = 'Transaction was successful'
export const relayRemainingAttemptsStr = 'free transactions left today'

export function verifyTxConfirmBtnDisabled() {
cy.get(txConfirmBtn).should('be.disabled')
}

export function verifySignBtnEnabled() {
cy.get(signBtn).should('be.enabled')
}

export function selectExecuteNow() {
cy.get(executeNowOption).click()
}
Expand Down
3 changes: 0 additions & 3 deletions cypress/e2e/regression/multichain_network.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ let staticSafes = []

const walletCredentials = JSON.parse(Cypress.env('CYPRESS_WALLET_CREDENTIALS'))
const signer = walletCredentials.OWNER_4_PRIVATE_KEY
// DO NOT use OWNER_2_PRIVATE_KEY for safe creation. Used for CF safes.
const signer2 = walletCredentials.OWNER_2_PRIVATE_KEY

describe('Multichain add network tests', () => {
before(async () => {
Expand Down Expand Up @@ -51,7 +49,6 @@ describe('Multichain add network tests', () => {
main.addToLocalStorage(constants.localStorageKeys.SAFE_v2__addedSafes, ls.addedSafes.set6_undeployed_safe)
main.addToLocalStorage(constants.localStorageKeys.SAFE_v2__undeployedSafes, ls.undeployedSafe.safe1)
main.addToLocalStorage(constants.localStorageKeys.SAFE_v2__addressBook, ls.addressBookData.undeployed)
wallet.connectSigner(signer2)
sideBar.openSidebar()
sideBar.removeSafeItem(sideBar.undeployedSafe)
cy.wrap(null, { timeout: 10000 }).should(() => {
Expand Down
8 changes: 4 additions & 4 deletions cypress/e2e/regression/proposers.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,26 +58,26 @@ describe('Proposers tests', () => {
})

it('Verify a proposer Creator is shown in the table', () => {
proposer.checkCreatorAddress(0, [creatorAddress])
proposer.checkCreatorAddress([creatorAddress])
})

it('Verify non-creators of a proposers cannot edit or delete it', () => {
navigation.clickOnWalletExpandMoreIcon()
navigation.clickOnDisconnectBtn()
wallet.connectSigner(signer2)
proposer.verifyDeleteProposerBtnIsDisabled()
proposer.verifyDeleteProposerBtnIsDisabled(proposerAddress)
proposer.verifyEditProposerBtnDisabled(proposerAddress)
})

it('Verify that the address book name of the proposers overwrites the name given during its creation', () => {
main.addToLocalStorage(constants.localStorageKeys.SAFE_v2__addressBook, ls.addressBookData.proposers)
cy.reload()
cy.contains(owner.safeAccountNonceStr, { timeout: 10000 })
proposer.checkProposerData(0, [proposerNameAD])
proposer.checkProposerData([proposerNameAD])
})

it('Verify if the address book entry of propers name is removed, then the name given during its creation shows again', () => {
proposer.checkProposerData(0, [proposerName])
proposer.checkProposerData([proposerName])
})

it('Verify Proposers cannot see the "Batched tx" button in the header', () => {
Expand Down
88 changes: 88 additions & 0 deletions cypress/e2e/regression/proposers_2.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import * as constants from '../../support/constants.js'
import * as owner from '../pages/owners.pages.js'
import { getSafes, CATEGORIES } from '../../support/safes/safesHandler.js'
import * as wallet from '../../support/utils/wallet.js'
import * as proposer from '../pages/proposers.pages.js'
import * as createtx from '../pages/create_tx.pages.js'
import * as tx from '../pages/transactions.page.js'

let staticSafes = []
const walletCredentials = JSON.parse(Cypress.env('CYPRESS_WALLET_CREDENTIALS'))
const signer = walletCredentials.OWNER_4_PRIVATE_KEY
const signer2 = walletCredentials.OWNER_1_PRIVATE_KEY
const signer3 = walletCredentials.OWNER_3_PRIVATE_KEY
const proposerAddress = '0x8eeC...2a3b'
const proposerAddress_2 = '0x0972...9f35'
const sendValue = 0.000001

describe('Proposers 2 tests', () => {
before(async () => {
staticSafes = await getSafes(CATEGORIES.static)
})

it('Verify that an owner that is also a proposer can still execute transactions', () => {
cy.visit(constants.setupUrl + staticSafes.SEP_STATIC_SAFE_32)
cy.contains(owner.safeAccountNonceStr, { timeout: 10000 })
wallet.connectSigner(signer)
createtx.clickOnNewtransactionBtn()
createtx.clickOnSendTokensBtn()
createtx.typeRecipientAddress(constants.EOA)
createtx.setSendValue(sendValue)
createtx.clickOnNextBtn()
tx.selectExecuteNow()
createtx.verifySubmitBtnIsEnabled()
tx.selectExecuteLater()
tx.verifySignBtnEnabled()
})

it('Verify a proposers is capable of propose transactions', () => {
cy.visit(constants.setupUrl + staticSafes.SEP_STATIC_SAFE_33)
cy.contains(owner.safeAccountNonceStr, { timeout: 10000 })
wallet.connectSigner(signer2)
createtx.clickOnNewtransactionBtn()
createtx.clickOnSendTokensBtn()
createtx.typeRecipientAddress(constants.EOA)
createtx.setSendValue(sendValue)
createtx.clickOnNextBtn()
createtx.verifySubmitBtnIsEnabled()
})

it('Verify a proposers cannot confirm a transaction', () => {
cy.visit(constants.transactionQueueUrl + staticSafes.SEP_STATIC_SAFE_31)
wallet.connectSigner(signer2)
tx.verifyTxConfirmBtnDisabled()
})

it('Verify a proposer cannot edit himself', () => {
cy.visit(constants.setupUrl + staticSafes.SEP_STATIC_SAFE_31)
wallet.connectSigner(signer2)
proposer.verifyEditProposerBtnDisabled(proposerAddress)
})

it('Verify a proposer cannot edit or remove other proposers', () => {
cy.visit(constants.setupUrl + staticSafes.SEP_STATIC_SAFE_33)
wallet.connectSigner(signer2)
proposer.verifyEditProposerBtnDisabled(proposerAddress_2)
proposer.verifyDeleteProposerBtnIsDisabled(proposerAddress_2)
})

it('Verify that deleting a proposer is only possible by creator', () => {
cy.visit(constants.setupUrl + staticSafes.SEP_STATIC_SAFE_33)
wallet.connectSigner(signer3)
proposer.verifyEditProposerBtnDisabled(proposerAddress_2)
proposer.verifyDeleteProposerBtnIsDisabled(proposerAddress_2)
proposer.verifyEditProposerBtnDisabled(proposerAddress)
proposer.verifyDeleteProposerBtnIsDisabled(proposerAddress)
})

//TODO: Unskip when tenderly visibilty bug is solved
it.skip('Verify a Tenderly simulation can be performed while proposing a tx', () => {
cy.visit(constants.setupUrl + staticSafes.SEP_STATIC_SAFE_33)
wallet.connectSigner(signer2)
owner.openAddOwnerWindow()
owner.typeOwnerAddress(constants.SEPOLIA_OWNER_2)
owner.clickOnNextBtn()
createtx.clickOnSimulateTxBtn()
createtx.verifySuccessfulSimulation()
})
})
Loading

0 comments on commit 436f99e

Please sign in to comment.