From 8d8f6b492828d623b3e36dc22aa9a2c159c0419e Mon Sep 17 00:00:00 2001 From: Joe Tsang <30622993+jtsang586@users.noreply.github.com> Date: Wed, 22 Mar 2023 17:35:00 +0000 Subject: [PATCH] test(governance): governance tests refactor (#3059) --- ...l-details.cy.js => proposal-details.cy.ts} | 192 ++-- ...l-enacted.cy.js => proposal-enacted.cy.ts} | 62 +- ...roposal-flow.cy.js => proposal-flow.cy.ts} | 285 +++--- ...posal-forms.cy.js => proposal-forms.cy.ts} | 115 ++- ...roposal-list.cy.js => proposal-list.cy.ts} | 125 +-- ...{rewards-flow.cy.js => rewards-flow.cy.ts} | 76 +- .../src/integration/flow/staking-flow.cy.js | 876 ------------------ .../src/integration/flow/staking-flow.cy.ts | 454 +++++++++ ...low.cy.js => token-association-flow.cy.ts} | 223 ++--- ...rawal-flow.cy.js => withdrawal-flow.cy.ts} | 127 ++- .../view/{home.cy.js => home.cy.ts} | 55 +- .../src/integration/view/pages.cy.js | 284 ------ .../src/integration/view/proposal.cy.ts | 77 ++ .../{pubkey-view.cy.js => pubkey-view.cy.ts} | 33 +- .../src/integration/view/rewards.cy.ts | 42 + .../view/{token.cy.js => token.cy.ts} | 5 +- .../view/{tranches.cy.js => tranches.cy.ts} | 11 +- .../src/integration/view/validators.cy.js | 210 ----- .../src/integration/view/validators.cy.ts | 246 +++++ .../view/{vesting.cy.js => vesting.cy.ts} | 32 +- .../{wallet-eth.cy.js => wallet-eth.cy.ts} | 41 +- .../{wallet-vega.cy.js => wallet-vega.cy.ts} | 36 +- .../src/integration/view/withdraw.cy.ts | 35 + .../src/support/common-interfaces.ts | 128 +++ .../src/support/common.functions.js | 87 -- .../src/support/common.functions.ts | 86 ++ .../src/support/governance.functions.js | 228 ----- .../src/support/governance.functions.ts | 215 +++++ apps/governance-e2e/src/support/index.d.ts | 20 + apps/governance-e2e/src/support/index.js | 12 +- ...king.functions.js => staking.functions.ts} | 231 ++--- ...h.functions.js => wallet-eth.functions.ts} | 4 +- .../src/support/wallet-teardown.functions.js | 197 ---- .../src/support/wallet-teardown.functions.ts | 146 +++ .../src/support/wallet-vega.functions.js | 17 - .../src/support/wallet-vega.functions.ts | 18 + apps/governance-e2e/tsconfig.json | 2 + .../src/components/eth-wallet/eth-wallet.tsx | 2 +- libs/cypress/src/index.ts | 4 + .../cypress/src/lib/capsule/ethereum-setup.ts | 2 +- .../commands/add-validators-to-multisig.ts | 2 +- .../associate-tokens-to-vega-wallet.ts | 33 + .../src/lib/commands/contains-exactly.ts | 2 +- .../lib/commands/get-network-parameters.ts | 123 ++- .../vega-wallet-receive-fauceted-asset.ts | 13 +- .../vega-wallet-top-up-rewards-pool.ts | 50 + .../data_node_full_external_postgres.tmpl | 7 +- .../default/data_node_full_snapshots.tmpl | 1 + .../default/tendermint_full.tmpl | 22 +- .../node_set_templates/default/vega_full.tmpl | 121 ++- 50 files changed, 2721 insertions(+), 2694 deletions(-) rename apps/governance-e2e/src/integration/flow/{proposal-details.cy.js => proposal-details.cy.ts} (56%) rename apps/governance-e2e/src/integration/flow/{proposal-enacted.cy.js => proposal-enacted.cy.ts} (74%) rename apps/governance-e2e/src/integration/flow/{proposal-flow.cy.js => proposal-flow.cy.ts} (54%) rename apps/governance-e2e/src/integration/flow/{proposal-forms.cy.js => proposal-forms.cy.ts} (83%) rename apps/governance-e2e/src/integration/flow/{proposal-list.cy.js => proposal-list.cy.ts} (54%) rename apps/governance-e2e/src/integration/flow/{rewards-flow.cy.js => rewards-flow.cy.ts} (58%) delete mode 100644 apps/governance-e2e/src/integration/flow/staking-flow.cy.js create mode 100644 apps/governance-e2e/src/integration/flow/staking-flow.cy.ts rename apps/governance-e2e/src/integration/flow/{token-association-flow.cy.js => token-association-flow.cy.ts} (64%) rename apps/governance-e2e/src/integration/flow/{withdrawal-flow.cy.js => withdrawal-flow.cy.ts} (63%) rename apps/governance-e2e/src/integration/view/{home.cy.js => home.cy.ts} (70%) delete mode 100644 apps/governance-e2e/src/integration/view/pages.cy.js create mode 100644 apps/governance-e2e/src/integration/view/proposal.cy.ts rename apps/governance-e2e/src/integration/view/{pubkey-view.cy.js => pubkey-view.cy.ts} (71%) create mode 100644 apps/governance-e2e/src/integration/view/rewards.cy.ts rename apps/governance-e2e/src/integration/view/{token.cy.js => token.cy.ts} (96%) rename apps/governance-e2e/src/integration/view/{tranches.cy.js => tranches.cy.ts} (89%) delete mode 100644 apps/governance-e2e/src/integration/view/validators.cy.js create mode 100644 apps/governance-e2e/src/integration/view/validators.cy.ts rename apps/governance-e2e/src/integration/view/{vesting.cy.js => vesting.cy.ts} (82%) rename apps/governance-e2e/src/integration/view/{wallet-eth.cy.js => wallet-eth.cy.ts} (87%) rename apps/governance-e2e/src/integration/view/{wallet-vega.cy.js => wallet-vega.cy.ts} (91%) create mode 100644 apps/governance-e2e/src/integration/view/withdraw.cy.ts create mode 100644 apps/governance-e2e/src/support/common-interfaces.ts delete mode 100644 apps/governance-e2e/src/support/common.functions.js create mode 100644 apps/governance-e2e/src/support/common.functions.ts delete mode 100644 apps/governance-e2e/src/support/governance.functions.js create mode 100644 apps/governance-e2e/src/support/governance.functions.ts create mode 100644 apps/governance-e2e/src/support/index.d.ts rename apps/governance-e2e/src/support/{staking.functions.js => staking.functions.ts} (56%) rename apps/governance-e2e/src/support/{wallet-eth.functions.js => wallet-eth.functions.ts} (94%) delete mode 100644 apps/governance-e2e/src/support/wallet-teardown.functions.js create mode 100644 apps/governance-e2e/src/support/wallet-teardown.functions.ts delete mode 100644 apps/governance-e2e/src/support/wallet-vega.functions.js create mode 100644 apps/governance-e2e/src/support/wallet-vega.functions.ts create mode 100644 libs/cypress/src/lib/commands/associate-tokens-to-vega-wallet.ts create mode 100644 libs/cypress/src/lib/commands/vega-wallet-top-up-rewards-pool.ts diff --git a/apps/governance-e2e/src/integration/flow/proposal-details.cy.js b/apps/governance-e2e/src/integration/flow/proposal-details.cy.ts similarity index 56% rename from apps/governance-e2e/src/integration/flow/proposal-details.cy.js rename to apps/governance-e2e/src/integration/flow/proposal-details.cy.ts index a8b698328..5fbab97b7 100644 --- a/apps/governance-e2e/src/integration/flow/proposal-details.cy.js +++ b/apps/governance-e2e/src/integration/flow/proposal-details.cy.ts @@ -1,9 +1,28 @@ -import { associateTokenStartOfTests } from '../../support/common.functions'; import { + navigateTo, + waitForSpinner, + navigation, +} from '../../support/common.functions'; +import { + convertUnixTimestampToDateformat, createRawProposal, + createTenDigitUnixTimeStampForSpecifiedDays, + enterUniqueFreeFormProposalBody, generateFreeFormProposalTitle, + getGovernanceProposalDateFormatForSpecifiedDays, + getProposalIdFromList, + getProposalInformationFromTable, + getSubmittedProposalFromProposalList, + goToMakeNewProposal, governanceProposalType, -} from '../../support/governance.functions'; + voteForProposal, + waitForProposalSubmitted, + waitForProposalSync, +} from '../../../../governance-e2e/src/support/governance.functions'; +import { ensureSpecifiedUnstakedTokensAreAssociated } from '../../../../governance-e2e/src/support/staking.functions'; +import { ethereumWalletConnect } from '../../../../governance-e2e/src/support/wallet-eth.functions'; +import { vegaWalletSetSpecifiedApprovalAmount } from '../../../../governance-e2e/src/support/wallet-teardown.functions'; +import type { testFreeformProposal } from '../../support/common-interfaces'; const proposalVoteProgressForPercentage = '[data-testid="vote-progress-indicator-percentage-for"]'; @@ -25,24 +44,23 @@ describe( function () { before('connect wallets and set approval limit', function () { cy.visit('/'); - cy.vega_wallet_set_specified_approval_amount('1000'); - associateTokenStartOfTests(); + vegaWalletSetSpecifiedApprovalAmount('1000'); }); beforeEach('visit proposals tab', function () { cy.reload(); - cy.wait_for_spinner(); + waitForSpinner(); cy.connectVegaWallet(); - cy.ethereum_wallet_connect(); - cy.ensure_specified_unstaked_tokens_are_associated(1); - cy.navigate_to_page_if_not_already_loaded('proposals'); + ethereumWalletConnect(); + ensureSpecifiedUnstakedTokensAreAssociated('1'); + navigateTo(navigation.proposals); }); // 3001-VOTE-055 it('Newly created raw proposal details - shows proposal title and full description', function () { createRawProposal(); - cy.get('@rawProposal').then((rawProposal) => { - cy.get_proposal_id_from_list(rawProposal.rationale.title); + cy.get('@rawProposal').then((rawProposal) => { + getProposalIdFromList(rawProposal.rationale.title); cy.get('@proposalIdText').then((proposalId) => { cy.get(openProposals).within(() => { cy.get(`#${proposalId}`).within(() => { @@ -69,30 +87,26 @@ describe( it('Newly created freeform proposal details - shows proposed and closing dates', function () { const closingVoteHrs = '72'; const proposalTitle = generateFreeFormProposalTitle(); + const proposalTimeStamp = createTenDigitUnixTimeStampForSpecifiedDays(3); - cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); - cy.create_ten_digit_unix_timestamp_for_specified_days('3').then( - (closingDateTimestamp) => { - cy.enter_unique_freeform_proposal_body(closingVoteHrs, proposalTitle); - - cy.wait_for_proposal_submitted(); - cy.wait_for_proposal_sync(); - cy.navigate_to('proposals'); - cy.get_submitted_proposal_from_proposal_list(proposalTitle).within( - () => cy.get(viewProposalButton).click() - ); - cy.convert_unix_timestamp_to_governance_data_table_date_format( - closingDateTimestamp - ).then((closingDate) => { - cy.get_proposal_information_from_table('Closes on') - .contains(closingDate) - .should('be.visible'); - }); + goToMakeNewProposal(governanceProposalType.FREEFORM); + enterUniqueFreeFormProposalBody(closingVoteHrs, proposalTitle); + waitForProposalSubmitted(); + waitForProposalSync(); + navigateTo(navigation.proposals); + getSubmittedProposalFromProposalList(proposalTitle).within(() => + cy.get(viewProposalButton).click() + ); + convertUnixTimestampToDateformat(proposalTimeStamp).then( + (closingDate) => { + getProposalInformationFromTable('Closes on') + .contains(closingDate) + .should('be.visible'); } ); - cy.get_governance_proposal_date_format_for_specified_days('0').then( + getGovernanceProposalDateFormatForSpecifiedDays(0).then( (proposalDate) => { - cy.get_proposal_information_from_table('Proposed on') + getProposalInformationFromTable('Proposed on') .contains(proposalDate) .should('be.visible'); } @@ -104,25 +118,25 @@ describe( // 3001-VOTE-040 // 3001-VOTE-067 createRawProposal(); - cy.get('@rawProposal').then((rawProposal) => { - cy.get_submitted_proposal_from_proposal_list( + cy.get('@rawProposal').then((rawProposal) => { + getSubmittedProposalFromProposalList( rawProposal.rationale.title ).within(() => cy.get(viewProposalButton).click()); }); cy.contains('Participation: Not Met 0.00 0.00%(0.00% Required)').should( 'be.visible' ); - cy.get_proposal_information_from_table('Expected to pass') + getProposalInformationFromTable('Expected to pass') .contains('👎') .should('be.visible'); // 3001-VOTE-062 // 3001-VOTE-040 // 3001-VOTE-070 - cy.get_proposal_information_from_table('Token majority met') + getProposalInformationFromTable('Token majority met') .contains('👎') .should('be.visible'); // 3001-VOTE-068 - cy.get_proposal_information_from_table('Token participation met') + getProposalInformationFromTable('Token participation met') .contains('👎') .should('be.visible'); }); @@ -130,28 +144,27 @@ describe( // 3001-VOTE-080 3001-VOTE-090 3001-VOTE-069 3001-VOTE-072 3001-VOTE-073 it('Newly created proposal details - ability to vote for and against proposal - with minimum required tokens associated', function () { createRawProposal(); - cy.get('@rawProposal').then((rawProposal) => { - cy.get_submitted_proposal_from_proposal_list( + cy.get('@rawProposal').then((rawProposal) => { + getSubmittedProposalFromProposalList( rawProposal.rationale.title ).within(() => cy.get(viewProposalButton).click()); }); // 3001-VOTE-080 cy.getByTestId('vote-buttons').contains('against').should('be.visible'); cy.getByTestId('vote-buttons').contains('for').should('be.visible'); - cy.vote_for_proposal('for'); - cy.get_governance_proposal_date_format_for_specified_days( - '0', - 'shortMonth' - ).then((votedDate) => { - // 3001-VOTE-051 - // 3001-VOTE-093 - cy.contains('You voted:') - .siblings() - .contains('For') - .siblings() - .contains(votedDate) - .should('be.visible'); - }); + voteForProposal('for'); + getGovernanceProposalDateFormatForSpecifiedDays(0, 'shortMonth').then( + (votedDate) => { + // 3001-VOTE-051 + // 3001-VOTE-093 + cy.contains('You voted:') + .siblings() + .contains('For') + .siblings() + .contains(votedDate) + .should('be.visible'); + } + ); cy.get(proposalVoteProgressForPercentage) // 3001-VOTE-072 .contains('100.00%') .and('be.visible'); @@ -162,38 +175,38 @@ describe( cy.get(proposalVoteProgressAgainstTokens) .contains('0.00') .and('be.visible'); - cy.get_proposal_information_from_table('Tokens for proposal') - .should('have.text', parseFloat(1).toFixed(2)) + getProposalInformationFromTable('Tokens for proposal') + .should('have.text', (1).toFixed(2)) .and('be.visible'); - cy.get_proposal_information_from_table('Tokens against proposal') + getProposalInformationFromTable('Tokens against proposal') .should('have.text', '0.00') .and('be.visible'); // 3001-VOTE-061 - cy.get_proposal_information_from_table('Participation required') - .contains(0.001) + getProposalInformationFromTable('Participation required') + .contains('0.00%') .should('be.visible'); // 3001-VOTE-066 - cy.get_proposal_information_from_table('Majority Required') // 3001-VOTE-073 - .contains(`${parseFloat(100).toFixed(2)}%`) + getProposalInformationFromTable('Majority Required') // 3001-VOTE-073 + .contains(`${(66).toFixed(2)}%`) .should('be.visible'); - cy.get_proposal_information_from_table('Number of voting parties') + getProposalInformationFromTable('Number of voting parties') .should('have.text', '1') .and('be.visible'); cy.get(changeVoteButton).should('be.visible').click(); - cy.vote_for_proposal('for'); + voteForProposal('for'); // 3001-VOTE-064 - cy.get_proposal_information_from_table('Tokens for proposal') - .should('have.text', parseFloat(1).toFixed(2)) + getProposalInformationFromTable('Tokens for proposal') + .should('have.text', (1).toFixed(2)) .and('be.visible'); cy.get(changeVoteButton).should('be.visible').click(); - cy.vote_for_proposal('against'); + voteForProposal('against'); cy.get(proposalVoteProgressAgainstPercentage) .contains('100.00%') .and('be.visible'); - cy.get_proposal_information_from_table('Tokens against proposal') - .should('have.text', parseFloat(1).toFixed(2)) + getProposalInformationFromTable('Tokens against proposal') + .should('have.text', (1).toFixed(2)) .and('be.visible'); - cy.get_proposal_information_from_table('Number of voting parties') + getProposalInformationFromTable('Number of voting parties') .should('have.text', '1') .and('be.visible'); }); @@ -201,30 +214,31 @@ describe( // 3001-VOTE-042, 3001-VOTE-057, 3001-VOTE-058, 3001-VOTE-059, 3001-VOTE-060 it('Newly created proposal details - ability to increase associated tokens - by voting again after association', function () { createRawProposal(); - cy.get('@rawProposal').then((rawProposal) => { - cy.get_submitted_proposal_from_proposal_list( - rawProposal.rationale.title - ) + cy.get('@rawProposal').then((rawProposal) => { + getSubmittedProposalFromProposalList(rawProposal.rationale.title) .as('submittedProposal') .within(() => cy.get(viewProposalButton).click()); }); - cy.vote_for_proposal('for'); + voteForProposal('for'); // 3001-VOTE-079 cy.contains('You voted: For').should('be.visible'); cy.get(proposalVoteProgressForTokens).contains('1').and('be.visible'); - cy.get_proposal_information_from_table('Total Supply') + getProposalInformationFromTable('Total Supply') .invoke('text') .then((totalSupply) => { - let tokensRequiredToAchieveResult = parseFloat( - (totalSupply.replace(/,/g, '') * 0.001) / 100 + const tokensRequiredToAchieveResult = ( + (Number(totalSupply.replace(/,/g, '')) * 0.001) / + 100 ).toFixed(2); - cy.ensure_specified_unstaked_tokens_are_associated( + ensureSpecifiedUnstakedTokensAreAssociated( tokensRequiredToAchieveResult ); - cy.navigate_to_page_if_not_already_loaded('proposals'); - cy.get('@submittedProposal').within(() => - cy.get(viewProposalButton).click() - ); + navigateTo(navigation.proposals); + cy.get('@rawProposal').then((rawProposal) => { + getSubmittedProposalFromProposalList(rawProposal.rationale.title) + .as('submittedProposal') + .within(() => cy.get(viewProposalButton).click()); + }); cy.get(proposalVoteProgressForPercentage) .contains('100.00%') .and('be.visible'); @@ -233,38 +247,36 @@ describe( .and('be.visible'); // 3001-VOTE-065 cy.get(changeVoteButton).should('be.visible').click(); - cy.vote_for_proposal('for'); + voteForProposal('for'); cy.get(proposalVoteProgressForTokens) .contains(tokensRequiredToAchieveResult) .and('be.visible'); cy.get(proposalVoteProgressAgainstTokens) .contains('0.00') .and('be.visible'); - cy.get_proposal_information_from_table( - 'Total tokens voted percentage' - ) + getProposalInformationFromTable('Total tokens voted percentage') .should('have.text', '0.00%') .and('be.visible'); - cy.get_proposal_information_from_table('Tokens for proposal') + getProposalInformationFromTable('Tokens for proposal') .should('have.text', tokensRequiredToAchieveResult) .and('be.visible'); - cy.get_proposal_information_from_table('Tokens against proposal') + getProposalInformationFromTable('Tokens against proposal') .should('have.text', '0.00') .and('be.visible'); - cy.get_proposal_information_from_table('Number of voting parties') + getProposalInformationFromTable('Number of voting parties') .should('have.text', '1') .and('be.visible'); - cy.get_proposal_information_from_table('Expected to pass') + getProposalInformationFromTable('Expected to pass') .contains('👍') .should('be.visible'); // 3001-VOTE-062 - cy.get_proposal_information_from_table('Token majority met') + getProposalInformationFromTable('Token majority met') .contains('👍') .should('be.visible'); - cy.get_proposal_information_from_table('Token participation met') + getProposalInformationFromTable('Token participation met') .contains('👍') .should('be.visible'); - cy.get_proposal_information_from_table('Tokens for proposal') + getProposalInformationFromTable('Tokens for proposal') .contains(tokensRequiredToAchieveResult) .and('be.visible'); }); diff --git a/apps/governance-e2e/src/integration/flow/proposal-enacted.cy.js b/apps/governance-e2e/src/integration/flow/proposal-enacted.cy.ts similarity index 74% rename from apps/governance-e2e/src/integration/flow/proposal-enacted.cy.js rename to apps/governance-e2e/src/integration/flow/proposal-enacted.cy.ts index 0c3d494c3..3231319b6 100644 --- a/apps/governance-e2e/src/integration/flow/proposal-enacted.cy.js +++ b/apps/governance-e2e/src/integration/flow/proposal-enacted.cy.ts @@ -1,10 +1,21 @@ /// -import { associateTokenStartOfTests } from '../../support/governance.functions'; +import { + navigateTo, + navigation, + waitForSpinner, +} from '../../support/common.functions'; +import { + getProposalInformationFromTable, + voteForProposal, +} from '../../support/governance.functions'; import { createUpdateNetworkProposalTxBody, createFreeFormProposalTxBody, } from '../../support/proposal.functions'; +import { ensureSpecifiedUnstakedTokensAreAssociated } from '../../support/staking.functions'; +import { ethereumWalletConnect } from '../../support/wallet-eth.functions'; +import { vegaWalletSetSpecifiedApprovalAmount } from '../../support/wallet-teardown.functions'; const closedProposals = '[data-testid="closed-proposals"]'; const proposalStatus = '[data-testid="proposal-status"]'; @@ -21,20 +32,19 @@ context( function () { before('Connect wallets and set approval', function () { cy.visit('/'); - cy.vega_wallet_set_specified_approval_amount('1000'); - associateTokenStartOfTests(); + vegaWalletSetSpecifiedApprovalAmount('1000'); cy.connectVegaWallet(); - cy.ethereum_wallet_connect(); - cy.ensure_specified_unstaked_tokens_are_associated(1); + ethereumWalletConnect(); + ensureSpecifiedUnstakedTokensAreAssociated('1'); cy.clearLocalStorage(); }); beforeEach('visit proposals', function () { cy.reload(); - cy.wait_for_spinner(); + waitForSpinner(); cy.connectVegaWallet(); - cy.ethereum_wallet_connect(); - cy.navigate_to('proposals'); + ethereumWalletConnect(); + navigateTo(navigation.proposals); }); // 3001-VOTE-006 @@ -43,7 +53,7 @@ context( cy.createMarket(); cy.reload(); - cy.wait_for_spinner(); + waitForSpinner(); cy.get(closedProposals).within(() => { cy.contains(proposalTitle) .parentsUntil('[data-testid="proposals-list-item"]') @@ -53,7 +63,7 @@ context( }); }); cy.getByTestId('proposal-type').should('have.text', 'New market'); - cy.get_proposal_information_from_table('State') + getProposalInformationFromTable('State') .contains('Enacted') .and('be.visible'); cy.get(votesTable).within(() => { @@ -68,22 +78,22 @@ context( const proposalTx = createUpdateNetworkProposalTxBody(); cy.VegaWalletSubmitProposal(proposalTx); - cy.navigate_to('proposals'); + navigateTo(navigation.proposals); cy.reload(); - cy.wait_for_spinner(); + waitForSpinner(); cy.get(openProposals).within(() => { cy.contains(proposalTitle) .parentsUntil('[data-testid="proposals-list-item"]') .within(() => cy.get(viewProposalButton).click()); }); - cy.get_proposal_information_from_table('State') + getProposalInformationFromTable('State') .contains('Open') .and('be.visible'); - cy.vote_for_proposal('for'); - cy.get_proposal_information_from_table('State') // 3001-VOTE-047 + voteForProposal('for'); + getProposalInformationFromTable('State') // 3001-VOTE-047 .contains('Passed', proposalTimeout) .and('be.visible'); - cy.get_proposal_information_from_table('State') + getProposalInformationFromTable('State') .contains('Enacted', proposalTimeout) .and('be.visible'); cy.get(votesTable).within(() => { @@ -101,19 +111,19 @@ context( const proposalTx = createFreeFormProposalTxBody(); cy.VegaWalletSubmitProposal(proposalTx); - cy.navigate_to('proposals'); + navigateTo(navigation.proposals); cy.reload(); - cy.wait_for_spinner(); + waitForSpinner(); cy.get(openProposals).within(() => { cy.contains(proposalTitle) .parentsUntil('[data-testid="proposals-list-item"]') .within(() => cy.get(viewProposalButton).click()); }); - cy.get_proposal_information_from_table('State') + getProposalInformationFromTable('State') .contains('Open') .and('be.visible'); - cy.vote_for_proposal('for'); - cy.get_proposal_information_from_table('State') + voteForProposal('for'); + getProposalInformationFromTable('State') .contains('Enacted', proposalTimeout) .and('be.visible'); }); @@ -123,21 +133,21 @@ context( const proposalTitle = 'Add New free form proposal with short enactment'; const proposalTx = createFreeFormProposalTxBody(); cy.VegaWalletSubmitProposal(proposalTx); - cy.navigate_to('proposals'); + navigateTo(navigation.proposals); cy.reload(); - cy.wait_for_spinner(); + waitForSpinner(); cy.get(openProposals).within(() => { cy.contains(proposalTitle) .parentsUntil('[data-testid="proposals-list-item"]') .within(() => cy.get(viewProposalButton).click()); }); - cy.get_proposal_information_from_table('State') + getProposalInformationFromTable('State') .contains('Open') .and('be.visible'); - cy.get_proposal_information_from_table('State') // 3001-VOTE-047 + getProposalInformationFromTable('State') // 3001-VOTE-047 .contains('Declined', proposalTimeout) .and('be.visible'); - cy.get_proposal_information_from_table('Rejection reason') + getProposalInformationFromTable('Rejection reason') .contains('PROPOSAL_ERROR_PARTICIPATION_THRESHOLD_NOT_REACHED') .and('be.visible'); }); diff --git a/apps/governance-e2e/src/integration/flow/proposal-flow.cy.js b/apps/governance-e2e/src/integration/flow/proposal-flow.cy.ts similarity index 54% rename from apps/governance-e2e/src/integration/flow/proposal-flow.cy.js rename to apps/governance-e2e/src/integration/flow/proposal-flow.cy.ts index c5f2a90ab..5adb87c87 100644 --- a/apps/governance-e2e/src/integration/flow/proposal-flow.cy.js +++ b/apps/governance-e2e/src/integration/flow/proposal-flow.cy.ts @@ -1,17 +1,42 @@ /// import { createRawProposal, + createTenDigitUnixTimeStampForSpecifiedDays, + enterRawProposalBody, + enterUniqueFreeFormProposalBody, generateFreeFormProposalTitle, + getProposalInformationFromTable, + getSubmittedProposalFromProposalList, + goToMakeNewProposal, governanceProposalType, + voteForProposal, + waitForProposalSubmitted, + waitForProposalSync, } from '../../support/governance.functions'; -import { associateTokenStartOfTests } from '../../support/common.functions'; +import { + verifyUnstakedBalance, + waitForSpinner, + navigateTo, + navigation, +} from '../../support/common.functions'; +import { + clickOnValidatorFromList, + closeStakingDialog, + ensureSpecifiedUnstakedTokensAreAssociated, + stakingPageDisassociateTokens, + stakingValidatorPageAddStake, +} from '../../support/staking.functions'; +import { + vegaWalletSetSpecifiedApprovalAmount, + vegaWalletTeardown, +} from '../../support/wallet-teardown.functions'; +import { ethereumWalletConnect } from '../../support/wallet-eth.functions'; +import type { testFreeformProposal } from '../../support/common-interfaces'; -const vegaWalletUnstakedBalance = - '[data-testid="vega-wallet-balance-unstaked"]'; const vegaWalletStakedBalances = '[data-testid="vega-wallet-balance-staked-validators"]'; -const vegaWalletAssociatedBalance = '[data-testid="currency-value"]'; +const vegaWalletAssociatedBalance = '[data-testid="associated-amount"]'; const vegaWalletNameElement = '[data-testid="wallet-name"]'; const vegaWallet = '[data-testid="vega-wallet"]'; const connectToVegaWalletButton = '[data-testid="connect-to-vega-wallet-btn"]'; @@ -40,30 +65,31 @@ context( cy.visit('/'); cy.get_network_parameters().then((network_parameters) => { cy.wrap( - network_parameters['spam.protection.proposal.min.tokens'] / + Number(network_parameters['spam.protection.proposal.min.tokens']) / 1000000000000000000 ).as('minProposerBalance'); cy.wrap( - network_parameters['spam.protection.voting.min.tokens'] / + Number(network_parameters['spam.protection.voting.min.tokens']) / 1000000000000000000 ).as('minVoterBalance'); cy.wrap( - network_parameters['governance.proposal.freeform.requiredMajority'] * - 100 + Number( + network_parameters['governance.proposal.freeform.requiredMajority'] + ) * 100 ).as('requiredMajority'); }); - cy.vega_wallet_set_specified_approval_amount('1000'); - associateTokenStartOfTests(); + vegaWalletSetSpecifiedApprovalAmount('1000'); + cy.associateTokensToVegaWallet('1'); }); beforeEach('visit governance tab', function () { cy.reload(); - cy.wait_for_spinner(); + waitForSpinner(); cy.connectVegaWallet(); - cy.ethereum_wallet_connect(); - cy.ensure_specified_unstaked_tokens_are_associated(1); - cy.navigate_to_page_if_not_already_loaded('proposals'); + ethereumWalletConnect(); + ensureSpecifiedUnstakedTokensAreAssociated('1'); + navigateTo(navigation.proposals); }); it('Should be able to see that no proposals exist', function () { @@ -80,7 +106,7 @@ context( // 3002-PROP-003 it('Submit a proposal form - shows how many vega tokens are required to make a proposal', function () { // 3002-PROP-005 - cy.go_to_make_new_proposal(governanceProposalType.NEW_MARKET); + goToMakeNewProposal(governanceProposalType.NEW_MARKET); cy.contains( `You must have at least 1 VEGA associated to make a proposal` ).should('be.visible'); @@ -88,7 +114,7 @@ context( // 3002-PROP-011 it('Able to submit a valid freeform proposal - with minimum required tokens associated', function () { - cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); + goToMakeNewProposal(governanceProposalType.FREEFORM); cy.get(minVoteButton).should('be.visible'); // 3002-PROP-008 cy.get(maxVoteButton).should('be.visible'); cy.get(votingDate).should('not.be.empty'); @@ -96,40 +122,31 @@ context( 'contain.text', 'we add 2 minutes of extra time' ); - cy.enter_unique_freeform_proposal_body( - '50', - generateFreeFormProposalTitle() - ); + enterUniqueFreeFormProposalBody('50', generateFreeFormProposalTitle()); // 3002-PROP-012 // 3002-PROP-016 - cy.wait_for_proposal_submitted(); + waitForProposalSubmitted(); }); it('Able to submit a valid freeform proposal - with minimum required tokens associated - but also staked', function () { - cy.ensure_specified_unstaked_tokens_are_associated('2'); - cy.get(vegaWalletUnstakedBalance, txTimeout).should('contain', '2'); - cy.navigate_to('validators'); - cy.click_on_validator_from_list(0); - cy.staking_validator_page_add_stake('2'); - cy.close_staking_dialog(); + ensureSpecifiedUnstakedTokensAreAssociated('2'); + verifyUnstakedBalance(2); + navigateTo(navigation.validators); + clickOnValidatorFromList(0); + stakingValidatorPageAddStake('2'); + closeStakingDialog(); cy.get(vegaWalletStakedBalances, txTimeout).should('contain', '2'); - cy.navigate_to('proposals'); - cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); - cy.enter_unique_freeform_proposal_body( - '50', - generateFreeFormProposalTitle() - ); - cy.wait_for_proposal_submitted(); + navigateTo(navigation.proposals); + goToMakeNewProposal(governanceProposalType.FREEFORM); + enterUniqueFreeFormProposalBody('50', generateFreeFormProposalTitle()); + waitForProposalSubmitted(); }); it('Creating a proposal - proposal rejected - when closing time sooner than system default', function () { - cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); - cy.enter_unique_freeform_proposal_body( - '0.1', - generateFreeFormProposalTitle() - ); + goToMakeNewProposal(governanceProposalType.FREEFORM); + enterUniqueFreeFormProposalBody('0.1', generateFreeFormProposalTitle()); cy.contains('Awaiting network confirmation', epochTimeout).should( 'not.exist' ); @@ -139,8 +156,8 @@ context( }); it('Creating a proposal - proposal rejected - when closing time later than system default', function () { - cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); - cy.enter_unique_freeform_proposal_body( + goToMakeNewProposal(governanceProposalType.FREEFORM); + enterUniqueFreeFormProposalBody( '100000', generateFreeFormProposalTitle() ); @@ -154,22 +171,18 @@ context( // 3001-VOTE-006 it('Creating a proposal - proposal rejected - able to access rejected proposals', function () { - cy.go_to_make_new_proposal(governanceProposalType.RAW); - cy.create_ten_digit_unix_timestamp_for_specified_days('1000').then( - (closingDateTimestamp) => { - cy.enter_raw_proposal_body(closingDateTimestamp).as('rawProposal'); - } - ); + goToMakeNewProposal(governanceProposalType.RAW); + enterRawProposalBody(createTenDigitUnixTimeStampForSpecifiedDays(1000)); cy.contains('Awaiting network confirmation', epochTimeout).should( 'be.visible' ); cy.contains('Proposal rejected', proposalTimeout).should('be.visible'); cy.get(dialogCloseButton).click(); - cy.wait_for_proposal_sync(); - cy.navigate_to('proposals'); + waitForProposalSync(); + navigateTo(navigation.proposals); cy.get(rejectProposalsLink).click(); - cy.get('@rawProposal').then((rawProposal) => { - cy.get_submitted_proposal_from_proposal_list( + cy.get('@rawProposal').then((rawProposal) => { + getSubmittedProposalFromProposalList( rawProposal.rationale.title ).within(() => { cy.contains('Rejected').should('be.visible'); @@ -177,78 +190,67 @@ context( cy.get(viewProposalButton).click(); }); }); - cy.get_proposal_information_from_table('State') + getProposalInformationFromTable('State') .contains('Rejected') .and('be.visible'); - cy.get_proposal_information_from_table('Rejection reason') + getProposalInformationFromTable('Rejection reason') .contains('PROPOSAL_ERROR_CLOSE_TIME_TOO_LATE') .and('be.visible'); - cy.get_proposal_information_from_table('Error details') + getProposalInformationFromTable('Error details') .contains('proposal closing time too late') .and('be.visible'); }); // 0005-ETXN-004 it('Unable to create a proposal - when no tokens are associated', function () { - cy.vega_wallet_teardown(); + const errorMsg = + 'Network error: the network blocked the transaction through the spam protection: party has insufficient associated governance tokens in their staking account to submit proposal request (ABCI code 89)'; + vegaWalletTeardown(); cy.get(vegaWalletAssociatedBalance, txTimeout).contains( '0.00', txTimeout ); - cy.go_to_make_new_proposal(governanceProposalType.RAW); - cy.create_ten_digit_unix_timestamp_for_specified_days('8').then( - (closingDateTimestamp) => { - cy.enter_raw_proposal_body(closingDateTimestamp).as; - } - ); + goToMakeNewProposal(governanceProposalType.RAW); + enterRawProposalBody(createTenDigitUnixTimeStampForSpecifiedDays(8)); cy.contains('Transaction failed', proposalTimeout).should('be.visible'); - cy.get(feedbackError).should( - 'have.text', - 'Network error: the network blocked the transaction through the spam protection' - ); + cy.get(feedbackError).should('have.text', errorMsg); cy.get(dialogCloseButton).click(); }); // 3002-PROP-009 it('Unable to create a proposal - when some but not enough tokens are associated', function () { - cy.ensure_specified_unstaked_tokens_are_associated(0.000001); - cy.go_to_make_new_proposal(governanceProposalType.RAW); - cy.create_ten_digit_unix_timestamp_for_specified_days('8').then( - (closingDateTimestamp) => { - cy.enter_raw_proposal_body(closingDateTimestamp); - } - ); + const errorMsg = + 'Network error: the network blocked the transaction through the spam protection: party has insufficient associated governance tokens in their staking account to submit proposal request (ABCI code 89)'; + + ensureSpecifiedUnstakedTokensAreAssociated('0.000001'); + goToMakeNewProposal(governanceProposalType.RAW); + enterRawProposalBody(createTenDigitUnixTimeStampForSpecifiedDays(8)); cy.contains('Transaction failed', proposalTimeout).should('be.visible'); - cy.get(feedbackError).should( - 'have.text', - 'Network error: the network blocked the transaction through the spam protection' - ); + cy.get(feedbackError).should('have.text', errorMsg); cy.get(dialogCloseButton).click(); }); it('Unable to create a freeform proposal - when json parent section contains unexpected field', function () { + const errorMsg = + 'Invalid params: the transaction does not use a valid Vega command: unknown field unexpected" in vega.commands.v1.ProposalSubmission'; + // 3001-VOTE-038 3002-PROP-013 3002-PROP-014 - cy.go_to_make_new_proposal(governanceProposalType.RAW); - cy.create_ten_digit_unix_timestamp_for_specified_days('8').then( - (closingDateTimestamp) => { - cy.fixture('/proposals/raw.json').then((freeformProposal) => { - freeformProposal.terms.closingTimestamp = closingDateTimestamp; - freeformProposal.unexpected = `i shouldn't be here`; - let proposalPayload = JSON.stringify(freeformProposal); - cy.get(rawProposalData).type(proposalPayload, { - parseSpecialCharSequences: false, - delay: 2, - }); - }); - } - ); + goToMakeNewProposal(governanceProposalType.RAW); + + cy.fixture('/proposals/raw.json').then((freeformProposal) => { + freeformProposal.terms.closingTimestamp = + createTenDigitUnixTimeStampForSpecifiedDays(8); + freeformProposal.unexpected = `i shouldn't be here`; + const proposalPayload = JSON.stringify(freeformProposal); + cy.get(rawProposalData).type(proposalPayload, { + parseSpecialCharSequences: false, + delay: 2, + }); + }); cy.get(newProposalSubmitButton).should('be.visible').click(); cy.contains('Transaction failed', proposalTimeout).should('be.visible'); - cy.get(feedbackError).should( - 'have.text', - 'Invalid params: the transaction is malformed' - ); + cy.get(feedbackError).should('have.text', errorMsg); cy.get(dialogCloseButton).click(); cy.get(rawProposalData) .invoke('val') @@ -257,71 +259,64 @@ context( it('Unable to create a freeform proposal - when json terms section contains unexpected field', function () { // 3001-VOTE-038 - cy.go_to_make_new_proposal(governanceProposalType.RAW); - cy.create_ten_digit_unix_timestamp_for_specified_days('8').then( - (closingDateTimestamp) => { - cy.fixture('/proposals/raw.json').then((rawProposal) => { - rawProposal.terms.closingTimestamp = closingDateTimestamp; - rawProposal.terms.unexpectedField = `i shouldn't be here`; - let proposalPayload = JSON.stringify(rawProposal); + const errorMsg = + 'Invalid params: the transaction does not use a valid Vega command: unknown field "unexpectedField" in vega.ProposalTerms'; - cy.get(rawProposalData).type(proposalPayload, { - parseSpecialCharSequences: false, - delay: 2, - }); - }); - } - ); + goToMakeNewProposal(governanceProposalType.RAW); + + cy.fixture('/proposals/raw.json').then((rawProposal) => { + rawProposal.terms.closingTimestamp = + createTenDigitUnixTimeStampForSpecifiedDays(8); + rawProposal.terms.unexpectedField = `i shouldn't be here`; + const proposalPayload = JSON.stringify(rawProposal); + + cy.get(rawProposalData).type(proposalPayload, { + parseSpecialCharSequences: false, + delay: 2, + }); + }); cy.get(newProposalSubmitButton).should('be.visible').click(); cy.contains('Transaction failed', proposalTimeout).should('be.visible'); - cy.get(feedbackError).should( - 'have.text', - 'Invalid params: the transaction is malformed' - ); + cy.get(feedbackError).should('have.text', errorMsg); cy.get(dialogCloseButton).click(); }); // 1005-PROP-009 - it.skip( - 'Unable to vote on a freeform proposal - when some but not enough vega associated', - { tags: '@smoke' }, - function () { - const proposalTitle = generateFreeFormProposalTitle(); + it('Unable to vote on a freeform proposal - when some but not enough vega associated', function () { + const proposalTitle = generateFreeFormProposalTitle(); - cy.ensure_specified_unstaked_tokens_are_associated(1); - cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); - cy.enter_unique_freeform_proposal_body('50', proposalTitle); - cy.wait_for_proposal_submitted(); - cy.staking_page_disassociate_tokens('0.0001'); - cy.get(vegaWallet).within(() => { - cy.get(vegaWalletAssociatedBalance).should('have.length', 1); - cy.get(vegaWalletAssociatedBalance, txTimeout).should( - 'contain', - '0.9999' - ); - }); - cy.navigate_to('proposals'); - cy.get_submitted_proposal_from_proposal_list(proposalTitle).within(() => - cy.get(viewProposalButton).click() + ensureSpecifiedUnstakedTokensAreAssociated('1'); + goToMakeNewProposal(governanceProposalType.FREEFORM); + enterUniqueFreeFormProposalBody('50', proposalTitle); + waitForProposalSubmitted(); + stakingPageDisassociateTokens('0.0001'); + cy.get(vegaWallet).within(() => { + cy.get(vegaWalletAssociatedBalance, txTimeout).should( + 'contain', + '0.9999' ); - cy.contains('Vote breakdown').should('be.visible', { - timeout: 10000, - }); - cy.get(voteButtons).should('not.exist'); - cy.getByTestId('min-proposal-requirements').should( - 'have.text', - `You must have at least ${this.minVoterBalance} VEGA associated to vote on this proposal` - ); - } - ); + }); + navigateTo(navigation.proposals); + getSubmittedProposalFromProposalList(proposalTitle).within(() => + cy.get(viewProposalButton).click() + ); + cy.contains('Vote breakdown').should('be.visible', { + timeout: 10000, + }); + cy.get(voteButtons).should('not.exist'); + cy.getByTestId('min-proposal-requirements').should( + 'have.text', + `You must have at least ${this.minVoterBalance} VEGA associated to vote on this proposal` + ); + }); it('Unable to vote on a proposal - when vega wallet disconnected - option to connect from within', function () { createRawProposal(); cy.get('[data-testid="manage-vega-wallet"]').click(); cy.get('[data-testid="disconnect"]').click(); - cy.get('@rawProposal').then((rawProposal) => { - cy.get_submitted_proposal_from_proposal_list( + cy.get('@rawProposal').then((rawProposal) => { + getSubmittedProposalFromProposalList( rawProposal.rationale.title ).within(() => cy.get(viewProposalButton).click()); }); @@ -339,7 +334,7 @@ context( '1.00', txTimeout ); - cy.vote_for_proposal('against'); + voteForProposal('against'); // 3001-VOTE-079 cy.contains('You voted: Against').should('be.visible'); }); diff --git a/apps/governance-e2e/src/integration/flow/proposal-forms.cy.js b/apps/governance-e2e/src/integration/flow/proposal-forms.cy.ts similarity index 83% rename from apps/governance-e2e/src/integration/flow/proposal-forms.cy.js rename to apps/governance-e2e/src/integration/flow/proposal-forms.cy.ts index 2059fa77e..1fdee286a 100644 --- a/apps/governance-e2e/src/integration/flow/proposal-forms.cy.js +++ b/apps/governance-e2e/src/integration/flow/proposal-forms.cy.ts @@ -1,3 +1,22 @@ +import { + navigateTo, + navigation, + waitForSpinner, +} from '../../support/common.functions'; +import { + getProposalInformationFromTable, + goToMakeNewProposal, + voteForProposal, + waitForProposalSubmitted, +} from '../../support/governance.functions'; +import { ensureSpecifiedUnstakedTokensAreAssociated } from '../../support/staking.functions'; +import { ethereumWalletConnect } from '../../support/wallet-eth.functions'; +import { + vegaWalletSetSpecifiedApprovalAmount, + vegaWalletTeardown, +} from '../../support/wallet-teardown.functions'; +import { vegaWalletFaucetAssetsWithoutCheck } from '../../support/wallet-vega.functions'; + const proposalListItem = '[data-testid="proposals-list-item"]'; const openProposals = '[data-testid="open-proposals"]'; const proposalType = '[data-testid="proposal-type"]'; @@ -51,20 +70,20 @@ context( before('connect wallets and set approval limit', function () { cy.createMarket(); cy.visit('/'); - cy.vega_wallet_set_specified_approval_amount('1000'); + vegaWalletSetSpecifiedApprovalAmount('1000'); }); beforeEach('visit governance tab', function () { cy.reload(); - cy.wait_for_spinner(); + waitForSpinner(); cy.connectVegaWallet(); - cy.ethereum_wallet_connect(); - cy.ensure_specified_unstaked_tokens_are_associated('1'); - cy.navigate_to('proposals'); + ethereumWalletConnect(); + ensureSpecifiedUnstakedTokensAreAssociated('1'); + navigateTo(navigation.proposals); }); it('Able to submit valid update network parameter proposal', function () { - cy.go_to_make_new_proposal(governanceProposalType.NETWORK_PARAMETER); + goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER); // 3002-PROP-006 cy.get(newProposalTitle).type('Test update network parameter proposal'); // 3002-PROP-007 @@ -78,12 +97,12 @@ context( cy.get(currentParameterValue).should('have.value', '2s'); cy.get(newProposedParameterValue).type('5s'); // 3007-PNEC-003 cy.get(newProposalSubmitButton).should('be.visible').click(); - cy.wait_for_proposal_submitted(); + waitForProposalSubmitted(); }); it('Unable to submit network parameter with missing/invalid fields', function () { - cy.navigate_to_page_if_not_already_loaded('proposals'); - cy.go_to_make_new_proposal(governanceProposalType.NETWORK_PARAMETER); + navigateTo(navigation.proposals); + goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER); cy.get(newProposalSubmitButton).should('be.visible').click(); cy.get(inputError).should('have.length', 3); cy.get(newProposalTitle).type( @@ -108,7 +127,7 @@ context( it('Able to download network param proposal json', function () { const downloadFolder = './cypress/downloads/'; - cy.go_to_make_new_proposal(governanceProposalType.NETWORK_PARAMETER); + goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER); cy.log('Download proposal file'); cy.get(proposalDownloadBtn) .should('be.visible') @@ -156,8 +175,8 @@ context( }); it('Unable to submit network parameter proposal with vote deadline above enactment deadline', function () { - cy.navigate_to_page_if_not_already_loaded('proposals'); - cy.go_to_make_new_proposal(governanceProposalType.NETWORK_PARAMETER); + navigateTo(navigation.proposals); + goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER); cy.get(newProposalTitle).type('Test update network parameter proposal'); cy.get(newProposalDescription).type('invalid deadlines'); cy.get(proposalParameterSelect).select( @@ -182,29 +201,32 @@ context( // 3003-PMAN-001 it('Able to submit valid new market proposal', function () { - cy.go_to_make_new_proposal(governanceProposalType.NEW_MARKET); + goToMakeNewProposal(governanceProposalType.NEW_MARKET); cy.get(newProposalTitle).type('Test new market proposal'); cy.get(newProposalDescription).type('E2E test for proposals'); cy.fixture('/proposals/new-market').then((newMarketProposal) => { - let newMarketPayload = JSON.stringify(newMarketProposal); + const newMarketPayload = JSON.stringify(newMarketProposal); cy.get(newProposalTerms).type(newMarketPayload, { parseSpecialCharSequences: false, delay: 2, }); }); cy.get(newProposalSubmitButton).should('be.visible').click(); - cy.wait_for_proposal_submitted(); + waitForProposalSubmitted(); }); it('Unable to submit new market proposal with missing/invalid fields', function () { - cy.go_to_make_new_proposal(governanceProposalType.NEW_MARKET); + const errorMsg = + 'Invalid params: the transaction is not a valid Vega command: unknown field "filters" in vega.DataSourceDefinition'; + + goToMakeNewProposal(governanceProposalType.NEW_MARKET); cy.get(newProposalSubmitButton).should('be.visible').click(); cy.get(inputError).should('have.length', 3); cy.get(newProposalTitle).type('Test new market proposal'); cy.get(newProposalDescription).type('E2E test for proposals'); cy.fixture('/proposals/new-market').then((newMarketProposal) => { newMarketProposal.invalid = 'I am an invalid field'; - let newMarketPayload = JSON.stringify(newMarketProposal); + const newMarketPayload = JSON.stringify(newMarketProposal); cy.get(newProposalTerms).type(newMarketPayload, { parseSpecialCharSequences: false, delay: 2, @@ -212,21 +234,18 @@ context( }); cy.get(newProposalSubmitButton).should('be.visible').click(); cy.contains('Transaction failed', proposalTimeout).should('be.visible'); - cy.get(feedbackError).should( - 'have.text', - 'Invalid params: the transaction is not a valid Vega command: unknown field "invalid" in vega.NewMarket' - ); + cy.get(feedbackError).should('have.text', errorMsg); }); // Will fail if run after 'Able to submit update market proposal and vote for proposal' // 3002-PROP-022 it('Unable to submit update market proposal without equity-like share in the market', function () { - cy.go_to_make_new_proposal(governanceProposalType.UPDATE_MARKET); + goToMakeNewProposal(governanceProposalType.UPDATE_MARKET); cy.get(newProposalTitle).type('Test update market proposal - rejected'); cy.get(newProposalDescription).type('E2E test for proposals'); cy.get(proposalMarketSelect).select('Test market 1'); cy.fixture('/proposals/update-market').then((updateMarketProposal) => { - let newUpdateMarketProposal = JSON.stringify(updateMarketProposal); + const newUpdateMarketProposal = JSON.stringify(updateMarketProposal); cy.get(newProposalTerms).type(newUpdateMarketProposal, { parseSpecialCharSequences: false, delay: 2, @@ -237,23 +256,23 @@ context( cy.getByTestId('dialog-content') .find('p') .should('have.text', 'PROPOSAL_ERROR_INSUFFICIENT_EQUITY_LIKE_SHARE'); - cy.ensure_specified_unstaked_tokens_are_associated('1'); + ensureSpecifiedUnstakedTokensAreAssociated('1'); }); // 3002-PROP-020 it('Unable to submit update market proposal without minimum amount of tokens', function () { - cy.vega_wallet_teardown(); - cy.vega_wallet_faucet_assets_without_check( + vegaWalletTeardown(); + vegaWalletFaucetAssetsWithoutCheck( 'fUSDC', '1000000', vegaWalletPublicKey ); - cy.go_to_make_new_proposal(governanceProposalType.UPDATE_MARKET); + goToMakeNewProposal(governanceProposalType.UPDATE_MARKET); cy.get(newProposalTitle).type('Test update market proposal - rejected'); cy.get(newProposalDescription).type('E2E test for proposals'); cy.get(proposalMarketSelect).select('Test market 1'); cy.fixture('/proposals/update-market').then((updateMarketProposal) => { - let newUpdateMarketProposal = JSON.stringify(updateMarketProposal); + const newUpdateMarketProposal = JSON.stringify(updateMarketProposal); cy.get(newProposalTerms).type(newUpdateMarketProposal, { parseSpecialCharSequences: false, delay: 2, @@ -269,12 +288,12 @@ context( // 3001-VOTE-092 it('Able to submit update market proposal and vote for proposal', function () { - cy.vega_wallet_faucet_assets_without_check( + vegaWalletFaucetAssetsWithoutCheck( 'fUSDC', '1000000', vegaWalletPublicKey ); - cy.go_to_make_new_proposal(governanceProposalType.UPDATE_MARKET); + goToMakeNewProposal(governanceProposalType.UPDATE_MARKET); cy.get(newProposalTitle).type('Test update market proposal'); cy.get(newProposalDescription).type('E2E test for proposals'); cy.get(proposalMarketSelect).select('Test market 1'); @@ -285,20 +304,20 @@ context( cy.get('dd').eq(2).invoke('text').as('EnactedMarketId'); }); cy.get('@EnactedMarketId').then((marketId) => { - cy.VegaWalletSubmitLiquidityProvision(marketId, '1'); + cy.VegaWalletSubmitLiquidityProvision(String(marketId), '1'); }); cy.fixture('/proposals/update-market').then((updateMarketProposal) => { - let newUpdateMarketProposal = JSON.stringify(updateMarketProposal); + const newUpdateMarketProposal = JSON.stringify(updateMarketProposal); cy.get(newProposalTerms).type(newUpdateMarketProposal, { parseSpecialCharSequences: false, delay: 2, }); }); cy.get(newProposalSubmitButton).should('be.visible').click(); - cy.wait_for_proposal_submitted(); - cy.navigate_to('proposals'); + waitForProposalSubmitted(); + navigateTo(navigation.proposals); cy.get('@EnactedMarketId').then((marketId) => { - cy.contains(marketId) + cy.contains(String(marketId)) .parentsUntil(proposalListItem) .within(() => { cy.getByTestId(viewProposalBtn).click(); @@ -312,7 +331,7 @@ context( 'contain.text', 'Currently expected to fail' ); - cy.vote_for_proposal('for'); + voteForProposal('for'); cy.getByTestId(liquidityVoteStatus).should( 'contain.text', 'Currently expected to pass' @@ -321,18 +340,18 @@ context( 'contain.text', 'Currently expected to pass' ); - cy.get_proposal_information_from_table('Expected to pass') + getProposalInformationFromTable('Expected to pass') .contains('👍 by Token vote') .should('be.visible'); }); // 3001-VOTE-026 3001-VOTE-027 3001-VOTE-028 3001-VOTE-095 3001-VOTE-096 3005-PASN-001 it('Able to submit new asset proposal using min deadlines', function () { - cy.go_to_make_new_proposal(governanceProposalType.NEW_ASSET); + goToMakeNewProposal(governanceProposalType.NEW_ASSET); cy.get(newProposalTitle).type('Test new asset proposal'); cy.get(newProposalDescription).type('E2E test for proposals'); cy.fixture('/proposals/new-asset').then((newAssetProposal) => { - let newAssetPayload = JSON.stringify(newAssetProposal); + const newAssetPayload = JSON.stringify(newAssetProposal); cy.get(newProposalTerms).type(newAssetPayload, { parseSpecialCharSequences: false, delay: 2, @@ -361,7 +380,7 @@ context( }); it('Unable to submit new asset proposal with missing/invalid fields', function () { - cy.go_to_make_new_proposal(governanceProposalType.NEW_ASSET); + goToMakeNewProposal(governanceProposalType.NEW_ASSET); cy.get(newProposalSubmitButton).should('be.visible').click(); cy.get(inputError).should('have.length', 3); cy.get(newProposalTitle).type('Invalid new asset proposal'); @@ -377,13 +396,13 @@ context( const assetId = 'ebcd94151ae1f0d39a4bde3b21a9c7ae81a80ea4352fb075a92e07608d9c953d'; - cy.go_to_make_new_proposal(governanceProposalType.UPDATE_ASSET); + goToMakeNewProposal(governanceProposalType.UPDATE_ASSET); enterUpdateAssetProposalDetails(); cy.get(minVoteDeadline).click(); cy.get(minEnactDeadline).click(); cy.get(newProposalSubmitButton).should('be.visible').click(); - cy.wait_for_proposal_submitted(); - cy.navigate_to('proposals'); + waitForProposalSubmitted(); + navigateTo(navigation.proposals); cy.get(openProposals).within(() => { cy.get(proposalType) .contains('Update asset') @@ -393,22 +412,22 @@ context( cy.getByTestId(viewProposalBtn).click(); }); }); - cy.get_proposal_information_from_table('Proposed enactment') // 3001-VOTE-044 + getProposalInformationFromTable('Proposed enactment') // 3001-VOTE-044 .invoke('text') .should('not.be.empty'); }); it('Able to submit update asset proposal using max deadline', function () { - cy.go_to_make_new_proposal(governanceProposalType.UPDATE_ASSET); + goToMakeNewProposal(governanceProposalType.UPDATE_ASSET); enterUpdateAssetProposalDetails(); cy.get(maxVoteDeadline).click(); cy.get(maxEnactDeadline).click(); cy.get(newProposalSubmitButton).should('be.visible').click(); - cy.wait_for_proposal_submitted(); + waitForProposalSubmitted(); }); it('Unable to submit edit asset proposal with missing/invalid fields', function () { - cy.go_to_make_new_proposal(governanceProposalType.UPDATE_ASSET); + goToMakeNewProposal(governanceProposalType.UPDATE_ASSET); cy.get(newProposalSubmitButton).should('be.visible').click(); cy.get(inputError).should('have.length', 3); }); @@ -428,7 +447,7 @@ context( cy.get(newProposalTitle).type('Test update asset proposal'); cy.get(newProposalDescription).type('E2E test for proposals'); cy.fixture('/proposals/update-asset').then((newAssetProposal) => { - let newAssetPayload = JSON.stringify(newAssetProposal); + const newAssetPayload = JSON.stringify(newAssetProposal); cy.get(newProposalTerms).type(newAssetPayload, { parseSpecialCharSequences: false, delay: 2, diff --git a/apps/governance-e2e/src/integration/flow/proposal-list.cy.js b/apps/governance-e2e/src/integration/flow/proposal-list.cy.ts similarity index 54% rename from apps/governance-e2e/src/integration/flow/proposal-list.cy.js rename to apps/governance-e2e/src/integration/flow/proposal-list.cy.ts index 250105b56..c7d6e273d 100644 --- a/apps/governance-e2e/src/integration/flow/proposal-list.cy.js +++ b/apps/governance-e2e/src/integration/flow/proposal-list.cy.ts @@ -1,9 +1,28 @@ +import type { testFreeformProposal } from '../../support/common-interfaces'; +import { + navigateTo, + navigation, + waitForSpinner, +} from '../../support/common.functions'; import { createFreeformProposal, createRawProposal, + createTenDigitUnixTimeStampForSpecifiedDays, + enterRawProposalBody, generateFreeFormProposalTitle, + getProposalIdFromList, + getProposalInformationFromTable, + getSortOrderOfSuppliedArray, + getSubmittedProposalFromProposalList, + goToMakeNewProposal, governanceProposalType, + voteForProposal, + waitForProposalSubmitted, + waitForProposalSync, } from '../../support/governance.functions'; +import { ensureSpecifiedUnstakedTokensAreAssociated } from '../../support/staking.functions'; +import { ethereumWalletConnect } from '../../support/wallet-eth.functions'; +import { vegaWalletSetSpecifiedApprovalAmount } from '../../support/wallet-teardown.functions'; const proposalDetailsTitle = '[data-testid="proposal-title"]'; const openProposals = '[data-testid="open-proposals"]'; @@ -12,17 +31,17 @@ const viewProposalButton = '[data-testid="view-proposal-btn"]'; describe('Governance flow for proposal list', { tags: '@slow' }, function () { before('connect wallets and set approval limit', function () { - cy.vega_wallet_set_specified_approval_amount('1000'); + vegaWalletSetSpecifiedApprovalAmount('1000'); cy.visit('/'); }); beforeEach('visit proposals tab', function () { cy.reload(); - cy.wait_for_spinner(); + waitForSpinner(); cy.connectVegaWallet(); - cy.ethereum_wallet_connect(); - cy.ensure_specified_unstaked_tokens_are_associated(1); - cy.navigate_to_page_if_not_already_loaded('proposals'); + ethereumWalletConnect(); + ensureSpecifiedUnstakedTokensAreAssociated('1'); + navigateTo(navigation.proposals); }); it('Newly created proposals list - proposals closest to closing date appear higher in list', function () { @@ -30,32 +49,30 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () { const maxCloseDays = 3; // 3001-VOTE-005 - let proposalDays = [ + const proposalDays = [ minCloseDays + 1, maxCloseDays, minCloseDays + 3, minCloseDays + 2, ]; - for (var index = 0; index < proposalDays.length; index++) { - cy.go_to_make_new_proposal(governanceProposalType.RAW); - cy.create_ten_digit_unix_timestamp_for_specified_days( - proposalDays[index] - ).then((closingDateTimestamp) => { - cy.enter_raw_proposal_body(closingDateTimestamp); - }); - cy.wait_for_proposal_submitted(); - cy.wait_for_proposal_sync(); + for (let index = 0; index < proposalDays.length; index++) { + goToMakeNewProposal(governanceProposalType.RAW); + enterRawProposalBody( + createTenDigitUnixTimeStampForSpecifiedDays(proposalDays[index]) + ); + waitForProposalSubmitted(); + waitForProposalSync(); } - let arrayOfProposals = []; + const arrayOfProposals: string[] = []; - cy.navigate_to('proposals'); + navigateTo(navigation.proposals); cy.get(proposalDetailsTitle) .each((proposalTitleElement) => { arrayOfProposals.push(proposalTitleElement.text()); }) .then(() => { - cy.get_sort_order_of_supplied_array(arrayOfProposals).should( + cy.wrap(getSortOrderOfSuppliedArray(arrayOfProposals)).should( 'equal', 'descending' ); @@ -67,7 +84,7 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () { const proposalTitle = generateFreeFormProposalTitle(); createFreeformProposal(proposalTitle); - cy.get_proposal_id_from_list(proposalTitle); + getProposalIdFromList(proposalTitle); cy.get('@proposalIdText').then((proposalId) => { cy.get('[data-testid="set-proposals-filter-visible"]').click(); cy.get('[data-testid="filter-input"]').type(proposerId); @@ -77,8 +94,8 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () { it('Newly created proposals list - shows title and portion of summary', function () { createRawProposal(this.minProposerBalance); // 3001-VOTE-052 - cy.get('@rawProposal').then((rawProposal) => { - cy.get_proposal_id_from_list(rawProposal.rationale.title); + cy.get('@rawProposal').then((rawProposal) => { + getProposalIdFromList(rawProposal.rationale.title); cy.get('@proposalIdText').then((proposalId) => { cy.get(openProposals).within(() => { // 3001-VOTE-008 @@ -102,21 +119,22 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () { // 3001-VOTE-004 // 3001-VOTE-035 createRawProposal(this.minProposerBalance); - cy.get('@rawProposal').then((rawProposal) => { - cy.get_submitted_proposal_from_proposal_list( - rawProposal.rationale.title - ).within(() => { - cy.get(viewProposalButton).should('be.visible').click(); - }); + cy.get('@rawProposal').then((rawProposal) => { + getSubmittedProposalFromProposalList(rawProposal.rationale.title).within( + () => { + cy.get(viewProposalButton).should('be.visible').click(); + } + ); + cy.get('@proposalIdText').then((proposalId) => { - cy.get_proposal_information_from_table('ID') - .contains(proposalId) + getProposalInformationFromTable('ID') + .contains(String(proposalId)) .and('be.visible'); }); - cy.get_proposal_information_from_table('State') + getProposalInformationFromTable('State') .contains('Open') .and('be.visible'); - cy.get_proposal_information_from_table('Type') + getProposalInformationFromTable('Type') .contains('Freeform') .and('be.visible'); }); @@ -125,38 +143,21 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () { // 3001-VOTE-071 it('Newly created freeform proposals list - shows proposal participation - both met and not', function () { const proposalTitle = generateFreeFormProposalTitle(); - const requiredParticipation = 0.001; createFreeformProposal(proposalTitle); - - cy.get_submitted_proposal_from_proposal_list(proposalTitle) - .as('submittedProposal') - .within(() => { - // 3001-VOTE-039 - cy.get(voteStatus).should('have.text', 'Participation not reached'); - cy.get(viewProposalButton).click(); - }); - cy.vote_for_proposal('for'); - cy.get_proposal_information_from_table('Total Supply') - .invoke('text') - .then((totalSupply) => { - let tokensRequiredToAchieveResult = parseFloat( - (totalSupply.replace(/,/g, '') * requiredParticipation) / 100 - ).toFixed(2); - cy.ensure_specified_unstaked_tokens_are_associated( - tokensRequiredToAchieveResult - ); - cy.navigate_to_page_if_not_already_loaded('proposals'); - cy.get('@submittedProposal').within(() => - cy.get(viewProposalButton).click() - ); - cy.get_proposal_information_from_table('Token participation met') - .contains('👍') - .should('be.visible'); - cy.navigate_to('proposals'); - cy.get('@submittedProposal').within(() => - cy.get(voteStatus).should('have.text', 'Set to pass') - ); - }); + getSubmittedProposalFromProposalList(proposalTitle).within(() => { + // 3001-VOTE-039 + cy.get(voteStatus).should('have.text', 'Participation not reached'); + cy.get(viewProposalButton).click(); + }); + voteForProposal('for'); + navigateTo(navigation.proposals); + getSubmittedProposalFromProposalList(proposalTitle).within(() => { + cy.get(voteStatus).should('have.text', 'Set to pass'); + cy.get(viewProposalButton).click(); + }); + getProposalInformationFromTable('Token participation met') + .contains('👍') + .should('be.visible'); }); }); diff --git a/apps/governance-e2e/src/integration/flow/rewards-flow.cy.js b/apps/governance-e2e/src/integration/flow/rewards-flow.cy.ts similarity index 58% rename from apps/governance-e2e/src/integration/flow/rewards-flow.cy.js rename to apps/governance-e2e/src/integration/flow/rewards-flow.cy.ts index 30e8630ea..2f33aadfa 100644 --- a/apps/governance-e2e/src/integration/flow/rewards-flow.cy.js +++ b/apps/governance-e2e/src/integration/flow/rewards-flow.cy.ts @@ -1,3 +1,21 @@ +import { + navigateTo, + navigation, + waitForSpinner, +} from '../../support/common.functions'; +import { + clickOnValidatorFromList, + closeStakingDialog, + stakingPageAssociateTokens, + stakingValidatorPageAddStake, + waitForBeginningOfEpoch, +} from '../../support/staking.functions'; +import { ethereumWalletConnect } from '../../support/wallet-eth.functions'; +import { + depositAsset, + vegaWalletTeardown, +} from '../../support/wallet-teardown.functions'; + const vegaAssetAddress = '0x67175Da1D5e966e40D11c4B2519392B2058373de'; const vegaWalletUnstakedBalance = '[data-testid="vega-wallet-balance-unstaked"]'; @@ -8,29 +26,29 @@ const rewardsTimeOut = { timeout: 60000 }; context('rewards - flow', { tags: '@slow' }, function () { before('set up environment to allow rewards', function () { cy.visit('/'); - cy.wait_for_spinner(); - cy.deposit_asset(vegaAssetAddress, '1000'); + waitForSpinner(); + depositAsset(vegaAssetAddress, '1000'); cy.validatorsSelfDelegate(); - cy.ethereum_wallet_connect(); + ethereumWalletConnect(); cy.connectVegaWallet(); - topUpRewardsPool(); - cy.navigate_to('validators'); - cy.vega_wallet_teardown(); - cy.staking_page_associate_tokens('6000'); + cy.VegaWalletTopUpRewardsPool(30, 200); + navigateTo(navigation.validators); + vegaWalletTeardown(); + stakingPageAssociateTokens('6000'); cy.get(vegaWalletUnstakedBalance, txTimeout).should( 'contain', '6,000.0', txTimeout ); cy.get('button').contains('Select a validator to nominate').click(); - cy.click_on_validator_from_list(0); - cy.staking_validator_page_add_stake('3000'); - cy.close_staking_dialog(); - cy.navigate_to('validators'); - cy.click_on_validator_from_list(1); - cy.staking_validator_page_add_stake('3000'); - cy.close_staking_dialog(); - cy.navigate_to('rewards'); + clickOnValidatorFromList(0); + stakingValidatorPageAddStake('3000'); + closeStakingDialog(); + navigateTo(navigation.validators); + clickOnValidatorFromList(1); + stakingValidatorPageAddStake('3000'); + closeStakingDialog(); + navigateTo(navigation.rewards); }); it('Should display rewards per epoch', function () { @@ -54,7 +72,7 @@ context('rewards - flow', { tags: '@slow' }, function () { .within(() => { cy.get('h2').first().invoke('text').as('epochNumber'); }); - cy.wait_for_beginning_of_epoch(); + waitForBeginningOfEpoch(); cy.get('@epochNumber').then((epochNumber) => { cy.getByTestId(rewardsTable) .first() @@ -76,28 +94,12 @@ context('rewards - flow', { tags: '@slow' }, function () { cy.get('h2').first().should('contain.text', 'EPOCH'); cy.getByTestId('individual-rewards-asset').should('have.text', 'Vega'); cy.getByTestId('ACCOUNT_TYPE_GLOBAL_REWARD') - .should('contain.text', '0.4415') - .and('contain.text', '(44.15%)'); + .should('contain.text', '0.1177') + .and('contain.text', '(11.7733%)'); cy.getByTestId('ACCOUNT_TYPE_FEES_INFRASTRUCTURE') - .should('contain.text', '0.0004') - .and('contain.text', '(44.15%)'); - cy.getByTestId('total').should('have.text', '0.4419'); + .should('contain.text', '0.0001') + .and('contain.text', '(11.7733%)'); + cy.getByTestId('total').should('have.text', '0.1179'); }); }); - - function topUpRewardsPool() { - // Must ensure that test wallet contains assets already and that the tests are within the start and end epochs - cy.exec( - `vega wallet transaction send --wallet ${Cypress.env( - 'vegaWalletName' - )} --pubkey ${Cypress.env( - 'vegaWalletPublicKey' - )} -p "./src/fixtures/wallet/passphrase" --network DV '{"transfer":{"fromAccountType":4,"toAccountType":12,"to":"0000000000000000000000000000000000000000000000000000000000000000","asset":"b4f2726571fbe8e33b442dc92ed2d7f0d810e21835b7371a7915a365f07ccd9b","amount":"1000000000000000000","recurring":{"startEpoch":30, "endEpoch": 200, "factor":"1"}}}' --home ${Cypress.env( - 'vegaWalletLocation' - )}`, - { failOnNonZeroExit: false } - ) - .its('stderr') - .should('contain', ''); - } }); diff --git a/apps/governance-e2e/src/integration/flow/staking-flow.cy.js b/apps/governance-e2e/src/integration/flow/staking-flow.cy.js deleted file mode 100644 index 66e3a1794..000000000 --- a/apps/governance-e2e/src/integration/flow/staking-flow.cy.js +++ /dev/null @@ -1,876 +0,0 @@ -/// -const stakeValidatorListTotalStake = '[col-id="stake"] > div > span'; -const stakeValidatorListTotalShare = '[col-id="stakeShare"] > div > span'; -const stakeValidatorListValidatorStake = '[col-id="stake"] > div > span'; -const stakeRemoveStakeRadioButton = '[data-testid="remove-stake-radio"]'; -const stakeTokenAmountInputBox = '[data-testid="token-amount-input"]'; -const stakeTokenSubmitButton = '[data-testid="token-input-submit-button"]'; -const stakeNextEpochValue = '[data-testid="stake-next-epoch"]'; -const stakeThisEpochValue = '[data-testid="stake-this-epoch"]'; -const stakeAddStakeRadioButton = '[data-testid="add-stake-radio"]'; -const stakeMaximumTokens = '[data-testid="token-amount-use-maximum"]'; -const totalStake = '[data-testid="total-stake"]'; -const stakeShare = '[data-testid="stake-percentage"]'; -const vegaWalletPublicKeyShort = Cypress.env('vegaWalletPublicKeyShort'); -const vegaWalletAssociatedBalance = '[data-testid="currency-value"]'; -const vegaWalletUnstakedBalance = - '[data-testid="vega-wallet-balance-unstaked"]:visible'; -const vegaWalletStakedBalances = - '[data-testid="vega-wallet-balance-staked-validators"]'; -const ethWalletAssociatedBalances = - '[data-testid="eth-wallet-associated-balances"]'; -const ethWalletTotalAssociatedBalance = - '[data-testid="currency-locked"]:visible'; -const ethWalletContainer = '[data-testid="ethereum-wallet"]:visible'; -const vegaWallet = '[data-testid="vega-wallet"]'; -const partValidatorId = '…'; -const txTimeout = Cypress.env('txTimeout'); -const epochTimeout = Cypress.env('epochTimeout'); - -context( - 'Staking Tab - with eth and vega wallets connected', - { tags: '@slow' }, - function () { - // 2001-STKE-002, 2001-STKE-032 - before('visit staking tab and connect vega wallet', function () { - cy.visit('/'); - cy.vega_wallet_set_specified_approval_amount('1000'); - }); - - describe('Eth wallet - contains VEGA tokens', function () { - beforeEach( - 'teardown wallet & drill into a specific validator', - function () { - cy.reload(); - cy.wait_for_spinner(); - cy.connectVegaWallet(); - cy.ethereum_wallet_connect(); - cy.vega_wallet_teardown(); - cy.navigate_to('validators'); - } - ); - - it('Able to stake against a validator - using vega from wallet', function () { - cy.staking_page_associate_tokens('3'); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 3.0, - txTimeout - ); - - cy.get(ethWalletTotalAssociatedBalance, txTimeout) - .contains('3.0', txTimeout) - .should('be.visible'); - - cy.get(ethWalletAssociatedBalances, txTimeout) - .contains(vegaWalletPublicKeyShort, txTimeout) - .parent() - .should('contain', 3.0, txTimeout); - - cy.get('button').contains('Select a validator to nominate').click(); - - // 2001-STKE-031 - cy.click_on_validator_from_list(0); - - // 2001-STKE-033, 2001-STKE-034, 2001-STKE-037 - cy.staking_validator_page_add_stake('2'); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 1.0, - txTimeout - ); - // 2001-STKE-039 - cy.get(vegaWalletStakedBalances, txTimeout) - .should('contain', 2.0, txTimeout) - .and('contain', partValidatorId); - - cy.get(stakeNextEpochValue, epochTimeout) // 2001-STKE-016 2001-STKE-038 - .contains(2.0, epochTimeout) - .should('be.visible'); - - cy.get(stakeThisEpochValue, epochTimeout) // 2001-STKE-013 - .contains(2.0, epochTimeout) - .should('be.visible'); - - cy.close_staking_dialog(); - cy.navigate_to('validators'); - - // 2002-SINC-007 - cy.validate_validator_list_total_stake_and_share( - '0', - '2.00', - '100.00%' - ); - }); - - it('Able to stake against a validator - using vega from vesting contract', function () { - cy.staking_page_associate_tokens('3', { type: 'contract' }); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 3.0, - txTimeout - ); - - cy.get(ethWalletTotalAssociatedBalance, txTimeout) - .contains('3.0', txTimeout) - .should('be.visible'); - - cy.get(ethWalletAssociatedBalances, txTimeout) - .contains(vegaWalletPublicKeyShort, txTimeout) - .parent() - .should('contain', 3.0, txTimeout); - - cy.get('button').contains('Select a validator to nominate').click(); - - cy.click_on_validator_from_list(0); - - cy.staking_validator_page_add_stake('2'); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 1.0, - txTimeout - ); - - cy.get(vegaWalletStakedBalances, txTimeout) - .should('contain', 2.0, txTimeout) - .and('contain', partValidatorId); - - cy.get(stakeNextEpochValue, epochTimeout) - .contains(2.0, epochTimeout) - .should('be.visible'); - - cy.get(stakeThisEpochValue, epochTimeout) - .contains(2.0, epochTimeout) - .should('be.visible'); - - cy.close_staking_dialog(); - cy.navigate_to('validators'); - - cy.validate_validator_list_total_stake_and_share( - '0', - '2.00', - '100.00%' - ); - }); - - it('Able to stake against a validator - using vega from both wallet and vesting contract', function () { - cy.staking_page_associate_tokens('3', { type: 'contract' }); - cy.navigate_to('validators'); - cy.staking_page_associate_tokens('4', { type: 'wallet' }); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 7.0, - txTimeout - ); - - cy.get(ethWalletTotalAssociatedBalance, txTimeout) - .contains('3.0', txTimeout) - .should('be.visible'); - - cy.get(ethWalletTotalAssociatedBalance, txTimeout) - .contains('4.0', txTimeout) - .should('be.visible'); - - cy.get(ethWalletAssociatedBalances, txTimeout).should( - 'contain', - 3.0, - txTimeout - ); - - cy.get(ethWalletAssociatedBalances, txTimeout).should( - 'contain', - 4.0, - txTimeout - ); - - cy.get('button').contains('Select a validator to nominate').click(); - - cy.click_on_validator_from_list(0); - - cy.staking_validator_page_add_stake('6'); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 1.0, - txTimeout - ); - - cy.get(vegaWalletStakedBalances, txTimeout) - .should('contain', 6.0, txTimeout) - .and('contain', partValidatorId); - - cy.get(stakeNextEpochValue, epochTimeout) - .contains(6.0, epochTimeout) - .should('be.visible'); - - cy.get(stakeThisEpochValue, epochTimeout) - .contains(6.0, epochTimeout) - .should('be.visible'); - - cy.close_staking_dialog(); - cy.navigate_to('validators'); - - cy.validate_validator_list_total_stake_and_share( - '0', - '6.00', - '100.00%' - ); - }); - - it('Able to stake against multiple validators', function () { - cy.staking_page_associate_tokens('5'); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 5.0, - txTimeout - ); - - cy.get('button').contains('Select a validator to nominate').click(); - - cy.click_on_validator_from_list(0); - - cy.staking_validator_page_add_stake('2'); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 3.0, - txTimeout - ); - - cy.get(vegaWalletStakedBalances, txTimeout) - .parent() - .should('contain', 2.0, txTimeout); - - cy.close_staking_dialog(); - cy.navigate_to('validators'); - - cy.click_on_validator_from_list(1); - - cy.staking_validator_page_add_stake('1'); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 2.0, - txTimeout - ); - - cy.get(vegaWalletStakedBalances, txTimeout) - .should('have.length', 2, txTimeout) - .eq(0) - .should('contain', 2.0, txTimeout); - - cy.get(vegaWalletStakedBalances, txTimeout) - .eq(1) - .should('contain', 1.0, txTimeout); - - cy.close_staking_dialog(); - cy.navigate_to('validators'); - - cy.get(`[row-id="${0}"]`).within(() => { - cy.get(stakeValidatorListTotalStake) - .should('have.text', '2.00') - .and('be.visible'); - cy.get(stakeValidatorListTotalShare) - .should('have.text', '66.67%') - .and('be.visible'); - cy.get(stakeValidatorListValidatorStake) - .scrollIntoView() - .should('have.text', '2.00') - .and('be.visible'); - }); - - cy.get(`[row-id="${1}"]`).within(() => { - cy.get(stakeValidatorListTotalStake) - .scrollIntoView() - .should('have.text', '1.00') - .and('be.visible'); - cy.get(stakeValidatorListTotalShare) - .should('have.text', '33.33%') - .and('be.visible'); - cy.get(stakeValidatorListValidatorStake) - .scrollIntoView() - .should('have.text', '1.00') - .and('be.visible'); - }); - }); - - // 2001-STKE-041 - it( - 'Able to remove part of a stake against a validator', - { tags: '@smoke' }, - function () { - cy.staking_page_associate_tokens('4'); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 4.0, - txTimeout - ); - - cy.get('button').contains('Select a validator to nominate').click(); - - cy.click_on_validator_from_list(0); - - cy.staking_validator_page_add_stake('3'); - - cy.get(stakeNextEpochValue, epochTimeout) - .contains(3.0, epochTimeout) - .should('be.visible'); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 1.0, - txTimeout - ); - - cy.close_staking_dialog(); - cy.navigate_to('validators'); - // 2001-STKE-040 - cy.click_on_validator_from_list(0); - - // 2001-STKE-044, 2001-STKE-048 - cy.staking_validator_page_remove_stake('1'); - - // 2001-STKE-049 - cy.get(stakeNextEpochValue, epochTimeout).contains(2.0, epochTimeout); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 2.0, - txTimeout - ); - - cy.get(vegaWalletStakedBalances, txTimeout).should( - 'contain', - 2.0, - txTimeout - ); - - cy.get(stakeNextEpochValue, epochTimeout) - .contains(2.0, epochTimeout) - .should('be.visible'); - - cy.get(stakeThisEpochValue, epochTimeout) - .contains(2.0, epochTimeout) - .should('be.visible'); - - cy.get(totalStake, epochTimeout).should('contain.text', '2'); - cy.get(stakeShare, epochTimeout).should('have.text', '100%'); - - cy.navigate_to('validators'); - - cy.validate_validator_list_total_stake_and_share( - '0', - '2.00', - '100.00%' - ); - } - ); - - // 2001-STKE-045 - it('Able to remove a full stake against a validator', function () { - cy.staking_page_associate_tokens('3'); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 3.0, - txTimeout - ); - - cy.get('button').contains('Select a validator to nominate').click(); - - cy.click_on_validator_from_list(0); - - cy.staking_validator_page_add_stake('1'); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 2.0, - txTimeout - ); - - cy.close_staking_dialog(); - cy.navigate_to('validators'); - - cy.click_on_validator_from_list('0'); - - cy.staking_validator_page_remove_stake('1'); - - cy.get(stakeNextEpochValue, epochTimeout) - .contains(0.0, epochTimeout) - .should('be.visible'); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 3.0, - txTimeout - ); - - cy.get(stakeNextEpochValue, epochTimeout) - .contains(0.0, epochTimeout) - .should('be.visible'); - - cy.get(stakeThisEpochValue, epochTimeout) - .contains(0.0, epochTimeout) - .should('be.visible'); - - cy.get(vegaWalletStakedBalances, txTimeout).should( - 'not.exist', - txTimeout - ); - - cy.navigate_to('validators'); - - cy.validate_validator_list_total_stake_and_share('0', '0.00', '0.00%'); - }); - - it('Unable to remove a stake with a negative value for a validator', function () { - cy.staking_page_associate_tokens('3'); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 3.0, - txTimeout - ); - - cy.get('button').contains('Select a validator to nominate').click(); - - cy.click_on_validator_from_list(0); - - cy.staking_validator_page_add_stake('2'); - - cy.get(stakeNextEpochValue, epochTimeout) - .contains(2.0, epochTimeout) - .should('be.visible'); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 1.0, - txTimeout - ); - - cy.close_staking_dialog(); - cy.navigate_to('validators'); - - cy.click_on_validator_from_list(0); - - cy.get(stakeRemoveStakeRadioButton, txTimeout).click(); - - cy.get(stakeTokenAmountInputBox).type('-0.1'); - - cy.contains('Waiting for next epoch to start', epochTimeout); - - cy.get(stakeTokenSubmitButton) - .should('be.disabled', epochTimeout) - .and('contain', `Remove -0.1 $VEGA tokens at the end of epoch`) - .and('be.visible'); - }); - - it('Unable to remove a stake greater than staked amount next epoch for a validator', function () { - cy.staking_page_associate_tokens('3'); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 3.0, - txTimeout - ); - - cy.get('button').contains('Select a validator to nominate').click(); - - cy.click_on_validator_from_list(0); - - cy.staking_validator_page_add_stake('2'); - - cy.get(stakeNextEpochValue, epochTimeout) - .contains(2.0, epochTimeout) - .should('be.visible'); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 1.0, - txTimeout - ); - - cy.close_staking_dialog(); - cy.navigate_to('validators'); - - cy.click_on_validator_from_list(0); - - cy.get(stakeRemoveStakeRadioButton).click(); - - cy.get(stakeTokenAmountInputBox).type(4); - - cy.contains('Waiting for next epoch to start', epochTimeout); - - cy.get(stakeTokenSubmitButton) - .should('be.disabled', epochTimeout) - .and('contain', `Remove 4 $VEGA tokens at the end of epoch`) - .and('be.visible'); - }); - - it('Disassociating all wallet tokens max - removes all staked tokens', function () { - cy.staking_page_associate_tokens('3'); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 3.0, - txTimeout - ); - - cy.get('button').contains('Select a validator to nominate').click(); - - cy.click_on_validator_from_list('1'); - - cy.staking_validator_page_add_stake('2'); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 1.0, - txTimeout - ); - - cy.get(vegaWalletStakedBalances, txTimeout).should( - 'contain', - 2.0, - txTimeout - ); - - cy.close_staking_dialog(); - cy.staking_page_disassociate_all_tokens('wallet'); - - cy.get(ethWalletContainer).within(() => { - cy.contains(vegaWalletPublicKeyShort, txTimeout).should('not.exist'); - }); - - cy.get(ethWalletTotalAssociatedBalance, txTimeout) - .contains('0.0', txTimeout) - .should('be.visible'); - - cy.get(vegaWallet).within(() => { - cy.get(vegaWalletAssociatedBalance, txTimeout).should( - 'contain', - '0.00' - ); - }); - - cy.get(vegaWalletStakedBalances, txTimeout).should( - 'not.exist', - txTimeout - ); - - cy.navigate_to('validators'); - - cy.validate_validator_list_total_stake_and_share('0', '0.00', '0.00%'); - }); - - it('Disassociating all vesting contract tokens max - removes all staked tokens', function () { - cy.staking_page_associate_tokens('3', { type: 'contract' }); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 3.0, - txTimeout - ); - - cy.get('button').contains('Select a validator to nominate').click(); - - cy.click_on_validator_from_list('1'); - - cy.staking_validator_page_add_stake('2'); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 1.0, - txTimeout - ); - - cy.get(vegaWalletStakedBalances, txTimeout).should( - 'contain', - 2.0, - txTimeout - ); - cy.close_staking_dialog(); - cy.staking_page_disassociate_all_tokens('contract'); - - cy.get(ethWalletContainer).within(() => { - cy.contains(vegaWalletPublicKeyShort, txTimeout).should('not.exist'); - }); - - cy.get(ethWalletTotalAssociatedBalance, txTimeout) - .contains('0.0', txTimeout) - .should('be.visible'); - - cy.get(vegaWallet).within(() => { - cy.get(vegaWalletAssociatedBalance, txTimeout).should( - 'contain', - '0.00' - ); - }); - - cy.get(vegaWalletStakedBalances, txTimeout).should( - 'not.exist', - txTimeout - ); - - cy.navigate_to('validators'); - - cy.validate_validator_list_total_stake_and_share('0', '0.00', '0.00%'); - }); - - it('Disassociating some tokens - prioritizes unstaked tokens', function () { - cy.staking_page_associate_tokens('3'); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 3.0, - txTimeout - ); - - cy.get('button').contains('Select a validator to nominate').click(); - cy.click_on_validator_from_list(0); - - cy.staking_validator_page_add_stake('2'); - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 1.0, - txTimeout - ); - - cy.get(vegaWalletStakedBalances, txTimeout).should( - 'contain', - 2.0, - txTimeout - ); - cy.close_staking_dialog(); - cy.staking_page_disassociate_tokens('1'); - - cy.get(ethWalletTotalAssociatedBalance, txTimeout) - .contains('2.0', txTimeout) - .should('be.visible'); - - cy.get(vegaWallet).within(() => { - cy.get(vegaWalletAssociatedBalance, txTimeout).should( - 'contain', - '2.00' - ); - }); - - cy.get(vegaWalletStakedBalances, txTimeout) - .should('contain', 2.0, txTimeout) - .and('contain', partValidatorId); - - cy.navigate_to('validators'); - - cy.validate_validator_list_total_stake_and_share( - '0', - '2.00', - '100.00%' - ); - }); - - it('Associating wallet tokens - when some already staked - auto stakes tokens to staked validator', function () { - // 2001-STKE-004 - cy.staking_page_associate_tokens('3'); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 3.0, - txTimeout - ); - - cy.get('button').contains('Select a validator to nominate').click(); - cy.click_on_validator_from_list(0); - - cy.staking_validator_page_add_stake('3'); - - cy.get(vegaWalletStakedBalances, txTimeout).should( - 'contain', - 3.0, - txTimeout - ); - cy.close_staking_dialog(); - cy.staking_page_associate_tokens('4'); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 0.0, - txTimeout - ); - - cy.get(vegaWalletStakedBalances, txTimeout).should( - 'contain', - 7.0, - txTimeout - ); - }); - - it('Associating vesting contract tokens - when some already staked - auto stakes tokens to staked validator', function () { - // 2001-STKE-004 - cy.staking_page_associate_tokens('3', { type: 'contract' }); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 3.0, - txTimeout - ); - - cy.get('button').contains('Select a validator to nominate').click(); - cy.click_on_validator_from_list(0); - - cy.staking_validator_page_add_stake('3'); - - cy.get(vegaWalletStakedBalances, txTimeout).should( - 'contain', - 3.0, - txTimeout - ); - cy.close_staking_dialog(); - cy.staking_page_associate_tokens('4', { type: 'contract' }); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 0.0, - txTimeout - ); - - cy.get(vegaWalletStakedBalances, txTimeout).should( - 'contain', - 7.0, - txTimeout - ); - }); - - it('Associating vesting contract tokens - when wallet tokens already staked - auto stakes tokens to staked validator', function () { - // 2001-STKE-004 - cy.staking_page_associate_tokens('3', { type: 'wallet' }); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 3.0, - txTimeout - ); - - cy.get('button').contains('Select a validator to nominate').click(); - cy.click_on_validator_from_list(0); - - cy.staking_validator_page_add_stake('3'); - - cy.get(vegaWalletStakedBalances, txTimeout).should( - 'contain', - 3.0, - txTimeout - ); - cy.close_staking_dialog(); - cy.staking_page_associate_tokens('4', { type: 'contract' }); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 0.0, - txTimeout - ); - - cy.get(vegaWalletStakedBalances, txTimeout).should( - 'contain', - 7.0, - txTimeout - ); - }); - - it('Associating tokens - with multiple validators already staked - auto stakes to staked validators - abiding by existing stake ratio', function () { - // 2001-STKE-004 - cy.staking_page_associate_tokens('6'); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 6.0, - txTimeout - ); - - cy.get('button').contains('Select a validator to nominate').click(); - cy.click_on_validator_from_list(0); - - cy.staking_validator_page_add_stake('2'); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 0.0, - txTimeout - ); - cy.close_staking_dialog(); - - cy.click_on_validator_from_list(1); - - cy.staking_validator_page_add_stake('4'); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 0.0, - txTimeout - ); - cy.close_staking_dialog(); - cy.staking_page_associate_tokens('6'); - - cy.get(vegaWallet).within(() => { - cy.get(vegaWalletAssociatedBalance, txTimeout).should( - 'contain', - '12.00' - ); - }); - - cy.get(vegaWalletStakedBalances, txTimeout) - .should('contain', '4.0', txTimeout) - .and('contain', partValidatorId); - - cy.get(vegaWalletStakedBalances, txTimeout) - .should('contain', '8.0') - .and('contain', partValidatorId); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 0.0, - txTimeout - ); - }); - - it('Selecting use maximum where tokens are already staked - suggests the unstaked token amount', function () { - cy.staking_page_associate_tokens('3'); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 3.0, - txTimeout - ); - - cy.get('button').contains('Select a validator to nominate').click(); - cy.click_on_validator_from_list(0); - - cy.staking_validator_page_add_stake('2'); - - cy.get(vegaWalletUnstakedBalance, txTimeout).should( - 'contain', - 1.0, - txTimeout - ); - cy.close_staking_dialog(); - - cy.click_on_validator_from_list(0); - - cy.get(stakeAddStakeRadioButton).click(); - - cy.get(stakeMaximumTokens, { timeout: 60000 }).click(); - - cy.get(stakeTokenSubmitButton).should('contain', 'Add 1 $VEGA tokens'); - }); - - after('teardown wallet', function () { - cy.vega_wallet_teardown(); - }); - }); - } -); diff --git a/apps/governance-e2e/src/integration/flow/staking-flow.cy.ts b/apps/governance-e2e/src/integration/flow/staking-flow.cy.ts new file mode 100644 index 000000000..e76d97a06 --- /dev/null +++ b/apps/governance-e2e/src/integration/flow/staking-flow.cy.ts @@ -0,0 +1,454 @@ +/// +import { + verifyUnstakedBalance, + verifyStakedBalance, + verifyEthWalletTotalAssociatedBalance, + verifyEthWalletAssociatedBalance, + waitForSpinner, + navigateTo, + navigation, +} from '../../support/common.functions'; +import { + clickOnValidatorFromList, + closeStakingDialog, + ensureSpecifiedUnstakedTokensAreAssociated, + stakingPageAssociateTokens, + stakingPageDisassociateAllTokens, + stakingPageDisassociateTokens, + stakingValidatorPageAddStake, + stakingValidatorPageRemoveStake, + validateValidatorListTotalStakeAndShare, + waitForBeginningOfEpoch, +} from '../../support/staking.functions'; +import { ethereumWalletConnect } from '../../support/wallet-eth.functions'; +import { + vegaWalletSetSpecifiedApprovalAmount, + vegaWalletTeardown, +} from '../../support/wallet-teardown.functions'; +const stakeValidatorListTotalStake = '[col-id="stake"] > div > span'; +const stakeValidatorListTotalShare = '[col-id="stakeShare"] > div > span'; +const stakeValidatorListValidatorStake = '[col-id="stake"] > div > span'; +const stakeRemoveStakeRadioButton = '[data-testid="remove-stake-radio"]'; +const stakeTokenAmountInputBox = '[data-testid="token-amount-input"]'; +const stakeTokenSubmitButton = '[data-testid="token-input-submit-button"]'; +const stakeAddStakeRadioButton = '[data-testid="add-stake-radio"]'; +const stakeMaximumTokens = '[data-testid="token-amount-use-maximum"]'; +const totalStake = '[data-testid="total-stake"]'; +const stakeShare = '[data-testid="stake-percentage"]'; +const vegaWalletPublicKeyShort = Cypress.env('vegaWalletPublicKeyShort'); +const vegaWalletAssociatedBalance = '[data-testid="currency-value"]'; +const vegaWalletStakedBalances = + '[data-testid="vega-wallet-balance-staked-validators"]'; +const ethWalletContainer = '[data-testid="ethereum-wallet"]'; +const vegaWallet = '[data-testid="vega-wallet"]'; +const txTimeout = Cypress.env('txTimeout'); +const epochTimeout = Cypress.env('epochTimeout'); + +context( + 'Staking Tab - with eth and vega wallets connected', + { tags: '@slow' }, + function () { + // 2001-STKE-002, 2001-STKE-032 + before('visit staking tab and connect vega wallet', function () { + cy.visit('/'); + ethereumWalletConnect(); + // this is a workaround for #2422 which can be removed once issue is resolved + cy.associateTokensToVegaWallet('4'); + vegaWalletSetSpecifiedApprovalAmount('1000'); + }); + + describe('Eth wallet - contains VEGA tokens', function () { + beforeEach( + 'teardown wallet & drill into a specific validator', + function () { + cy.reload(); + waitForSpinner(); + cy.connectVegaWallet(); + ethereumWalletConnect(); + navigateTo(navigation.validators); + } + ); + + it('Able to stake against a validator - using vega from wallet', function () { + ensureSpecifiedUnstakedTokensAreAssociated('3'); + verifyUnstakedBalance(3.0); + verifyEthWalletTotalAssociatedBalance('3.0'); + verifyEthWalletAssociatedBalance('3.0'); + cy.get('button').contains('Select a validator to nominate').click(); + // 2001-STKE-031 + clickOnValidatorFromList(0); + // 2001-STKE-033, 2001-STKE-034, 2001-STKE-037 + stakingValidatorPageAddStake('2'); + verifyUnstakedBalance(1.0); + // 2001-STKE-039 + verifyStakedBalance(2.0); + verifyNextEpochValue(2.0); // 2001-STKE-016 2001-STKE-038 + verifyThisEpochValue(2.0); // 2001-STKE-013 + closeStakingDialog(); + navigateTo(navigation.validators); + + // 2002-SINC-007 + validateValidatorListTotalStakeAndShare('0', '2.00', '100.00%'); + }); + + it('Able to stake against a validator - using vega from vesting contract', function () { + stakingPageAssociateTokens('3', { type: 'contract' }); + verifyUnstakedBalance(3.0); + verifyEthWalletTotalAssociatedBalance('3.0'); + verifyEthWalletAssociatedBalance('3.0'); + cy.get('button').contains('Select a validator to nominate').click(); + clickOnValidatorFromList(0); + stakingValidatorPageAddStake('2'); + verifyUnstakedBalance(1.0); + verifyStakedBalance(2.0); + verifyNextEpochValue(2.0); + verifyThisEpochValue(2.0); + closeStakingDialog(); + navigateTo(navigation.validators); + validateValidatorListTotalStakeAndShare('0', '2.00', '100.00%'); + }); + + it('Able to stake against a validator - using vega from both wallet and vesting contract', function () { + stakingPageAssociateTokens('3', { type: 'contract' }); + navigateTo(navigation.validators); + stakingPageAssociateTokens('4', { type: 'wallet' }); + verifyUnstakedBalance(7.0); + verifyEthWalletTotalAssociatedBalance('3.0'); + verifyEthWalletTotalAssociatedBalance('4.0'); + verifyEthWalletTotalAssociatedBalance('3.0'); + verifyEthWalletTotalAssociatedBalance('4.0'); + cy.get('button').contains('Select a validator to nominate').click(); + clickOnValidatorFromList(0); + stakingValidatorPageAddStake('6'); + verifyUnstakedBalance(1.0); + verifyStakedBalance(6.0); + verifyNextEpochValue(6.0); + verifyThisEpochValue(6.0); + closeStakingDialog(); + navigateTo(navigation.validators); + validateValidatorListTotalStakeAndShare('0', '6.00', '100.00%'); + }); + + it('Able to stake against multiple validators', function () { + stakingPageAssociateTokens('5'); + verifyUnstakedBalance(5.0); + cy.get('button').contains('Select a validator to nominate').click(); + clickOnValidatorFromList(0); + stakingValidatorPageAddStake('2'); + verifyUnstakedBalance(3.0); + cy.get(vegaWalletStakedBalances, txTimeout) + .parent() + .should('contain', 2.0, txTimeout); + closeStakingDialog(); + navigateTo(navigation.validators); + clickOnValidatorFromList(1); + stakingValidatorPageAddStake('1'); + verifyUnstakedBalance(2.0); + cy.get(vegaWalletStakedBalances, txTimeout) + .should('have.length', 4, txTimeout) + .eq(0) + .should('contain', 2.0, txTimeout); + cy.get(vegaWalletStakedBalances, txTimeout) + .eq(1) + .should('contain', 1.0, txTimeout); + closeStakingDialog(); + navigateTo(navigation.validators); + cy.get(`[row-id="${0}"]`).within(() => { + cy.get(stakeValidatorListTotalStake) + .should('have.text', '2.00') + .and('be.visible'); + cy.get(stakeValidatorListTotalShare) + .should('have.text', '66.67%') + .and('be.visible'); + cy.get(stakeValidatorListValidatorStake) + .scrollIntoView() + .should('have.text', '2.00') + .and('be.visible'); + }); + cy.get(`[row-id="${1}"]`).within(() => { + cy.get(stakeValidatorListTotalStake) + .scrollIntoView() + .should('have.text', '1.00') + .and('be.visible'); + cy.get(stakeValidatorListTotalShare) + .should('have.text', '33.33%') + .and('be.visible'); + cy.get(stakeValidatorListValidatorStake) + .scrollIntoView() + .should('have.text', '1.00') + .and('be.visible'); + }); + }); + + // 2001-STKE-041 + it( + 'Able to remove part of a stake against a validator', + { tags: '@smoke' }, + function () { + ensureSpecifiedUnstakedTokensAreAssociated('4'); + navigateTo(navigation.validators); + clickOnValidatorFromList(0); + stakingValidatorPageAddStake('3'); + verifyNextEpochValue(3.0); + verifyUnstakedBalance(1.0); + closeStakingDialog(); + navigateTo(navigation.validators); + // 2001-STKE-040 + clickOnValidatorFromList(0); + // 2001-STKE-044, 2001-STKE-048 + stakingValidatorPageRemoveStake('1'); + // 2001-STKE-049 + verifyNextEpochValue(2.0); + verifyUnstakedBalance(2.0); + verifyStakedBalance(2.0); + verifyNextEpochValue(2.0); + verifyThisEpochValue(2.0); + cy.get(totalStake, epochTimeout).should('contain.text', '2'); + waitForBeginningOfEpoch(); + cy.get(stakeShare).should('have.text', '100%'); + navigateTo(navigation.validators); + validateValidatorListTotalStakeAndShare('0', '2.00', '100.00%'); + } + ); + + // 2001-STKE-045 + it('Able to remove a full stake against a validator', function () { + stakingPageAssociateTokens('3'); + verifyUnstakedBalance(3.0); + cy.get('button').contains('Select a validator to nominate').click(); + clickOnValidatorFromList(0); + stakingValidatorPageAddStake('1'); + verifyUnstakedBalance(2.0); + closeStakingDialog(); + navigateTo(navigation.validators); + clickOnValidatorFromList(0); + stakingValidatorPageRemoveStake('1'); + verifyNextEpochValue(0.0); + verifyUnstakedBalance(3.0); + verifyNextEpochValue(0.0); + verifyThisEpochValue(0.0); + cy.get(vegaWalletStakedBalances, txTimeout).should( + 'not.exist', + txTimeout + ); + navigateTo(navigation.validators); + validateValidatorListTotalStakeAndShare('0', '0.00', '0.00%'); + }); + + it('Unable to remove a stake with a negative value for a validator', function () { + stakingPageAssociateTokens('3'); + verifyUnstakedBalance(3.0); + cy.get('button').contains('Select a validator to nominate').click(); + clickOnValidatorFromList(0); + stakingValidatorPageAddStake('2'); + verifyNextEpochValue(2.0); + verifyUnstakedBalance(1.0); + closeStakingDialog(); + navigateTo(navigation.validators); + clickOnValidatorFromList(0); + cy.get(stakeRemoveStakeRadioButton, txTimeout).click(); + cy.get(stakeTokenAmountInputBox).type('-0.1'); + cy.contains('Waiting for next epoch to start', epochTimeout); + cy.get(stakeTokenSubmitButton) + .should('be.disabled', epochTimeout) + .and('contain', `Remove -0.1 $VEGA tokens at the end of epoch`) + .and('be.visible'); + }); + + it('Unable to remove a stake greater than staked amount next epoch for a validator', function () { + stakingPageAssociateTokens('3'); + verifyUnstakedBalance(3.0); + cy.get('button').contains('Select a validator to nominate').click(); + clickOnValidatorFromList(0); + stakingValidatorPageAddStake('2'); + verifyNextEpochValue(2.0); + verifyUnstakedBalance(3.0); + closeStakingDialog(); + navigateTo(navigation.validators); + clickOnValidatorFromList(0); + cy.get(stakeRemoveStakeRadioButton).click(); + cy.get(stakeTokenAmountInputBox).type('4'); + cy.contains('Waiting for next epoch to start', epochTimeout); + cy.get(stakeTokenSubmitButton) + .should('be.disabled', epochTimeout) + .and('contain', `Remove 4 $VEGA tokens at the end of epoch`) + .and('be.visible'); + }); + + it('Disassociating all wallet tokens max - removes all staked tokens', function () { + stakingPageAssociateTokens('3'); + verifyUnstakedBalance(3.0); + cy.get('button').contains('Select a validator to nominate').click(); + clickOnValidatorFromList(1); + stakingValidatorPageAddStake('2'); + verifyUnstakedBalance(3.0); + verifyStakedBalance(2.0); + closeStakingDialog(); + stakingPageDisassociateAllTokens(); + cy.get(ethWalletContainer).within(() => { + cy.contains(vegaWalletPublicKeyShort, txTimeout).should('not.exist'); + }); + verifyEthWalletTotalAssociatedBalance('0.0'); + cy.get(vegaWallet).within(() => { + cy.get(vegaWalletAssociatedBalance, txTimeout).should( + 'contain', + '0.00' + ); + }); + cy.get(vegaWalletStakedBalances, txTimeout).should( + 'not.exist', + txTimeout + ); + navigateTo(navigation.validators); + validateValidatorListTotalStakeAndShare('0', '0.00', '0.00%'); + }); + + it('Disassociating all vesting contract tokens max - removes all staked tokens', function () { + stakingPageAssociateTokens('3', { type: 'contract' }); + verifyUnstakedBalance(3.0); + cy.get('button').contains('Select a validator to nominate').click(); + clickOnValidatorFromList(1); + stakingValidatorPageAddStake('2'); + verifyUnstakedBalance(1.0); + verifyStakedBalance(2.0); + closeStakingDialog(); + stakingPageDisassociateAllTokens('contract'); + cy.get(ethWalletContainer).within(() => { + cy.contains(vegaWalletPublicKeyShort, txTimeout).should('not.exist'); + }); + verifyEthWalletTotalAssociatedBalance('0.0'); + cy.get(vegaWallet).within(() => { + cy.get(vegaWalletAssociatedBalance, txTimeout).should( + 'contain', + '0.00' + ); + }); + cy.get(vegaWalletStakedBalances, txTimeout).should( + 'not.exist', + txTimeout + ); + navigateTo(navigation.validators); + validateValidatorListTotalStakeAndShare('0', '0.00', '0.00%'); + }); + + it('Disassociating some tokens - prioritizes unstaked tokens', function () { + stakingPageAssociateTokens('3'); + verifyUnstakedBalance(3.0); + cy.get('button').contains('Select a validator to nominate').click(); + clickOnValidatorFromList(0); + stakingValidatorPageAddStake('2'); + verifyUnstakedBalance(1.0); + verifyStakedBalance(2.0); + closeStakingDialog(); + stakingPageDisassociateTokens('1'); + verifyEthWalletTotalAssociatedBalance('2.0'); + cy.get(vegaWallet).within(() => { + cy.get(vegaWalletAssociatedBalance, txTimeout).should( + 'contain', + '2.00' + ); + }); + verifyStakedBalance(2.0); + navigateTo(navigation.validators); + validateValidatorListTotalStakeAndShare('0', '2.00', '100.00%'); + }); + + it('Associating wallet tokens - when some already staked - auto stakes tokens to staked validator', function () { + // 2001-STKE-004 + stakingPageAssociateTokens('3'); + verifyUnstakedBalance(3.0); + cy.get('button').contains('Select a validator to nominate').click(); + clickOnValidatorFromList(0); + stakingValidatorPageAddStake('3'); + verifyStakedBalance(3.0); + closeStakingDialog(); + stakingPageAssociateTokens('4'); + verifyUnstakedBalance(0.0); + verifyStakedBalance(7.0); + }); + + it('Associating vesting contract tokens - when some already staked - auto stakes tokens to staked validator', function () { + // 2001-STKE-004 + stakingPageAssociateTokens('3', { type: 'contract' }); + verifyUnstakedBalance(3.0); + cy.get('button').contains('Select a validator to nominate').click(); + clickOnValidatorFromList(0); + stakingValidatorPageAddStake('3'); + verifyStakedBalance(3.0); + closeStakingDialog(); + stakingPageAssociateTokens('4', { type: 'contract' }); + verifyUnstakedBalance(0.0); + verifyStakedBalance(7.0); + }); + + it('Associating vesting contract tokens - when wallet tokens already staked - auto stakes tokens to staked validator', function () { + // 2001-STKE-004 + stakingPageAssociateTokens('3', { type: 'wallet' }); + verifyUnstakedBalance(3.0); + cy.get('button').contains('Select a validator to nominate').click(); + clickOnValidatorFromList(0); + stakingValidatorPageAddStake('3'); + verifyStakedBalance(3.0); + closeStakingDialog(); + stakingPageAssociateTokens('4', { type: 'contract' }); + verifyUnstakedBalance(0.0); + verifyStakedBalance(7.0); + }); + + it('Associating tokens - with multiple validators already staked - auto stakes to staked validators - abiding by existing stake ratio', function () { + // 2001-STKE-004 + stakingPageAssociateTokens('6'); + verifyUnstakedBalance(6.0); + cy.get('button').contains('Select a validator to nominate').click(); + clickOnValidatorFromList(0); + stakingValidatorPageAddStake('2'); + verifyUnstakedBalance(0.0); + closeStakingDialog(); + clickOnValidatorFromList(1); + stakingValidatorPageAddStake('4'); + verifyUnstakedBalance(0.0); + closeStakingDialog(); + stakingPageAssociateTokens('6'); + cy.get(vegaWallet).within(() => { + cy.get(vegaWalletAssociatedBalance, txTimeout).should( + 'contain', + '12.00' + ); + }); + verifyStakedBalance(4.0); + verifyStakedBalance(8.0); + verifyUnstakedBalance(0.0); + }); + + it('Selecting use maximum where tokens are already staked - suggests the unstaked token amount', function () { + stakingPageAssociateTokens('3'); + verifyUnstakedBalance(3.0); + cy.get('button').contains('Select a validator to nominate').click(); + clickOnValidatorFromList(0); + stakingValidatorPageAddStake('2'); + verifyUnstakedBalance(1.0); + closeStakingDialog(); + clickOnValidatorFromList(0); + cy.get(stakeAddStakeRadioButton).click(); + cy.get(stakeMaximumTokens, { timeout: 60000 }).click(); + cy.get(stakeTokenSubmitButton).should('contain', 'Add 1 $VEGA tokens'); + }); + + afterEach('Teardown Wallet', function () { + vegaWalletTeardown(); + }); + + function verifyNextEpochValue(amount: number) { + cy.getByTestId('stake-next-epoch', epochTimeout) + .contains(amount, epochTimeout) + .should('be.visible'); + } + + function verifyThisEpochValue(amount: number) { + cy.getByTestId('stake-this-epoch', epochTimeout) // 2001-STKE-013 + .contains(amount, epochTimeout) + .should('be.visible'); + } + }); + } +); diff --git a/apps/governance-e2e/src/integration/flow/token-association-flow.cy.js b/apps/governance-e2e/src/integration/flow/token-association-flow.cy.ts similarity index 64% rename from apps/governance-e2e/src/integration/flow/token-association-flow.cy.js rename to apps/governance-e2e/src/integration/flow/token-association-flow.cy.ts index ad067a18e..5d81caec0 100644 --- a/apps/governance-e2e/src/integration/flow/token-association-flow.cy.js +++ b/apps/governance-e2e/src/integration/flow/token-association-flow.cy.ts @@ -1,13 +1,31 @@ +import { + verifyEthWalletTotalAssociatedBalance, + verifyEthWalletAssociatedBalance, + waitForSpinner, + navigateTo, + navigation, +} from '../../support/common.functions'; +import { + stakingPageAssociateTokens, + stakingPageDisassociateAllTokens, + stakingPageDisassociateTokens, + validateWalletCurrency, +} from '../../support/staking.functions'; +import { ethereumWalletConnect } from '../../support/wallet-eth.functions'; +import { + vegaWalletAssociate, + vegaWalletDisassociate, + vegaWalletSetSpecifiedApprovalAmount, + vegaWalletTeardown, +} from '../../support/wallet-teardown.functions'; + const ethWalletContainer = '[data-testid="ethereum-wallet"]'; -const ethWalletAssociatedBalances = - '[data-testid="eth-wallet-associated-balances"]'; -const ethWalletTotalAssociatedBalance = '[data-testid="currency-locked"]'; const vegaWalletAssociatedBalance = '[data-testid="currency-value"]'; const vegaWalletUnstakedBalance = '[data-testid="vega-wallet-balance-unstaked"]'; const txTimeout = Cypress.env('txTimeout'); const vegaWalletPublicKeyShort = Cypress.env('vegaWalletPublicKeyShort'); -const ethWalletAssociateButton = '[href="/token/associate"]'; +const ethWalletAssociateButton = '[data-testid="associate-btn"]'; const associateWalletRadioButton = '[data-testid="associate-radio-wallet"]'; const tokenAmountInputBox = '[data-testid="token-amount-input"]'; const tokenSubmitButton = '[data-testid="token-input-submit-button"]'; @@ -28,7 +46,7 @@ context( before('visit staking tab and connect vega wallet', function () { cy.visit('/'); // 0005-ETXN-001 - cy.vega_wallet_set_specified_approval_amount('1000'); + vegaWalletSetSpecifiedApprovalAmount('1000'); }); describe('Eth wallet - contains VEGA tokens', function () { @@ -36,11 +54,10 @@ context( 'teardown wallet & drill into a specific validator', function () { cy.reload(); - cy.wait_for_spinner(); - cy.ethereum_wallet_connect(); + waitForSpinner(); cy.connectVegaWallet(); - cy.vega_wallet_teardown(); - cy.navigate_to('validators'); + ethereumWalletConnect(); + vegaWalletTeardown(); } ); @@ -57,26 +74,21 @@ context( //0005-ETXN-006 //0005-ETXN-003 //0005-ETXN-005 - cy.staking_page_associate_tokens('2', { skipConfirmation: true }); + stakingPageAssociateTokens('2', { skipConfirmation: true }); cy.getByTestId('currency-title', txTimeout).should( 'have.length.above', 3 ); - cy.validate_wallet_currency('Associated', '0.00'); - cy.validate_wallet_currency('Pending association', '2.00'); - cy.validate_wallet_currency('Total associated after pending', '2.00'); + validateWalletCurrency('Associated', '0.00'); + validateWalletCurrency('Pending association', '2.00'); + validateWalletCurrency('Total associated after pending', '2.00'); cy.getByTestId('currency-title', txTimeout).should('have.length', 3); // 0005-ETXN-002 - cy.get(ethWalletAssociatedBalances, txTimeout) - .contains(vegaWalletPublicKeyShort) - .parent(txTimeout) - .should('contain', 2.0); + verifyEthWalletAssociatedBalance('2.0'); - cy.get(ethWalletTotalAssociatedBalance, txTimeout) - .contains('2.0', txTimeout) - .should('be.visible'); + verifyEthWalletTotalAssociatedBalance('2.0'); cy.get(vegaWallet).within(() => { cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0); @@ -92,50 +104,30 @@ context( // 1004-ASSO-029 // 1004-ASSO-031 - cy.staking_page_associate_tokens('2'); - - cy.get(ethWalletAssociatedBalances, txTimeout) - .contains(vegaWalletPublicKeyShort) - .parent(txTimeout) - .should('contain', 2.0); - - cy.get(ethWalletTotalAssociatedBalance, txTimeout) - .contains('2.0', txTimeout) - .should('be.visible'); - + stakingPageAssociateTokens('2'); + verifyEthWalletAssociatedBalance('2.0'); + verifyEthWalletTotalAssociatedBalance('2.0'); cy.get('button').contains('Select a validator to nominate').click(); - - cy.staking_page_disassociate_tokens('2'); - + stakingPageDisassociateTokens('2'); cy.getByTestId('currency-title', txTimeout).should( 'have.length.above', 3 ); - cy.validate_wallet_currency('Associated', '2.00'); - cy.validate_wallet_currency('Pending association', '2.00'); - cy.validate_wallet_currency('Total associated after pending', '0.00'); + validateWalletCurrency('Associated', '2.00'); + validateWalletCurrency('Pending association', '2.00'); + validateWalletCurrency('Total associated after pending', '0.00'); cy.getByTestId('currency-title', txTimeout).should('have.length', 3); - - cy.get(ethWalletAssociatedBalances, txTimeout).should('not.exist'); - - cy.get(ethWalletTotalAssociatedBalance, txTimeout) - .contains('0.00', txTimeout) - .should('be.visible'); + cy.getByTestId('eth-wallet-associated-balances', txTimeout).should( + 'not.exist' + ); + verifyEthWalletTotalAssociatedBalance('0.00'); }); it('Able to associate more tokens than the approved amount of 1000 - requires re-approval', function () { //1004-ASSO-011 - cy.staking_page_associate_tokens('1001', { approve: true }); - - cy.get(ethWalletAssociatedBalances, txTimeout) - .contains(vegaWalletPublicKeyShort) - .parent() - .should('contain', '1,001.00', txTimeout); - - cy.get(ethWalletTotalAssociatedBalance, txTimeout) - .contains('1,001.00', txTimeout) - .should('be.visible'); - + stakingPageAssociateTokens('1001', { approve: true }); + verifyEthWalletAssociatedBalance('1,001.00'); + verifyEthWalletTotalAssociatedBalance('1,001.00'); cy.get(vegaWallet).within(() => { cy.get(vegaWalletAssociatedBalance, txTimeout).should( 'contain', @@ -145,26 +137,14 @@ context( }); it('Able to disassociate a partial amount of tokens currently associated', function () { - cy.staking_page_associate_tokens('2'); - + stakingPageAssociateTokens('2'); cy.get(vegaWallet).within(() => { cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0); }); cy.get('button').contains('Select a validator to nominate').click(); - - cy.staking_page_disassociate_tokens('1'); - - cy.get(ethWalletAssociatedBalances, txTimeout) - .contains(vegaWalletPublicKeyShort) - .parent(txTimeout) - .should('contain', 1.0); - - cy.get(ethWalletAssociatedBalances, txTimeout) - .contains(vegaWalletPublicKeyShort) - .parent(txTimeout) - .should('contain', 1.0); - + stakingPageDisassociateTokens('1'); + verifyEthWalletAssociatedBalance('1.0'); cy.get(vegaWallet).within(() => { cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 1.0); }); @@ -174,32 +154,24 @@ context( // 1004-ASSO-026 const warningText = 'Warning: Any tokens that have been nominated to a node will sacrifice rewards they are due for the current epoch. If you do not wish to sacrifice these, you should remove stake from a node at the end of an epoch before disassociation.'; - - cy.staking_page_associate_tokens('2'); - + stakingPageAssociateTokens('2'); cy.get(vegaWallet).within(() => { cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0); }); - cy.get('button').contains('Select a validator to nominate').click(); - cy.get(ethWalletDissociateButton).click(); cy.get(disassociationWarning).should('contain', warningText); - - cy.staking_page_disassociate_all_tokens(); - + stakingPageDisassociateAllTokens(); cy.get(ethWalletContainer).within(() => { cy.contains(vegaWalletPublicKeyShort, { timeout: 20000 }).should( 'not.exist' ); }); - cy.get(ethWalletContainer).within(() => { cy.contains(vegaWalletPublicKeyShort, { timeout: 20000 }).should( 'not.exist' ); }); - cy.get(vegaWallet).within(() => { cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 0.0); }); @@ -212,7 +184,7 @@ context( // 1004-ASSO-024 // 1004-ASSO-023 - cy.staking_page_associate_tokens('2', { + stakingPageAssociateTokens('2', { type: 'contract', skipConfirmation: true, }); @@ -221,47 +193,30 @@ context( 'have.length.above', 3 ); - cy.validate_wallet_currency('Associated', '0.00'); - cy.validate_wallet_currency('Pending association', '2.00'); - cy.validate_wallet_currency('Total associated after pending', '2.00'); + validateWalletCurrency('Associated', '0.00'); + validateWalletCurrency('Pending association', '2.00'); + validateWalletCurrency('Total associated after pending', '2.00'); cy.getByTestId('currency-title', txTimeout).should('have.length', 3); - - cy.get(ethWalletAssociatedBalances, txTimeout) - .contains(vegaWalletPublicKeyShort) - .parent(txTimeout) - .should('contain', 2.0); - - cy.get(ethWalletTotalAssociatedBalance, txTimeout) - .contains('2.0', txTimeout) - .should('be.visible'); - + verifyEthWalletAssociatedBalance('2.0'); + verifyEthWalletTotalAssociatedBalance('2.0'); cy.get(vegaWallet).within(() => { cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0); }); - cy.get(vegaWalletUnstakedBalance, txTimeout).should('contain', 2.0); - cy.staking_page_disassociate_tokens('1', { + stakingPageDisassociateTokens('1', { type: 'contract', skipConfirmation: true, }); - cy.getByTestId('currency-title', txTimeout).should( 'have.length.above', 3 ); - cy.validate_wallet_currency('Associated', '2.00'); - cy.validate_wallet_currency('Pending association', '1.00'); - cy.validate_wallet_currency('Total associated after pending', '1.00'); + validateWalletCurrency('Associated', '2.00'); + validateWalletCurrency('Pending association', '1.00'); + validateWalletCurrency('Total associated after pending', '1.00'); cy.getByTestId('currency-title', txTimeout).should('have.length', 3); - - cy.get(ethWalletAssociatedBalances, txTimeout) - .contains(vegaWalletPublicKeyShort) - .parent(txTimeout) - .should('contain', 1.0); - - cy.get(ethWalletTotalAssociatedBalance, txTimeout) - .contains('1.0', txTimeout) - .should('be.visible'); + verifyEthWalletAssociatedBalance('1.0'); + verifyEthWalletTotalAssociatedBalance('1.0'); }); it('Able to associate & disassociate both wallet and vesting contract tokens', function () { @@ -269,11 +224,9 @@ context( // 1004-ASSO-020 // 1004-ASSO-021 // 1004-ASSO-022 - - cy.staking_page_associate_tokens('21', { type: 'wallet' }); + stakingPageAssociateTokens('21', { type: 'wallet' }); cy.get('button').contains('Select a validator to nominate').click(); - cy.staking_page_associate_tokens('37', { type: 'contract' }); - + stakingPageAssociateTokens('37', { type: 'contract' }); cy.get(vestingContractSection).within(() => { cy.get(associatedKey).should( 'contain', @@ -281,7 +234,6 @@ context( ); cy.get(associatedAmount, txTimeout).should('contain', 37); }); - cy.get(vegaInWalletSection).within(() => { cy.get(associatedKey).should( 'contain', @@ -289,27 +241,21 @@ context( ); cy.get(associatedAmount, txTimeout).should('contain', 21); }); - cy.get(vegaWallet).within(() => { cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 58); }); - - cy.staking_page_disassociate_tokens('6', { type: 'contract' }); + stakingPageDisassociateTokens('6', { type: 'contract' }); cy.get(vestingContractSection).within(() => { cy.get(associatedAmount, txTimeout).should('contain', 31); }); - cy.get(vegaWallet).within(() => { cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 52); }); - - cy.navigate_to('validators'); - - cy.staking_page_disassociate_tokens('9', { type: 'wallet' }); + navigateTo(navigation.validators); + stakingPageDisassociateTokens('9', { type: 'wallet' }); cy.get(vegaInWalletSection).within(() => { cy.get(associatedAmount, txTimeout).should('contain', 12); }); - cy.get(vegaWallet).within(() => { cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 43); }); @@ -319,42 +265,41 @@ context( // 1004-ASSO-008 // 1004-ASSO-010 // No warning visible as described in AC, but the button is disabled - cy.get(ethWalletAssociateButton).first().click(); cy.get(associateWalletRadioButton, { timeout: 30000 }).click(); cy.get(tokenSubmitButton, txTimeout).should('be.disabled'); // button disabled with no input - cy.get(tokenAmountInputBox, { timeout: 10000 }).type(6500000); + cy.get(tokenAmountInputBox, { timeout: 10000 }).type('6500000'); cy.get(tokenSubmitButton, txTimeout).should('be.disabled'); }); // 1004-ASSO-004 - it('Pending association outside of app is shown', function () { - cy.vega_wallet_associate('2'); + vegaWalletAssociate('2'); cy.getByTestId('currency-title', txTimeout).should( 'have.length.above', 3 ); - cy.validate_wallet_currency('Associated', '0.00'); - cy.validate_wallet_currency('Pending association', '2.00'); - cy.validate_wallet_currency('Total associated after pending', '2.00'); + validateWalletCurrency('Associated', '0.00'); + validateWalletCurrency('Pending association', '2.00'); + validateWalletCurrency('Total associated after pending', '2.00'); cy.getByTestId('currency-title', txTimeout).should('have.length', 3); - cy.validate_wallet_currency('Associated', '2.00'); + validateWalletCurrency('Associated', '2.00'); }); it('Disassociation outside of app is shown', function () { - cy.staking_page_associate_tokens('2'); - cy.validate_wallet_currency('Associated', '2.00'); - cy.vega_wallet_disassociate('2'); + stakingPageAssociateTokens('2'); + cy.wrap(validateWalletCurrency('Associated', '2.00')).then(() => { + vegaWalletDisassociate('2'); + }); cy.getByTestId('currency-title', txTimeout).should( 'have.length.above', 3 ); - cy.validate_wallet_currency('Associated', '2.00'); - cy.validate_wallet_currency('Pending association', '2.00'); - cy.validate_wallet_currency('Total associated after pending', '0.00'); + validateWalletCurrency('Associated', '2.00'); + validateWalletCurrency('Pending association', '2.00'); + validateWalletCurrency('Total associated after pending', '0.00'); cy.getByTestId('currency-title', txTimeout).should('have.length', 3); - cy.validate_wallet_currency('Associated', '0.00'); + validateWalletCurrency('Associated', '0.00'); }); it('Able to associate tokens to different public key of connected vega wallet', function () { @@ -371,7 +316,7 @@ context( 'have.text', Cypress.env('vegaWalletPublicKey2') ); - cy.staking_page_associate_tokens('2'); + stakingPageAssociateTokens('2'); cy.get(vegaWallet).within(() => { cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0); }); @@ -381,7 +326,7 @@ context( 'vegaWalletPublicKey2Short' )} can now participate in governance and nominate a validator with your associated $VEGA.` ); - cy.staking_page_disassociate_all_tokens(); + stakingPageDisassociateAllTokens(); }); }); } diff --git a/apps/governance-e2e/src/integration/flow/withdrawal-flow.cy.js b/apps/governance-e2e/src/integration/flow/withdrawal-flow.cy.ts similarity index 63% rename from apps/governance-e2e/src/integration/flow/withdrawal-flow.cy.js rename to apps/governance-e2e/src/integration/flow/withdrawal-flow.cy.ts index 19e77b260..ebd2f619b 100644 --- a/apps/governance-e2e/src/integration/flow/withdrawal-flow.cy.js +++ b/apps/governance-e2e/src/integration/flow/withdrawal-flow.cy.ts @@ -1,5 +1,16 @@ +import { + navigateTo, + navigation, + waitForSpinner, +} from '../../support/common.functions'; +import { ethereumWalletConnect } from '../../support/wallet-eth.functions'; +import { + depositAsset, + vegaWalletTeardown, +} from '../../support/wallet-teardown.functions'; + const withdraw = 'withdraw'; -const selectAsset = 'select-asset'; +const withdrawalForm = 'withdraw-form'; const ethAddressInput = 'eth-address-input'; const amountInput = 'amount-input'; const balanceAvailable = 'BALANCE_AVAILABLE_value'; @@ -17,6 +28,8 @@ const completeWithdrawalButton = 'complete-withdrawal'; const usdtName = 'USDC (local)'; const usdcEthAddress = '0x1b8a1B6CBE5c93609b46D1829Cc7f3Cb8eeE23a0'; const usdcSymbol = 'tUSDC'; +const usdtSelectValue = + '993ed98f4f770d91a796faab1738551193ba45c62341d20597df70fea6704ede'; const truncatedWithdrawalEthAddress = '0xEe7D…22d94F'; const formValidationError = 'input-error-text'; const txTimeout = Cypress.env('txTimeout'); @@ -26,60 +39,72 @@ context( { tags: '@slow' }, function () { before('visit withdrawals and connect vega wallet', function () { - cy.updateCapsuleMultiSig(); // When running tests locally, will fail if run without restarting capsule - cy.deposit_asset(usdcEthAddress, '100000000000000000000'); + cy.visit('/'); + // When running tests locally, will fail if run without restarting capsule + cy.updateCapsuleMultiSig().then(() => { + depositAsset(usdcEthAddress, '100'); + }); }); beforeEach('Navigate to withdrawal page', function () { cy.reload(); - cy.visit('/'); - cy.wait_for_spinner(); - cy.navigate_to('withdraw'); + waitForSpinner(); + navigateTo(navigation.withdraw); cy.connectVegaWallet(); - cy.ethereum_wallet_connect(); - cy.vega_wallet_teardown(); + ethereumWalletConnect(); + vegaWalletTeardown(); }); it('Able to open withdrawal form with vega wallet connected', function () { // needs to reload page for withdrawal form to be displayed in ci - not reproducible outside of ci + cy.reload(); + waitForSpinner(); + ethereumWalletConnect(); cy.getByTestId(withdraw).should('be.visible').click(); - cy.getByTestId(selectAsset) - .find('option') - .should('have.length.at.least', 2); - cy.getByTestId(ethAddressInput).should('be.visible'); - cy.getByTestId(amountInput).should('be.visible'); + cy.getByTestId(withdrawalForm).within(() => { + cy.get('select').find('option').should('have.length.at.least', 2); + cy.getByTestId(ethAddressInput).should('be.visible'); + cy.getByTestId(amountInput).should('be.visible'); + }); }); it('Unable to submit withdrawal with invalid fields', function () { cy.getByTestId(withdraw).should('be.visible').click(); - cy.getByTestId(selectAsset).select(usdtName); - cy.getByTestId(balanceAvailable, txTimeout).should('exist'); - cy.getByTestId(submitWithdrawalButton).click(); - cy.getByTestId(formValidationError).should('have.length', 1); - cy.getByTestId(amountInput).clear().click().type('0.0000001'); - cy.getByTestId(submitWithdrawalButton).click(); - cy.getByTestId(formValidationError).should( - 'have.text', - 'Value is below minimum' - ); - cy.getByTestId(amountInput).clear().click().type('10'); - cy.getByTestId(ethAddressInput).click().type('123'); - cy.getByTestId(submitWithdrawalButton).click(); - cy.getByTestId(formValidationError).should( - 'have.text', - 'Invalid Ethereum address' - ); + cy.getByTestId(withdrawalForm).within(() => { + cy.get('select').select(usdtSelectValue, { force: true }); + cy.getByTestId(balanceAvailable, txTimeout).should('exist'); + cy.getByTestId(submitWithdrawalButton).click(); + cy.getByTestId(formValidationError).should('have.length', 1); + cy.getByTestId(amountInput).clear().click().type('0.0000001'); + cy.getByTestId(submitWithdrawalButton).click(); + cy.getByTestId(formValidationError).should( + 'have.text', + 'Value is below minimum' + ); + cy.getByTestId(amountInput).clear().click().type('10'); + cy.getByTestId(ethAddressInput).click().type('123'); + cy.getByTestId(submitWithdrawalButton).click(); + cy.getByTestId(formValidationError).should( + 'have.text', + 'Invalid Ethereum address' + ); + }); }); it('Able to withdraw asset: -eth wallet connected -withdraw funds button', function () { // fill in withdrawal form cy.getByTestId(withdraw).should('be.visible').click(); - cy.getByTestId(selectAsset).select(usdtName); - cy.getByTestId(balanceAvailable, txTimeout).should('exist'); - cy.getByTestId(withdrawalThreshold).should('have.text', '100,000.00000T'); - cy.getByTestId(delayTime).should('have.text', 'None'); - cy.getByTestId(amountInput).click().type('100'); - cy.getByTestId(submitWithdrawalButton).click(); + cy.getByTestId(withdrawalForm).within(() => { + cy.get('select').select(usdtSelectValue, { force: true }); + cy.getByTestId(balanceAvailable, txTimeout).should('exist'); + cy.getByTestId(withdrawalThreshold).should( + 'have.text', + '100,000.00000T' + ); + cy.getByTestId(delayTime).should('have.text', 'None'); + cy.getByTestId(amountInput).click().type('100'); + cy.getByTestId(submitWithdrawalButton).click(); + }); cy.contains('Awaiting network confirmation').should('be.visible'); // assert withdrawal request @@ -136,15 +161,17 @@ context( waitForAssetsDisplayed(usdtName); // fill in withdrawal form cy.getByTestId(withdraw).should('be.visible').click(); - cy.getByTestId(selectAsset).select(usdtName); - cy.getByTestId(ethAddressInput).should('be.empty'); - cy.getByTestId(amountInput).click().type('100'); - cy.getByTestId(submitWithdrawalButton).click(); + cy.getByTestId(withdrawalForm).within(() => { + cy.get('select').select(usdtSelectValue, { force: true }); + cy.getByTestId(ethAddressInput).should('be.empty'); + cy.getByTestId(amountInput).click().type('100'); + cy.getByTestId(submitWithdrawalButton).click(); - // Need eth address to submit withdrawal - cy.getByTestId(formValidationError).should('have.length', 1); - cy.getByTestId(ethAddressInput).click().type(ethWalletAddress); - cy.getByTestId(submitWithdrawalButton).click(); + // Need eth address to submit withdrawal + cy.getByTestId(formValidationError).should('have.length', 1); + cy.getByTestId(ethAddressInput).click().type(ethWalletAddress); + cy.getByTestId(submitWithdrawalButton).click(); + }); cy.contains('Awaiting network confirmation').should('be.visible'); // assert withdrawal request @@ -180,10 +207,12 @@ context( cy.connectPublicKey(vegaWalletPubKey); cy.getByTestId(withdraw).should('be.visible').click(); - cy.getByTestId(selectAsset).select(usdtName); - cy.getByTestId(balanceAvailable, txTimeout).should('exist'); - cy.getByTestId(amountInput).click().type('100'); - cy.getByTestId(submitWithdrawalButton).click(); + cy.getByTestId(withdrawalForm).within(() => { + cy.get('select').select(usdtSelectValue, { force: true }); + cy.getByTestId(balanceAvailable, txTimeout).should('exist'); + cy.getByTestId(amountInput).click().type('100'); + cy.getByTestId(submitWithdrawalButton).click(); + }); cy.getByTestId('dialog-content').within(() => { cy.get('h1').should('have.text', 'Transaction failed'); @@ -191,7 +220,7 @@ context( }); }); - function waitForAssetsDisplayed(expectedAsset) { + function waitForAssetsDisplayed(expectedAsset: string) { cy.contains(expectedAsset, txTimeout).should('be.visible'); } } diff --git a/apps/governance-e2e/src/integration/view/home.cy.js b/apps/governance-e2e/src/integration/view/home.cy.ts similarity index 70% rename from apps/governance-e2e/src/integration/view/home.cy.js rename to apps/governance-e2e/src/integration/view/home.cy.ts index b8098133d..0cce3da85 100644 --- a/apps/governance-e2e/src/integration/view/home.cy.js +++ b/apps/governance-e2e/src/integration/view/home.cy.ts @@ -1,3 +1,5 @@ +import { waitForSpinner } from '../../support/common.functions'; + context('Home Page - verify elements on page', { tags: '@smoke' }, function () { before('visit token home page', function () { cy.visit('/'); @@ -18,7 +20,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () { if (!$body.find('[data-testid="proposals-list-item"]').length) { cy.createMarket(); cy.reload(); - cy.wait_for_spinner(); + waitForSpinner(); } }); cy.getByTestId('proposals-list-item') @@ -107,5 +109,56 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () { }); }); }); + + describe('Mobile view - navigation bar', function () { + before('Change to mobile resolution', function () { + cy.viewport('iphone-xr'); + }); + + it('should have burger button', () => { + cy.getByTestId('button-menu-drawer').should('be.visible').click(); + cy.getByTestId('menu-drawer').should('be.visible'); + }); + + it('should have link for proposal page', function () { + cy.getByTestId('menu-drawer').within(() => { + cy.get('[href="/proposals"]') + .should('exist') + .and('have.text', 'Proposals'); + }); + }); + it('should have link for validator page', function () { + cy.getByTestId('menu-drawer').within(() => { + cy.get('[href="/validators"]') + .first() + .should('exist') + .and('have.text', 'Validators'); + }); + }); + + it('should have link for rewards page', function () { + cy.getByTestId('menu-drawer').within(() => { + cy.get('[href="/rewards"]') + .first() + .should('exist') + .and('have.text', 'Rewards'); + }); + }); + it('should have link for withdrawal page', function () { + cy.getByTestId('menu-drawer').within(() => { + cy.get('[href="/token/withdraw"]') + .first() + .should('exist') + .and('have.text', 'Withdraw'); + }); + }); + + after(function () { + cy.viewport( + Cypress.config('viewportWidth'), + Cypress.config('viewportHeight') + ); + }); + }); }); }); diff --git a/apps/governance-e2e/src/integration/view/pages.cy.js b/apps/governance-e2e/src/integration/view/pages.cy.js deleted file mode 100644 index 637da486b..000000000 --- a/apps/governance-e2e/src/integration/view/pages.cy.js +++ /dev/null @@ -1,284 +0,0 @@ -context( - 'Landing pages - verifies required elements', - { tags: '@smoke' }, - () => { - const navbar = 'nav .navbar'; - const mobileNav = '[data-testid="menu-drawer"]'; - - const topLevelLinks = [ - { - name: 'Proposals', - selector: '[href="/proposals"]', - tests: () => { - it('should be able to see a working link for - find out more about Vega governance', function () { - const governanceDocsUrl = 'https://vega.xyz/governance'; - const proposalDocumentationLink = - '[data-testid="proposal-documentation-link"]'; - // 3001-VOTE-001 - cy.get(proposalDocumentationLink) - .should('be.visible') - .and('have.text', 'Find out more about Vega governance') - .and('have.attr', 'href') - .and('equal', governanceDocsUrl); - - // 3002-PROP-001 - cy.request(governanceDocsUrl) - .its('body') - .then((body) => { - if (!body.includes('Govern the network')) { - assert.include( - body, - 'Govern the network', - `Checking that governance link destination includes 'Govern the network' text` - ); - } - }); - }); - - it('should be able to see button for - new proposal', function () { - // 3001-VOTE-002 - const newProposalLink = '[data-testid="new-proposal-link"]'; - cy.get(newProposalLink) - .should('be.visible') - .and('have.text', 'New proposal') - .and('have.attr', 'href') - .and('equal', '/proposals/propose'); - }); - }, - }, - { - name: 'Validators', - selector: '[href="/validators"]', - tests: () => { - it('Should have Staking Guide link visible', function () { - // 2001-STKE-003 - cy.get('[data-testid="staking-guide-link"]') - .should('be.visible') - .and('have.text', 'Read more about staking on Vega') - .and( - 'have.attr', - 'href', - 'https://docs.vega.xyz/mainnet/concepts/vega-chain/#staking-on-vega' - ); - }); - }, - }, - { - name: 'Rewards', - selector: '[href="/rewards"]', - header: 'Rewards and fees', - tests: () => { - it('should have epoch warning', () => { - cy.get('[data-testid="callout"]') - .should('be.visible') - .and( - 'have.text', - 'Rewards are credited less than a minute after the epoch ends.This delay is set by a network parameter' - ); - }); - it('should have toggle for seeing total vs individual rewards', () => { - cy.get('[data-testid="epoch-reward-view-toggle-total"]').should( - 'be.visible' - ); - }); - }, - }, - ]; - - const secondLevelLinks = [ - { - trigger: true, - name: 'Token', - selector: '[data-testid="state-trigger"]', - }, - { - name: 'Token', - selector: '[href="/token"]', - header: 'The $VEGA token', - }, - { - name: 'Supply & Vesting', - selector: '[href="/token/tranches"]', - header: 'Vesting tranches', - }, - { - name: 'Withdraw', - selector: '[href="/token/withdraw"]', - header: 'Withdrawals', - tests: () => { - it('should have connect Vega wallet button', function () { - cy.get('[data-testid="connect-to-vega-wallet-btn"]') - .should('be.visible') - .and('have.text', 'Connect Vega wallet'); - }); - }, - }, - { - name: 'Redeem', - selector: '[href="/token/redeem"]', - header: 'Vesting', - tests: () => { - // 1005-VEST-018 - it('should have connect Eth wallet button', function () { - cy.get('[data-testid="connect-to-eth-btn"]') - .should('be.visible') - .and('have.text', 'Connect Ethereum wallet'); - }); - }, - }, - { - name: 'Associate', - selector: '[href="/token/associate"]', - header: 'Associate $VEGA tokens with Vega Key', - }, - { - name: 'Disassociate', - selector: '[href="/token/disassociate"]', - header: 'Disassociate $VEGA tokens from a Vega key', - }, - ]; - - const expand = () => { - const trigger = secondLevelLinks.find((l) => l.trigger).selector; - cy.get(trigger).then((el) => { - if (el.attr('aria-expanded') === 'false') { - el.trigger('click'); - } - }); - }; - - const collapse = () => { - const trigger = secondLevelLinks.find((l) => l.trigger).selector; - cy.get(trigger).then((el) => { - if (el.attr('aria-expanded') === 'true') { - el.trigger('click'); - } - }); - }; - - const ensureHeader = (text) => { - cy.get('main header h1').should('have.text', text); - }; - - before(() => { - // goes to HOME - cy.visit('/'); - // and waits for it to load - cy.get(navbar, { timeout: 10000 }).should('be.visible'); - }); - - describe('Navigation (desktop)', () => { - for (const { name, selector } of topLevelLinks) { - it(`should have ${name} nav link`, () => { - cy.get(navbar).within(() => { - cy.get(selector).should('be.visible'); - cy.get(selector).should('have.text', name); - }); - }); - } - - for (const { name, selector, trigger } of secondLevelLinks) { - it(`should have ${name} ${ - trigger ? 'as trigger button' : '' - } second level nav link`, () => { - cy.get(navbar).within(() => { - cy.get(selector).should('be.visible'); - cy.get(selector).should('have.text', name); - if (trigger) cy.get(selector).click(); - }); - }); - } - - after(() => { - collapse(); - }); - }); - - describe('Navigation (mobile)', () => { - beforeEach(() => { - // iphone xr - cy.viewport(414, 896); - }); - - it('should have burger button', () => { - cy.get('[data-testid="button-menu-drawer"]').should('be.visible'); - cy.get('[data-testid="button-menu-drawer"]').click(); - cy.get(mobileNav).should('be.visible'); - }); - - for (const { name, selector } of topLevelLinks) { - it(`should have ${name} nav link`, () => { - cy.get(mobileNav).within(() => { - cy.get(selector).should('be.visible'); - cy.get(selector).should('have.text', name); - }); - }); - } - - for (const { name, selector, trigger } of secondLevelLinks) { - it(`should have ${name} ${ - trigger ? 'as trigger button' : '' - } second level nav link`, () => { - cy.get(mobileNav).within(() => { - cy.get(selector).should('be.visible'); - cy.get(selector).should('have.text', name); - }); - }); - } - - after(() => { - cy.get('[data-testid="button-menu-drawer"]').click(); - cy.viewport( - Cypress.config('viewportWidth'), - Cypress.config('viewportHeight') - ); - }); - }); - - describe('Elements', () => { - for (const { name, selector, header, tests } of topLevelLinks) { - describe(`${name} page`, () => { - it(`navigates to ${name}`, () => { - cy.get(navbar).within(() => { - cy.log(`goes to ${name}`); - cy.get(selector).click(); - cy.log(`ensures ${name} is highlighted`); - cy.get(selector).should('have.attr', 'aria-current'); - }); - }); - it('displays header', () => { - ensureHeader(header || name); - }); - - if (tests) tests.apply(this); - }); - } - - for (const { name, selector, header, tests } of secondLevelLinks.filter( - (l) => !l.trigger - )) { - describe(`${name} page`, () => { - it(`navigates to ${name}`, () => { - cy.get(navbar).within(() => { - expand(); - cy.log(`goes to ${name}`); - cy.get(selector).click(); - expand(); - cy.log(`ensures ${name} is highlighted`); - cy.get(selector).should('have.attr', 'aria-current'); - }); - }); - it('displays header', () => { - ensureHeader(header || name); - }); - - if (tests) tests.apply(this); - }); - } - - after(() => { - collapse(); - }); - }); - } -); diff --git a/apps/governance-e2e/src/integration/view/proposal.cy.ts b/apps/governance-e2e/src/integration/view/proposal.cy.ts new file mode 100644 index 000000000..cf13f0a2b --- /dev/null +++ b/apps/governance-e2e/src/integration/view/proposal.cy.ts @@ -0,0 +1,77 @@ +import { + navigateTo, + navigation, + verifyPageHeader, + verifyTabHighlighted, + waitForSpinner, +} from '../../support/common.functions'; + +const proposalDocumentationLink = '[data-testid="proposal-documentation-link"]'; +const newProposalButton = '[data-testid="new-proposal-link"]'; +const newProposalLink = '[data-testid="new-proposal-link"]'; +const governanceDocsUrl = 'https://vega.xyz/governance'; +const connectToVegaWalletButton = '[data-testid="connect-to-vega-wallet-btn"]'; + +context( + 'Governance Page - verify elements on page', + { tags: '@smoke' }, + function () { + before('navigate to governance page', function () { + cy.visit('/'); + navigateTo(navigation.proposals); + }); + + describe('with no network change proposals', function () { + it('should have governance tab highlighted', function () { + verifyTabHighlighted(navigation.proposals); + }); + + it('should have GOVERNANCE header visible', function () { + verifyPageHeader('Proposals'); + }); + + it('should be able to see a working link for - find out more about Vega governance', function () { + // 3001-VOTE-001 + cy.get(proposalDocumentationLink) + .should('be.visible') + .and('have.text', 'Find out more about Vega governance') + .and('have.attr', 'href') + .and('equal', governanceDocsUrl); + + // 3002-PROP-001 + cy.request(governanceDocsUrl) + .its('body') + .then((body) => { + if (!body.includes('Govern the network')) { + assert.include( + body, + 'Govern the network', + `Checking that governance link destination includes 'Govern the network' text` + ); + } + }); + }); + + it('should be able to see button for - new proposal', function () { + // 3001-VOTE-002 + cy.get(newProposalLink) + .should('be.visible') + .and('have.text', 'New proposal') + .and('have.attr', 'href') + .and('equal', '/proposals/propose'); + }); + + // Skipping this test for now, the new proposal button no longer takes a user directly + // to a proposal form, instead it takes them to a page where they can select a proposal type. + // Keeping this test here for now as it can be repurposed to test the new proposal forms. + it.skip('should be able to see a connect wallet button - if vega wallet disconnected and new proposal button selected', function () { + cy.get(newProposalButton).should('be.visible').click(); + cy.get(connectToVegaWalletButton) + .should('be.visible') + .and('have.text', 'Connect Vega wallet'); + navigateTo(navigation.proposals); + waitForSpinner(); + }); + }); + } +); diff --git a/apps/governance-e2e/src/integration/view/pubkey-view.cy.js b/apps/governance-e2e/src/integration/view/pubkey-view.cy.ts similarity index 71% rename from apps/governance-e2e/src/integration/view/pubkey-view.cy.js rename to apps/governance-e2e/src/integration/view/pubkey-view.cy.ts index 6dc896025..fe668ff62 100644 --- a/apps/governance-e2e/src/integration/view/pubkey-view.cy.js +++ b/apps/governance-e2e/src/integration/view/pubkey-view.cy.ts @@ -1,29 +1,36 @@ /// + +import { + navigateTo, + navigation, + waitForSpinner, +} from '../../support/common.functions'; +import { + enterUniqueFreeFormProposalBody, + goToMakeNewProposal, +} from '../../support/governance.functions'; +import { vegaWalletFaucetAssetsWithoutCheck } from '../../support/wallet-vega.functions'; + const vegaWalletPubKey = Cypress.env('vegaWalletPublicKey2'); const vegaPubkeyTruncated = Cypress.env('vegaWalletPublicKey2Short'); const banner = 'view-banner'; context('View functionality with public key', { tags: '@smoke' }, function () { before('send asset to wallet', function () { - cy.vega_wallet_faucet_assets_without_check( - 'fUSDC', - '1000000', - vegaWalletPubKey - ); + vegaWalletFaucetAssetsWithoutCheck('fUSDC', '1000000', vegaWalletPubKey); }); beforeEach('visit home page', function () { cy.visit('/'); - cy.wait_for_spinner(); + waitForSpinner(); cy.connectPublicKey(vegaWalletPubKey); }); it('Able to connect public key via wallet', function () { verifyConnectedToPubKey(); - cy.getByTestId('currency-title', Cypress.env('epochTimeout')).should( - 'contain.text', - 'USDC (fake)' - ); + cy.getByTestId('currency-title', { timeout: 10000 }) + .should('have.length.at.least', 4) + .and('contain.text', 'USDC (fake)'); }); it('Able to connect public key using url', function () { @@ -35,9 +42,9 @@ context('View functionality with public key', { tags: '@smoke' }, function () { it('Unable to submit proposal with public key', function () { const expectedErrorTxt = `You are connected in a view only state for public key: ${vegaWalletPubKey}. In order to send transactions you must connect to a real wallet.`; - cy.navigate_to('proposals'); - cy.go_to_make_new_proposal('Freeform'); - cy.enter_unique_freeform_proposal_body('50', 'pub key proposal test'); + navigateTo(navigation.proposals); + goToMakeNewProposal('Freeform'); + enterUniqueFreeFormProposalBody('50', 'pub key proposal test'); cy.getByTestId('dialog-content').within(() => { cy.get('h1').should('have.text', 'Transaction failed'); cy.getByTestId('Error').should('have.text', expectedErrorTxt); diff --git a/apps/governance-e2e/src/integration/view/rewards.cy.ts b/apps/governance-e2e/src/integration/view/rewards.cy.ts new file mode 100644 index 000000000..d7f0aaa4b --- /dev/null +++ b/apps/governance-e2e/src/integration/view/rewards.cy.ts @@ -0,0 +1,42 @@ +import { + navigateTo, + navigation, + verifyPageHeader, +} from '../../support/common.functions'; + +const viewToggle = '[data-testid="epoch-reward-view-toggle-total"]'; +const warning = '[data-testid="callout"]'; + +context( + 'Rewards Page - verify elements on page', + { tags: '@regression' }, + function () { + before('navigate to rewards page', function () { + cy.visit('/'); + navigateTo(navigation.rewards); + }); + + describe('with wallets disconnected', function () { + it('should have REWARDS tab highlighted', function () { + verifyPageHeader('Rewards and fees'); + }); + + it('should have rewards header visible', function () { + verifyPageHeader('Rewards and fees'); + }); + + it('should have epoch warning', function () { + cy.get(warning) + .should('be.visible') + .and( + 'have.text', + 'Rewards are credited less than a minute after the epoch ends.This delay is set by a network parameter' + ); + }); + + it('should have toggle for seeing total vs individual rewards', function () { + cy.get(viewToggle).should('be.visible'); + }); + }); + } +); diff --git a/apps/governance-e2e/src/integration/view/token.cy.js b/apps/governance-e2e/src/integration/view/token.cy.ts similarity index 96% rename from apps/governance-e2e/src/integration/view/token.cy.js rename to apps/governance-e2e/src/integration/view/token.cy.ts index ddf999f8d..7631dc0e4 100644 --- a/apps/governance-e2e/src/integration/view/token.cy.js +++ b/apps/governance-e2e/src/integration/view/token.cy.ts @@ -1,3 +1,5 @@ +import { navigateTo, navigation } from '../../support/common.functions'; + const tokenDetailsTable = '.token-details'; const address = '[data-testid="token-address"]'; const contract = '[data-testid="token-contract"]'; @@ -17,7 +19,8 @@ const vegaTokenContractAddress = Cypress.env('vegaTokenContractAddress'); context('Verify elements on Token page', { tags: '@smoke' }, function () { before('Visit token page', function () { - cy.visit('/token'); + cy.visit('/'); + navigateTo(navigation.token); }); describe('THE $VEGA TOKEN table', function () { it('should have TOKEN ADDRESS', function () { diff --git a/apps/governance-e2e/src/integration/view/tranches.cy.js b/apps/governance-e2e/src/integration/view/tranches.cy.ts similarity index 89% rename from apps/governance-e2e/src/integration/view/tranches.cy.js rename to apps/governance-e2e/src/integration/view/tranches.cy.ts index eef33a187..75ee6dcd8 100644 --- a/apps/governance-e2e/src/integration/view/tranches.cy.js +++ b/apps/governance-e2e/src/integration/view/tranches.cy.ts @@ -1,4 +1,5 @@ import { trancheData } from '../../fixtures/mocks/tranches'; +import { navigateTo, navigation } from '../../support/common.functions'; const tranches = trancheData; @@ -8,7 +9,13 @@ context( function () { before('visit homepage', function () { cy.intercept('GET', '**/tranches/stats', { tranches }); - cy.visit('/token/tranches'); + cy.visit('/'); + }); + + it('Able to navigate to tranches page', function () { + navigateTo(navigation.supply); + cy.url().should('include', '/token/tranches'); + cy.get('h1').should('contain.text', 'Vesting tranches'); }); // 1005-VEST-001 @@ -62,7 +69,7 @@ context( }); it('Able to view tranches with less than 10 vega', function () { - cy.navigate_to('supply'); + navigateTo(navigation.supply); cy.getByTestId('show-all-tranches').click(); cy.getByTestId('tranche-item') .should('have.length', 8) diff --git a/apps/governance-e2e/src/integration/view/validators.cy.js b/apps/governance-e2e/src/integration/view/validators.cy.js deleted file mode 100644 index 47a3b853b..000000000 --- a/apps/governance-e2e/src/integration/view/validators.cy.js +++ /dev/null @@ -1,210 +0,0 @@ -/// -const validatorTitle = '[data-testid="validator-node-title"]'; -const validatorId = '[data-testid="validator-id"]'; -const validatorPubKey = '[data-testid="validator-public-key"]'; -const ethAddressLink = '[data-testid="link"]'; -const validatorStatus = '[data-testid="validator-status"]'; -const totalStake = '[data-testid="total-stake"]'; -const pendingStake = '[data-testid="pending-stake"]'; -const stakedByOperator = '[data-testid="staked-by-operator"]'; -const stakedByDelegates = '[data-testid="staked-by-delegates"]'; -const stakeShare = '[data-testid="stake-percentage"]'; -const stakedByOperatorToolTip = "[data-testid='staked-operator-tooltip']"; -const stakedByDelegatesToolTip = "[data-testid='staked-delegates-tooltip']"; -const totalStakedToolTip = "[data-testid='total-staked-tooltip']"; -const unnormalisedVotingPowerToolTip = - "[data-testid='unnormalised-voting-power-tooltip']"; -const normalisedVotingPowerToolTip = - "[data-testid='normalised-voting-power-tooltip']"; -const performancePenaltyToolTip = "[data-testid='performance-penalty-tooltip']"; -const overstakedPenaltyToolTip = "[data-testid='overstaked-penalty-tooltip']"; -const totalPenaltyToolTip = "[data-testid='total-penalty-tooltip']"; -const epochCountDown = '[data-testid="epoch-countdown"]'; -const stakeNumberRegex = /^\d*\.?\d*$/; - -context('Staking Page - verify elements on page', function () { - before('navigate to staking page', function () { - cy.visit('/validators'); - }); - - describe( - 'Should be able to see validator list from the staking page', - { tags: '@regression' }, - function () { - // 2001-STKE-050 - it('Should be able to see validator names', function () { - cy.get('[col-id="validator"] > div > span') - .should('have.length.at.least', 1) - .each(($name) => { - cy.wrap($name).should('not.be.empty'); - }); - }); - - it('Should be able to see validator stake', function () { - cy.get('[col-id="stake"] > div > span > span') - .should('have.length.at.least', 1) - .each(($stake) => { - cy.wrap($stake).should('not.be.empty'); - }); - }); - - it('Should be able to see validator stake tooltip', function () { - cy.get('[col-id="stake"] > div > span > span').first().realHover(); - - cy.get(stakedByOperatorToolTip) - .invoke('text') - .should('contain', 'Staked by operator: 0.00'); - cy.get(stakedByDelegatesToolTip) - .invoke('text') - .should('contain', 'Staked by delegates: 0.00'); - cy.get(totalStakedToolTip) - .invoke('text') - .should('contain', 'Total stake: 0.00'); - }); - - it('Should be able to see validator normalised voting power', function () { - cy.get('[col-id="normalisedVotingPower"] > div > span > span') - .should('have.length.at.least', 1) - .each(($vPower) => { - cy.wrap($vPower).should('not.be.empty'); - }); - }); - - it('Should be able to see validator voting power tooltip', function () { - cy.get('[col-id="normalisedVotingPower"] > div > span > span') - .first() - .realHover(); - - cy.get(unnormalisedVotingPowerToolTip) - .invoke('text') - .should('contain', 'Unnormalised voting power: 0.00%'); - cy.get(normalisedVotingPowerToolTip) - .invoke('text') - .should('contain', 'Normalised voting power: 0.10%'); - }); - - // 2002-SINC-018 - it('Should be able to see validator total penalties', function () { - cy.get('[col-id="totalPenalties"] > div > span > span') - .should('have.length.at.least', 1) - .each(($penalties) => { - cy.wrap($penalties).should('contain.text', '0%'); - }); - }); - - it('Should be able to see validator penalties tooltip', function () { - cy.get('[col-id="totalPenalties"] > div > span > span').realHover(); - - cy.get(performancePenaltyToolTip) - .invoke('text') - .should('contain', 'Performance penalty: 100.00%'); - cy.get(overstakedPenaltyToolTip) - .invoke('text') - .should('contain', 'Overstaked penalty:'); // value not asserted due to #2886 - cy.get(totalPenaltyToolTip) - .invoke('text') - .should('contain', 'Total penalties: 0.00%'); - }); - - it('Should be able to see validator pending stake', function () { - cy.get('[col-id="pendingStake"] > div > span') - .should('have.length.at.least', 1) - .each(($pendingStake) => { - cy.wrap($pendingStake).should('contain.text', '0.00'); - }); - }); - } - ); - - // 2001-STKE-050 - describe( - 'Should be able to see static information about a validator', - { tags: '@smoke' }, - function () { - before('connect wallets and click on validator', function () { - cy.connectVegaWallet(); - cy.click_on_validator_from_list(0); - }); - - // 2001-STKE-006 - it('Should be able to see validator name', function () { - cy.get(validatorTitle).should('not.be.empty'); - }); - - // 2001-STKE-007 - it('Should be able to see validator id', function () { - cy.get(validatorId).should('not.be.empty'); - }); - - // 2001-STKE-008 - it('Should be able to see validator public key', function () { - cy.get(validatorPubKey).should('not.be.empty'); - }); - - // 2001-STKE-010 - it('Should be able to see Ethereum address', function () { - cy.get(ethAddressLink).should('not.be.empty').and('have.attr', 'href'); - }); - // TODO validators missing url for more information about them 2001-STKE-09 - - it('Should be able to see validator status', function () { - cy.get(validatorStatus).should('have.text', 'Consensus'); - }); - - // 2001-STKE-012 - it('Should be able to see total stake', function () { - cy.get(totalStake).invoke('text').should('match', stakeNumberRegex); - }); - - it('Should be able to see pending stake', function () { - cy.get(pendingStake).invoke('text').should('match', stakeNumberRegex); - }); - - it('Should be able to see staked by operator', function () { - cy.get(stakedByOperator) - .invoke('text') - .should('match', stakeNumberRegex); - }); - - it('Should be able to see staked by delegates', function () { - cy.get(stakedByDelegates) - .invoke('text') - .should('match', stakeNumberRegex); - }); - - // 2001-STKE-051 - it('Should be able to see stake share in percentage', function () { - cy.get(stakeShare) - .invoke('text') - .then(($stakePercentage) => { - // The pattern must start at a word boundary (\b). - // The pattern cannot be immediately preceded by a dot ((? { - cy.get(epochTitle).should('not.be.empty'); - cy.get(nextEpochInfo).should('contain.text', 'Next epoch'); - }); - }); - } - ); -}); diff --git a/apps/governance-e2e/src/integration/view/validators.cy.ts b/apps/governance-e2e/src/integration/view/validators.cy.ts new file mode 100644 index 000000000..40a8ed437 --- /dev/null +++ b/apps/governance-e2e/src/integration/view/validators.cy.ts @@ -0,0 +1,246 @@ +/// + +import { + navigateTo, + navigation, + verifyPageHeader, + verifyTabHighlighted, +} from '../../support/common.functions'; +import { clickOnValidatorFromList } from '../../support/staking.functions'; + +const guideLink = '[data-testid="staking-guide-link"]'; +const validatorTitle = '[data-testid="validator-node-title"]'; +const validatorId = '[data-testid="validator-id"]'; +const validatorPubKey = '[data-testid="validator-public-key"]'; +const ethAddressLink = '[data-testid="link"]'; +const validatorStatus = '[data-testid="validator-status"]'; +const totalStake = '[data-testid="total-stake"]'; +const pendingStake = '[data-testid="pending-stake"]'; +const stakedByOperator = '[data-testid="staked-by-operator"]'; +const stakedByDelegates = '[data-testid="staked-by-delegates"]'; +const stakeShare = '[data-testid="stake-percentage"]'; +const stakedByOperatorToolTip = '[data-testid="staked-operator-tooltip"]'; +const stakedByDelegatesToolTip = '[data-testid="staked-delegates-tooltip"]'; +const totalStakedToolTip = '[data-testid="total-staked-tooltip"]'; +const unnormalisedVotingPowerToolTip = + '[data-testid="unnormalised-voting-power-tooltip"]'; +const normalisedVotingPowerToolTip = + '[data-testid="normalised-voting-power-tooltip"]'; +const performancePenaltyToolTip = '[data-testid="performance-penalty-tooltip"]'; +const overstakedPenaltyToolTip = '[data-testid="overstaked-penalty-tooltip"]'; +const totalPenaltyToolTip = '[data-testid="total-penalty-tooltip"]'; +const epochCountDown = '[data-testid="epoch-countdown"]'; +const stakeNumberRegex = /^\d*\.?\d*$/; + +context('Validators Page - verify elements on page', function () { + before('navigate to validators page', function () { + cy.visit('/'); + navigateTo(navigation.validators); + }); + + describe('with wallets disconnected', { tags: '@smoke' }, function () { + describe('description section', function () { + it('Should have validators tab highlighted', function () { + verifyTabHighlighted(navigation.validators); + }); + + it('Should have validators ON VEGA header visible', function () { + verifyPageHeader('Validators'); + }); + + it('Should have Staking Guide link visible', function () { + // 2001-STKE-003 + cy.get(guideLink) + .should('be.visible') + .and('have.text', 'Read more about staking on Vega') + .and( + 'have.attr', + 'href', + 'https://docs.vega.xyz/mainnet/concepts/vega-chain/#staking-on-vega' + ); + }); + }); + describe( + 'Should be able to see validator list from the staking page', + { tags: '@regression' }, + function () { + // 2001-STKE-050 + it('Should be able to see validator names', function () { + cy.get('[col-id="validator"] > div > span') + .should('have.length.at.least', 1) + .each(($name) => { + cy.wrap($name).should('not.be.empty'); + }); + }); + + it('Should be able to see validator stake', function () { + cy.get('[col-id="stake"] > div > span > span') + .should('have.length.at.least', 1) + .each(($stake) => { + cy.wrap($stake).should('not.be.empty'); + }); + }); + + it('Should be able to see validator stake tooltip', function () { + cy.get('[col-id="stake"] > div > span > span').first().realHover(); + + cy.get(stakedByOperatorToolTip) + .invoke('text') + .should('contain', 'Staked by operator: 0.00'); + cy.get(stakedByDelegatesToolTip) + .invoke('text') + .should('contain', 'Staked by delegates: 0.00'); + cy.get(totalStakedToolTip) + .invoke('text') + .should('contain', 'Total stake: 0.00'); + }); + + it('Should be able to see validator normalised voting power', function () { + cy.get('[col-id="normalisedVotingPower"] > div > span > span') + .should('have.length.at.least', 1) + .each(($vPower) => { + cy.wrap($vPower).should('not.be.empty'); + }); + }); + + it('Should be able to see validator voting power tooltip', function () { + cy.get('[col-id="normalisedVotingPower"] > div > span > span') + .first() + .realHover(); + + cy.get(unnormalisedVotingPowerToolTip) + .invoke('text') + .should('contain', 'Unnormalised voting power: 0.00%'); + cy.get(normalisedVotingPowerToolTip) + .invoke('text') + .should('contain', 'Normalised voting power: 0.10%'); + }); + + // 2002-SINC-018 + it('Should be able to see validator total penalties', function () { + cy.get('[col-id="totalPenalties"] > div > span > span') + .should('have.length.at.least', 1) + .each(($penalties) => { + cy.wrap($penalties).should('contain.text', '0%'); + }); + }); + + it('Should be able to see validator penalties tooltip', function () { + cy.get('[col-id="totalPenalties"] > div > span > span').realHover(); + + cy.get(performancePenaltyToolTip) + .invoke('text') + .should('contain', 'Performance penalty: 100.00%'); + cy.get(overstakedPenaltyToolTip) + .invoke('text') + .should('contain', 'Overstaked penalty:'); // value not asserted due to #2886 + cy.get(totalPenaltyToolTip) + .invoke('text') + .should('contain', 'Total penalties: 0.00%'); + }); + + it('Should be able to see validator pending stake', function () { + cy.get('[col-id="pendingStake"] > div > span') + .should('have.length.at.least', 1) + .each(($pendingStake) => { + cy.wrap($pendingStake).should('contain.text', '0.00'); + }); + }); + } + ); + + // 2001-STKE-050 + describe( + 'Should be able to see static information about a validator', + { tags: '@smoke' }, + function () { + before('connect wallets and click on validator', function () { + cy.connectVegaWallet(); + clickOnValidatorFromList(0); + }); + + // 2001-STKE-006 + it('Should be able to see validator name', function () { + cy.get(validatorTitle).should('not.be.empty'); + }); + + // 2001-STKE-007 + it('Should be able to see validator id', function () { + cy.get(validatorId).should('not.be.empty'); + }); + + // 2001-STKE-008 + it('Should be able to see validator public key', function () { + cy.get(validatorPubKey).should('not.be.empty'); + }); + + // 2001-STKE-010 + it('Should be able to see Ethereum address', function () { + cy.get(ethAddressLink) + .should('not.be.empty') + .and('have.attr', 'href'); + }); + // TODO validators missing url for more information about them 2001-STKE-09 + + it('Should be able to see validator status', function () { + cy.get(validatorStatus).should('have.text', 'Consensus'); + }); + + // 2001-STKE-012 + it('Should be able to see total stake', function () { + cy.get(totalStake).invoke('text').should('match', stakeNumberRegex); + }); + + it('Should be able to see pending stake', function () { + cy.get(pendingStake).invoke('text').should('match', stakeNumberRegex); + }); + + it('Should be able to see staked by operator', function () { + cy.get(stakedByOperator) + .invoke('text') + .should('match', stakeNumberRegex); + }); + + it('Should be able to see staked by delegates', function () { + cy.get(stakedByDelegates) + .invoke('text') + .should('match', stakeNumberRegex); + }); + + // 2001-STKE-051 + it('Should be able to see stake share in percentage', function () { + cy.get(stakeShare) + .invoke('text') + .then(($stakePercentage) => { + // The pattern must start at a word boundary (\b). + // The pattern cannot be immediately preceded by a dot ((? { + cy.get(epochTitle).should('not.be.empty'); + cy.get(nextEpochInfo).should('contain.text', 'Next epoch'); + }); + }); + } + ); + }); +}); diff --git a/apps/governance-e2e/src/integration/view/vesting.cy.js b/apps/governance-e2e/src/integration/view/vesting.cy.ts similarity index 82% rename from apps/governance-e2e/src/integration/view/vesting.cy.js rename to apps/governance-e2e/src/integration/view/vesting.cy.ts index c6f8c3d63..82f6ff113 100644 --- a/apps/governance-e2e/src/integration/view/vesting.cy.js +++ b/apps/governance-e2e/src/integration/view/vesting.cy.ts @@ -1,3 +1,12 @@ +import { + navigateTo, + navigation, + verifyPageHeader, + verifyTabHighlighted, +} from '../../support/common.functions'; +import { ethereumWalletConnect } from '../../support/wallet-eth.functions'; + +const connectButton = '[data-testid="connect-to-eth-btn"]'; const lockedTokensInVestingContract = '6,499,972.30'; context( @@ -5,12 +14,30 @@ context( { tags: '@smoke' }, function () { before('navigate to vesting page', function () { - cy.visit('/token/redeem'); + cy.visit('/'); + navigateTo(navigation.vesting); + }); + + describe('with wallets disconnected', function () { + it('should have vesting tab highlighted', function () { + verifyTabHighlighted(navigation.vesting); + }); + + it('should have VESTING header visible', function () { + verifyPageHeader('Vesting'); + }); + + // 1005-VEST-018 + it('should have connect Eth wallet button', function () { + cy.get(connectButton) + .should('be.visible') + .and('have.text', 'Connect Ethereum wallet'); + }); }); describe('With Eth wallet connected', function () { before('connect eth wallet', function () { - cy.ethereum_wallet_connect(); + ethereumWalletConnect(); cy.getByTestId('view-connected-eth-btn').click(); }); @@ -105,7 +132,6 @@ context( 'All the tokens in this tranche are locked and can not be redeemed yet.' ); }); - cy.connectVegaWallet(); }); }); } diff --git a/apps/governance-e2e/src/integration/view/wallet-eth.cy.js b/apps/governance-e2e/src/integration/view/wallet-eth.cy.ts similarity index 87% rename from apps/governance-e2e/src/integration/view/wallet-eth.cy.js rename to apps/governance-e2e/src/integration/view/wallet-eth.cy.ts index ccdf42d60..cac1af3c9 100644 --- a/apps/governance-e2e/src/integration/view/wallet-eth.cy.js +++ b/apps/governance-e2e/src/integration/view/wallet-eth.cy.ts @@ -1,3 +1,6 @@ +import { convertTokenValueToNumber } from '../../support/common.functions'; +import { ethereumWalletConnect } from '../../support/wallet-eth.functions'; + const walletContainer = 'aside [data-testid="ethereum-wallet"]'; const walletHeader = '[data-testid="wallet-header"] h1'; const connectToEthButton = @@ -87,7 +90,7 @@ context( // 0004-EWAL-001 0004-EWAL-002 describe('when Ethereum wallet connected', function () { before('connect to Ethereum wallet', function () { - cy.ethereum_wallet_connect(); + ethereumWalletConnect(); }); it('should have ETHEREUM KEY header visible', function () { @@ -178,22 +181,25 @@ context( .within(() => { cy.get(currencyValue) .invoke('text') - .convert_token_value_to_number() - .as('value'); + .then((currencyValueTxt) => { + convertTokenValueToNumber(currencyValueTxt).as('value'); + }); cy.get(currencyLocked) .invoke('text') - .convert_token_value_to_number() - .as('locked'); + .then((currencyLockedTxt) => { + convertTokenValueToNumber(currencyLockedTxt).as('locked'); + }); cy.get(currencyUnlocked) .invoke('text') - .convert_token_value_to_number() - .as('unlocked'); + .then((currencyUnlockedTxt) => { + convertTokenValueToNumber(currencyUnlockedTxt).as('unlocked'); + }); }) .then(function () { expect(parseFloat(this.value).toFixed(1)).to.equal( - parseFloat( - Math.round((this.locked + this.unlocked) * 100) / 100 - ).toFixed(1) + (Math.round((this.locked + this.unlocked) * 100) / 100).toFixed( + 1 + ) ); }); }); @@ -247,16 +253,19 @@ context( .within(() => { cy.get(currencyValue) .invoke('text') - .convert_token_value_to_number() - .as('value'); + .then((currencyValueTxt) => { + convertTokenValueToNumber(currencyValueTxt).as('value'); + }); cy.get(currencyLocked) .invoke('text') - .convert_token_value_to_number() - .as('locked'); + .then((currencyLockedTxt) => { + convertTokenValueToNumber(currencyLockedTxt).as('locked'); + }); cy.get(currencyUnlocked) .invoke('text') - .convert_token_value_to_number() - .as('unlocked'); + .then((currencyUnlockedTxt) => { + convertTokenValueToNumber(currencyUnlockedTxt).as('unlocked'); + }); }) .then(function () { expect(this.value).to.equal(this.locked + this.unlocked); diff --git a/apps/governance-e2e/src/integration/view/wallet-vega.cy.js b/apps/governance-e2e/src/integration/view/wallet-vega.cy.ts similarity index 91% rename from apps/governance-e2e/src/integration/view/wallet-vega.cy.js rename to apps/governance-e2e/src/integration/view/wallet-vega.cy.ts index 2a5e4699e..4e1df5335 100644 --- a/apps/governance-e2e/src/integration/view/wallet-vega.cy.js +++ b/apps/governance-e2e/src/integration/view/wallet-vega.cy.ts @@ -1,4 +1,7 @@ import { truncateByChars } from '@vegaprotocol/utils'; +import { waitForSpinner } from '../../support/common.functions'; +import { vegaWalletTeardown } from '../../support/wallet-teardown.functions'; +import { vegaWalletFaucetAssetsWithoutCheck } from '../../support/wallet-vega.functions'; const walletContainer = 'aside [data-testid="vega-wallet"]'; const walletHeader = '[data-testid="wallet-header"] h1'; @@ -129,7 +132,7 @@ context( before('connect vega wallet', function () { cy.visit('/'); cy.connectVegaWallet(); - cy.vega_wallet_teardown(); + vegaWalletTeardown(); }); // 0002-WCON-007 @@ -158,7 +161,7 @@ context( cy.get(walletContainer).within(() => { cy.get(currencyTitle) .should('be.visible') - .and('have.text', `VEGAAssociated`); + .and('contain.text', `VEGAAssociated`); }); }); @@ -167,14 +170,19 @@ context( { tags: '@smoke' }, function () { cy.get(walletContainer).within(() => { - cy.get(currencyValue).should('be.visible').and('have.text', `0.00`); + cy.get(currencyValue) + .should('be.visible') + .and('contain.text', `0.00`); }); } ); it('should have Unstaked value visible', { tags: '@smoke' }, function () { cy.get(walletContainer).within(() => { - cy.get(vegaUnstaked).should('be.visible').and('have.text', `0.00`); + cy.get(vegaUnstaked) + .should('be.visible') + .invoke('text') + .and('not.be.empty'); }); }); @@ -300,16 +308,17 @@ context( before('faucet assets to connected vega wallet', function () { for (const { id, amount } of assets) { - cy.vega_wallet_faucet_assets_without_check( - id, - amount, - vegaWalletPublicKey - ); + vegaWalletFaucetAssetsWithoutCheck(id, amount, vegaWalletPublicKey); } cy.reload(); - cy.wait_for_spinner(); + waitForSpinner(); cy.connectVegaWallet(); - cy.ethereum_wallet_connect(); + cy.get(walletContainer).within(() => { + cy.getByTestId('currency-title', txTimeout).should( + 'have.length.at.least', + 5 + ); + }); }); for (const { id, name, expectedAmount } of assets) { @@ -323,8 +332,9 @@ context( .contains(id) .parent() .siblings() - .within((el) => { - const value = parseFloat(el.text()); + .invoke('text') + .then((el) => { + const value = parseFloat(el); cy.wrap(value).should('be.gte', parseFloat(expectedAmount)); }); diff --git a/apps/governance-e2e/src/integration/view/withdraw.cy.ts b/apps/governance-e2e/src/integration/view/withdraw.cy.ts new file mode 100644 index 000000000..3a2d51ce9 --- /dev/null +++ b/apps/governance-e2e/src/integration/view/withdraw.cy.ts @@ -0,0 +1,35 @@ +import { + navigateTo, + navigation, + verifyPageHeader, + verifyTabHighlighted, +} from '../../support/common.functions'; + +const connectToVegaBtn = '[data-testid="connect-to-vega-wallet-btn"]'; + +context( + 'Withdraw Page - verify elements on page', + { tags: '@smoke' }, + function () { + before('navigate to withdrawals page', function () { + cy.visit('/'); + navigateTo(navigation.withdraw); + }); + + describe('with wallets disconnected', function () { + it('should have withdraw tab highlighted', function () { + verifyTabHighlighted(navigation.withdraw); + }); + + it('should have WITHDRAW header visible', function () { + verifyPageHeader('Withdrawals'); + }); + + it('should have connect Vega wallet button', function () { + cy.get(connectToVegaBtn) + .should('be.visible') + .and('have.text', 'Connect Vega wallet'); + }); + }); + } +); diff --git a/apps/governance-e2e/src/support/common-interfaces.ts b/apps/governance-e2e/src/support/common-interfaces.ts new file mode 100644 index 000000000..e73a406de --- /dev/null +++ b/apps/governance-e2e/src/support/common-interfaces.ts @@ -0,0 +1,128 @@ +export interface testFreeformProposal { + rationale: { + title: string; + description: string; + }; + terms: { + closingTimestamp: number; + }; +} + +export interface networkParameters { + 'blockchains.ethereumConfig': string; + 'governance.proposal.asset.maxClose': string; + 'governance.proposal.asset.maxEnact': string; + 'governance.proposal.asset.minClose': string; + 'governance.proposal.asset.minEnact': string; + 'governance.proposal.asset.minProposerBalance': string; + 'governance.proposal.asset.minVoterBalance': string; + 'governance.proposal.asset.requiredMajority': string; + 'governance.proposal.asset.requiredParticipation': string; + 'governance.proposal.freeform.maxClose': string; + 'governance.proposal.freeform.minClose': string; + 'governance.proposal.freeform.minProposerBalance': string; + 'governance.proposal.freeform.minVoterBalance': string; + 'governance.proposal.freeform.requiredMajority': string; + 'governance.proposal.freeform.requiredParticipation': string; + 'governance.proposal.market.maxClose': string; + 'governance.proposal.market.maxEnact': string; + 'governance.proposal.market.minClose': string; + 'governance.proposal.market.minEnact': string; + 'governance.proposal.market.minProposerBalance': string; + 'governance.proposal.market.minVoterBalance': string; + 'governance.proposal.market.requiredMajority': string; + 'governance.proposal.market.requiredParticipation': string; + 'governance.proposal.updateAsset.maxClose': string; + 'governance.proposal.updateAsset.maxEnact': string; + 'governance.proposal.updateAsset.minClose': string; + 'governance.proposal.updateAsset.minEnact': string; + 'governance.proposal.updateAsset.minProposerBalance': string; + 'governance.proposal.updateAsset.minVoterBalance': string; + 'governance.proposal.updateAsset.requiredMajority': string; + 'governance.proposal.updateAsset.requiredParticipation': string; + 'governance.proposal.updateMarket.maxClose': string; + 'governance.proposal.updateMarket.maxEnact': string; + 'governance.proposal.updateMarket.minClose': string; + 'governance.proposal.updateMarket.minEnact': string; + 'governance.proposal.updateMarket.minProposerBalance': string; + 'governance.proposal.updateMarket.minProposerEquityLikeShare': string; + 'governance.proposal.updateMarket.minVoterBalance': string; + 'governance.proposal.updateMarket.requiredMajority': string; + 'governance.proposal.updateMarket.requiredMajorityLP': string; + 'governance.proposal.updateMarket.requiredParticipation': string; + 'governance.proposal.updateMarket.requiredParticipationLP': string; + 'governance.proposal.updateNetParam.maxClose': string; + 'governance.proposal.updateNetParam.maxEnact': string; + 'governance.proposal.updateNetParam.minClose': string; + 'governance.proposal.updateNetParam.minEnact': string; + 'governance.proposal.updateNetParam.minProposerBalance': string; + 'governance.proposal.updateNetParam.minVoterBalance': string; + 'governance.proposal.updateNetParam.requiredMajority': string; + 'governance.proposal.updateNetParam.requiredParticipation': string; + 'limits.assets.proposeEnabledFrom': string; + 'limits.markets.maxPeggedOrders': string; + 'limits.markets.proposeEnabledFrom': string; + 'market.auction.maximumDuration': string; + 'market.auction.minimumDuration': string; + 'market.fee.factors.infrastructureFee': string; + 'market.fee.factors.makerFee': string; + 'market.liquidity.bondPenaltyParameter': string; + 'market.liquidity.maximumLiquidityFeeFactorLevel': string; + 'market.liquidity.minimum.probabilityOfTrading.lpOrders': string; + 'market.liquidity.probabilityOfTrading.tau.scaling': string; + 'market.liquidity.providers.fee.distributionTimeStep': string; + 'market.liquidity.stakeToCcyVolume': string; + 'market.liquidity.targetstake.triggering.ratio': string; + 'market.liquidityProvision.minLpStakeQuantumMultiple': string; + 'market.liquidityProvision.shapes.maxSize': string; + 'market.margin.scalingFactors': string; + 'market.monitor.price.defaultParameters': string; + 'market.stake.target.scalingFactor': string; + 'market.stake.target.timeWindow': string; + 'market.value.windowLength': string; + 'network.checkpoint.timeElapsedBetweenCheckpoints': string; + 'network.floatingPointUpdates.delay': string; + 'network.markPriceUpdateMaximumFrequency': string; + 'network.transaction.defaultgas': string; + 'network.transactions.maxgasperblock': string; + 'network.transactions.minBlockCapacity': string; + 'network.validators.ersatz.multipleOfTendermintValidators': string; + 'network.validators.ersatz.rewardFactor': string; + 'network.validators.incumbentBonus': string; + 'network.validators.minimumEthereumEventsForNewValidator': string; + 'network.validators.multisig.numberOfSigners': string; + 'network.validators.tendermint.number': string; + 'reward.asset': string; + 'reward.staking.delegation.competitionLevel': string; + 'reward.staking.delegation.delegatorShare': string; + 'reward.staking.delegation.maxPayoutPerEpoch': string; + 'reward.staking.delegation.maxPayoutPerParticipant': string; + 'reward.staking.delegation.minValidators': string; + 'reward.staking.delegation.minimumValidatorStake': string; + 'reward.staking.delegation.optimalStakeMultiplier': string; + 'reward.staking.delegation.payoutDelay': string; + 'reward.staking.delegation.payoutFraction': string; + 'rewards.marketCreationQuantumMultiple': string; + 'snapshot.interval.length': string; + 'spam.pow.difficulty': string; + 'spam.pow.hashFunction': string; + 'spam.pow.increaseDifficulty': string; + 'spam.pow.numberOfPastBlocks': string; + 'spam.pow.numberOfTxPerBlock': string; + 'spam.protection.delegation.min.tokens': string; + 'spam.protection.max.batchSize': string; + 'spam.protection.max.delegations': string; + 'spam.protection.max.proposals': string; + 'spam.protection.max.votes': string; + 'spam.protection.maxUserTransfersPerEpoch': string; + 'spam.protection.minMultisigUpdates': string; + 'spam.protection.minimumWithdrawalQuantumMultiple': string; + 'spam.protection.proposal.min.tokens': string; + 'spam.protection.voting.min.tokens': string; + 'transfer.fee.factor': string; + 'transfer.minTransferQuantumMultiple': string; + 'validator.performance.scaling.factor': string; + 'validators.delegation.minAmount': string; + 'validators.epoch.length': string; + 'validators.vote.required': string; +} diff --git a/apps/governance-e2e/src/support/common.functions.js b/apps/governance-e2e/src/support/common.functions.js deleted file mode 100644 index 6ea9ece67..000000000 --- a/apps/governance-e2e/src/support/common.functions.js +++ /dev/null @@ -1,87 +0,0 @@ -const epochTimeout = Cypress.env('epochTimeout'); -const txTimeout = Cypress.env('txTimeout'); - -Cypress.Commands.add( - 'convert_token_value_to_number', - { prevSubject: true }, - (subject) => { - return parseFloat(subject.replace(/,/g, '')); - } -); - -const navigation = { - section: '[data-testid="navigation"]', - vesting: '[href="/token/redeem"]', - validators: '[href="/validators"]', - rewards: '[href="/rewards"]', - withdraw: '[href="/token/withdraw"]', - proposals: '[href="/proposals"]', - pageSpinner: '[data-testid="splash-loader"]', - supply: '[href="/token/tranches"]', - token: '[href="/token"]', -}; - -const topLevelRoutes = ['proposals', 'validators', 'rewards']; -const tokenDropDown = 'state-trigger'; - -Cypress.Commands.add('navigate_to', (page) => { - if (!topLevelRoutes.includes(page)) { - // FIXME: Timeout madness - cy.getByTestId(tokenDropDown, { timeout: 60000 }).eq(0).click(); - cy.get('[data-testid="token-dropdown"]:visible').within(() => { - cy.get(navigation[page]).eq(0).click(); - }); - } else { - return cy.get(navigation.section, { timeout: 10000 }).within(() => { - cy.get(navigation[page]).eq(0).click(); - }); - } -}); - -Cypress.Commands.add('verify_tab_highlighted', (page) => { - return cy.get(navigation.section).within(() => { - if (!topLevelRoutes.includes(page)) { - cy.getByTestId(tokenDropDown, { timeout: 10000 }).eq(0).click(); - cy.get('[data-testid="token-dropdown"]:visible').within(() => { - cy.get(navigation[page]).should('have.attr', 'aria-current'); - }); - } else { - cy.get(navigation[page]).should('have.attr', 'aria-current'); - } - }); -}); - -Cypress.Commands.add('verify_page_header', (text) => { - return cy.get('header h1').should('be.visible').and('have.text', text); -}); - -Cypress.Commands.add('wait_for_spinner', () => { - cy.get(navigation.pageSpinner, Cypress.env('epochTimeout')).should('exist'); - cy.get(navigation.pageSpinner, { timeout: 20000 }).should('not.exist'); -}); - -// This is a workaround function to begin tests with associating tokens without failing -// Should be removed when eth transaction bug is fixed -export function associateTokenStartOfTests() { - cy.highlight(`Associating tokens for first time`); - cy.ethereum_wallet_connect(); - cy.connectVegaWallet(); - cy.get('[href="/token/associate"]:visible').first().click(); - cy.getByTestId('associate-radio-wallet', { timeout: 30000 }).click(); - cy.getByTestId('token-amount-input', epochTimeout).type('1'); - cy.getByTestId('token-input-submit-button', txTimeout) - .should('be.enabled') - .click(); - cy.contains( - `Associating with Vega key. Waiting for ${Cypress.env( - 'blockConfirmations' - )} more confirmations..`, - txTimeout - ).should('be.visible'); - cy.getByTestId('associated-amount', txTimeout).should('contain.text', '1'); - // Wait is needed to allow time for transaction to complete - // eslint-disable-next-line cypress/no-unnecessary-waiting - cy.wait(10000); - cy.vega_wallet_teardown(); - cy.clearLocalStorage(); -} diff --git a/apps/governance-e2e/src/support/common.functions.ts b/apps/governance-e2e/src/support/common.functions.ts new file mode 100644 index 000000000..5cea725fc --- /dev/null +++ b/apps/governance-e2e/src/support/common.functions.ts @@ -0,0 +1,86 @@ +const tokenDropDown = 'state-trigger'; +const txTimeout = Cypress.env('txTimeout'); + +export enum navigation { + section = 'nav', + vesting = '[href="/token/redeem"]', + validators = '[href="/validators"]', + rewards = '[href="/rewards"]', + withdraw = '[href="/token/withdraw"]', + proposals = '[href="/proposals"]', + pageSpinner = '[data-testid="splash-loader"]', + supply = '[href="/token/tranches"]', + token = '[href="/token"]', +} + +export function convertTokenValueToNumber(subject: string) { + return cy.wrap(parseFloat(subject.replace(/,/g, ''))); +} + +const topLevelRoutes = [ + navigation.proposals, + navigation.validators, + navigation.rewards, +]; + +export function navigateTo(page: navigation) { + if (!topLevelRoutes.includes(page)) { + cy.getByTestId(tokenDropDown, { timeout: 10000 }).eq(0).click(); + cy.getByTestId('token-dropdown').within(() => { + cy.get(page).eq(0).click(); + }); + } else { + return cy.get(navigation.section, { timeout: 10000 }).within(() => { + cy.get(page).eq(0).click(); + }); + } +} + +export function verifyTabHighlighted(page: navigation) { + return cy.get(navigation.section).within(() => { + if (!topLevelRoutes.includes(page)) { + cy.getByTestId(tokenDropDown, { timeout: 10000 }).eq(0).click(); + cy.get('[data-testid="token-dropdown"]:visible').within(() => { + cy.get(page).should('have.attr', 'aria-current'); + }); + } else { + cy.get(page).should('have.attr', 'aria-current'); + } + }); +} + +export function verifyPageHeader(text: string) { + return cy.get('header h1').should('be.visible').and('have.text', text); +} + +export function waitForSpinner() { + cy.get(navigation.pageSpinner, Cypress.env('epochTimeout')).should('exist'); + cy.get(navigation.pageSpinner, { timeout: 20000 }).should('not.exist'); +} + +export function verifyUnstakedBalance(amount: number) { + cy.getByTestId('vega-wallet-balance-unstaked', txTimeout).should( + 'contain', + amount, + txTimeout + ); +} + +export function verifyStakedBalance(amount: number) { + cy.getByTestId('vega-wallet-balance-staked-validators', txTimeout) + .should('contain', amount, txTimeout) + .and('contain', '…'); +} + +export function verifyEthWalletTotalAssociatedBalance(amount: string) { + cy.getByTestId('currency-locked', txTimeout) + .should('contain', amount) + .and('be.visible'); +} + +export function verifyEthWalletAssociatedBalance(amount: string) { + cy.getByTestId('eth-wallet-associated-balances', txTimeout) + .contains(Cypress.env('vegaWalletPublicKeyShort'), txTimeout) + .parent(txTimeout) + .should('contain', amount, txTimeout); +} diff --git a/apps/governance-e2e/src/support/governance.functions.js b/apps/governance-e2e/src/support/governance.functions.js deleted file mode 100644 index 09affbf59..000000000 --- a/apps/governance-e2e/src/support/governance.functions.js +++ /dev/null @@ -1,228 +0,0 @@ -const newProposalButton = '[data-testid="new-proposal-link"]'; -const proposalInformationTableRows = '[data-testid="key-value-table-row"]'; -const proposalListItem = '[data-testid="proposals-list-item"]'; -const newProposalTitle = '[data-testid="proposal-title"]'; -const newProposalDescription = '[data-testid="proposal-description"]'; -const proposalDetails = '[data-testid="proposal-details"]'; -const rawProposalData = '[data-testid="proposal-data"]'; -const voteButtons = '[data-testid="vote-buttons"]'; -const dialogTitle = '[data-testid="dialog-title"]'; -const proposalVoteDeadline = '[data-testid="proposal-vote-deadline"]'; -const newProposalSubmitButton = '[data-testid="proposal-submit"]'; -const dialogCloseButton = '[data-testid="dialog-close"]'; -const epochTimeout = Cypress.env('epochTimeout'); -const proposalTimeout = { timeout: 14000 }; - -Cypress.Commands.add( - 'convert_unix_timestamp_to_governance_data_table_date_format', - (unixTimestamp, monthTextLength = 'longMonth') => { - let dateSupplied = new Date(unixTimestamp * 1000), - year = dateSupplied.getFullYear(), - months = [ - 'January', - 'February', - 'March', - 'April', - 'May', - 'June', - 'July', - 'August', - 'September', - 'October', - 'November', - 'December', - ], - month = months[dateSupplied.getMonth()], - shortMonth = months[dateSupplied.getMonth()].substring(0, 3), - date = dateSupplied.getDate(); - - if (monthTextLength === 'longMonth') return `${date} ${month} ${year}`; - else return `${date} ${shortMonth} ${year}`; - } -); - -Cypress.Commands.add( - 'create_ten_digit_unix_timestamp_for_specified_days', - (durationDays) => { - let today = new Date(); - let timestamp = today.setDate(today.getDate() + parseInt(durationDays)); - timestamp = Math.floor(timestamp / 1000); - - return timestamp; - } -); - -Cypress.Commands.add('enter_raw_proposal_body', (timestamp) => { - cy.fixture('/proposals/raw.json').then((rawProposal) => { - rawProposal.terms.closingTimestamp = timestamp; - rawProposal.rationale.title += timestamp; - let proposalPayload = JSON.stringify(rawProposal); - - cy.get(rawProposalData).type(proposalPayload, { - parseSpecialCharSequences: false, - delay: 2, - }); - cy.get(newProposalSubmitButton).should('be.visible').click(); - cy.wrap(rawProposal); - }); -}); - -Cypress.Commands.add( - 'enter_unique_freeform_proposal_body', - (timestamp, proposalTitle) => { - cy.get(newProposalTitle).type(proposalTitle); - cy.get(newProposalDescription).type( - 'this is a e2e freeform proposal description' - ); - cy.get(proposalVoteDeadline).clear().click().type(timestamp); - cy.getByTestId('proposal-submit').should('be.visible').click(); - } -); - -Cypress.Commands.add( - 'get_submitted_proposal_from_proposal_list', - (proposalTitle) => { - cy.get_proposal_id_from_list(proposalTitle).then(() => { - cy.get('@proposalIdText').then((proposalId) => { - return cy.get(`#${proposalId}`); - }); - }); - } -); - -Cypress.Commands.add('get_proposal_id_from_list', (proposalTitle) => { - cy.contains(proposalTitle) - .parentsUntil(proposalListItem) - .within(() => { - cy.get(proposalDetails) - .invoke('text') - .then((proposalIdText) => { - let newProposalId; - if (proposalIdText.includes('Freeform proposal')) { - newProposalId = proposalIdText.replace('Freeform proposal: ', ''); - } - cy.wrap(newProposalId).as('proposalIdText'); - }); - }); -}); - -Cypress.Commands.add( - 'get_governance_proposal_date_format_for_specified_days', - (days, shortOrLong) => { - cy.create_ten_digit_unix_timestamp_for_specified_days(days).then((date) => { - cy.convert_unix_timestamp_to_governance_data_table_date_format( - date, - shortOrLong - ).then((convertedDate) => { - return convertedDate; - }); - }); - } -); - -Cypress.Commands.add('get_proposal_information_from_table', (heading) => { - cy.get(proposalInformationTableRows).contains(heading).siblings(); -}); - -Cypress.Commands.add('vote_for_proposal', (vote) => { - cy.contains('Vote breakdown').should('be.visible', { timeout: 10000 }); - cy.get(voteButtons).contains(vote).click(); - cy.get(dialogTitle).should('have.text', 'Transaction complete'); - cy.get(dialogCloseButton).click(); -}); - -Cypress.Commands.add('wait_for_proposal_sync', () => { - // This is a workaround function required because after posting a proposal - // and waiting for the ProposalEvent network call to respond there can still be a few seconds - // before proposal appears in the list - so rather than hard coded wait - we just wait on the - // delegation checks that are performed on the governance page. - - cy.intercept('POST', '/query', (req) => { - if (req.body.operationName === 'Delegations') { - req.alias = 'proposalDelegationsCompletion'; - } - }); - - // waiting for two network calls - cy.wait(['@proposalDelegationsCompletion', '@proposalDelegationsCompletion']); - - // Turn off this intercept from here on in - cy.intercept('POST', '/query', (req) => { - if (req.body.operationName === 'Delegations') { - req.continue(); - } - }); -}); - -Cypress.Commands.add('navigate_to_page_if_not_already_loaded', (section) => { - cy.url().then((url) => { - if (url != `http://localhost:4210/${section}`) { - cy.navigate_to(section); - } - }); -}); - -Cypress.Commands.add('get_sort_order_of_supplied_array', (suppliedArray) => { - const tempArray = []; - for (let index = 1; index < suppliedArray.length; index++) { - tempArray.push( - suppliedArray[index - 1].localeCompare(suppliedArray[index]) - ); - } - if (tempArray.every((n) => n <= 0)) return 'ascending'; - else if (tempArray.every((n) => n >= 0)) return 'descending'; - else return 'unsorted'; -}); - -Cypress.Commands.add('go_to_make_new_proposal', (proposalType) => { - cy.navigate_to_page_if_not_already_loaded('proposals'); - cy.get(newProposalButton).should('be.visible').click(); - cy.url().should('include', '/proposals/propose'); - cy.get('li').should('contain.text', proposalType).and('be.visible'); - cy.get('li').contains(proposalType).click(); -}); - -Cypress.Commands.add('wait_for_proposal_submitted', () => { - cy.contains('Awaiting network confirmation', epochTimeout).should( - 'be.visible' - ); - cy.contains('Proposal submitted', proposalTimeout).should('be.visible'); - cy.get(dialogCloseButton).click(); -}); - -export function createRawProposal(proposerBalance) { - if (proposerBalance) - cy.ensure_specified_unstaked_tokens_are_associated(proposerBalance); - cy.go_to_make_new_proposal('raw proposal'); - cy.create_ten_digit_unix_timestamp_for_specified_days('8').then( - (closingDateTimestamp) => { - cy.enter_raw_proposal_body(closingDateTimestamp).as('rawProposal'); - } - ); - cy.wait_for_proposal_submitted(); - cy.wait_for_proposal_sync(); - cy.navigate_to('proposals'); -} - -export function generateFreeFormProposalTitle() { - const randomNum = Math.floor(Math.random() * 1000) + 1; - return randomNum + ': Freeform e2e proposal'; -} - -export function createFreeformProposal(proposalTitle) { - cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); - cy.enter_unique_freeform_proposal_body('50', proposalTitle); - cy.wait_for_proposal_submitted(); - cy.wait_for_proposal_sync(); - cy.getByTestId('proposal-title').invoke('text').as('proposalTitle'); - cy.navigate_to('proposals'); -} - -export const governanceProposalType = { - NETWORK_PARAMETER: 'Network parameter', - NEW_MARKET: 'New market', - UPDATE_MARKET: 'Update market', - NEW_ASSET: 'New asset', - FREEFORM: 'Freeform', - RAW: 'raw proposal', -}; diff --git a/apps/governance-e2e/src/support/governance.functions.ts b/apps/governance-e2e/src/support/governance.functions.ts new file mode 100644 index 000000000..2109335fd --- /dev/null +++ b/apps/governance-e2e/src/support/governance.functions.ts @@ -0,0 +1,215 @@ +import { navigateTo, navigation } from './common.functions'; +import { ensureSpecifiedUnstakedTokensAreAssociated } from './staking.functions'; + +const newProposalButton = '[data-testid="new-proposal-link"]'; +const proposalInformationTableRows = '[data-testid="key-value-table-row"]'; +const proposalListItem = '[data-testid="proposals-list-item"]'; +const newProposalTitle = '[data-testid="proposal-title"]'; +const newProposalDescription = '[data-testid="proposal-description"]'; +const proposalDetails = '[data-testid="proposal-details"]'; +const rawProposalData = '[data-testid="proposal-data"]'; +const voteButtons = '[data-testid="vote-buttons"]'; +const dialogTitle = '[data-testid="dialog-title"]'; +const proposalVoteDeadline = '[data-testid="proposal-vote-deadline"]'; +const newProposalSubmitButton = '[data-testid="proposal-submit"]'; +const dialogCloseButton = '[data-testid="dialog-close"]'; +const epochTimeout = Cypress.env('epochTimeout'); +const proposalTimeout = { timeout: 14000 }; + +export function convertUnixTimestampToDateformat( + unixTimestamp: number, + monthTextLength = 'longMonth' +) { + const dateSupplied = new Date(unixTimestamp * 1000); + const year = dateSupplied.getFullYear(); + const months = [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December', + ]; + const month = months[dateSupplied.getMonth()]; + const shortMonth = months[dateSupplied.getMonth()].substring(0, 3), + date = dateSupplied.getDate(); + + if (monthTextLength === 'longMonth') { + return cy.wrap(`${date} ${month} ${year}`); + } else return cy.wrap(`${date} ${shortMonth} ${year}`); +} + +export function createTenDigitUnixTimeStampForSpecifiedDays( + durationDays: number +) { + const today = new Date(); + let timestamp = today.setDate(today.getDate() + durationDays); + return (timestamp = Math.floor(timestamp / 1000)); +} + +export function enterRawProposalBody(timestamp: number) { + cy.fixture('/proposals/raw.json').then((rawProposal) => { + rawProposal.terms.closingTimestamp = timestamp; + rawProposal.rationale.title += timestamp; + const proposalPayload = JSON.stringify(rawProposal); + + cy.get(rawProposalData).type(proposalPayload, { + parseSpecialCharSequences: false, + delay: 2, + }); + cy.get(newProposalSubmitButton).should('be.visible').click(); + cy.wrap(rawProposal).as('rawProposal'); + }); +} + +export function enterUniqueFreeFormProposalBody( + timestamp: string, + proposalTitle: string +) { + cy.get(newProposalTitle).type(proposalTitle); + cy.get(newProposalDescription).type( + 'this is a e2e freeform proposal description' + ); + cy.get(proposalVoteDeadline).clear().click().type(timestamp); + cy.getByTestId('proposal-submit').should('be.visible').click(); +} + +export function getSubmittedProposalFromProposalList(proposalTitle: string) { + getProposalIdFromList(proposalTitle); + cy.get('@proposalIdText').then((proposalId) => { + cy.get(`#${proposalId}`).as('submittedProposal'); + }); + return cy.get('@submittedProposal'); +} + +export function getProposalIdFromList(proposalTitle: string) { + cy.contains(proposalTitle) + .parentsUntil(proposalListItem) + .within(() => { + cy.get(proposalDetails) + .invoke('text') + .then((proposalIdText) => { + let newProposalId; + if (proposalIdText.includes('Freeform proposal')) { + newProposalId = proposalIdText.replace('Freeform proposal: ', ''); + } + cy.wrap(newProposalId).as('proposalIdText'); + }); + }); +} + +export function getGovernanceProposalDateFormatForSpecifiedDays( + days: number, + shortOrLong?: string +) { + return convertUnixTimestampToDateformat( + createTenDigitUnixTimeStampForSpecifiedDays(days), + shortOrLong + ); +} + +export function getProposalInformationFromTable(heading: string) { + return cy.get(proposalInformationTableRows).contains(heading).siblings(); +} + +export function voteForProposal(vote: string) { + cy.contains('Vote breakdown').should('be.visible', { timeout: 10000 }); + cy.get(voteButtons).contains(vote).click(); + cy.get(dialogTitle, proposalTimeout).should( + 'have.text', + 'Transaction complete' + ); + cy.get(dialogCloseButton).click(); +} + +export function waitForProposalSync() { + // This is a workaround function required because after posting a proposal + // and waiting for the ProposalEvent network call to respond there can still be a few seconds + // before proposal appears in the list - so rather than hard coded wait - we just wait on the + // delegation checks that are performed on the governance page. + + cy.intercept('POST', '/query', (req) => { + if (req.body.operationName === 'Delegations') { + req.alias = 'proposalDelegationsCompletion'; + } + }); + + // waiting for two network calls + cy.wait(['@proposalDelegationsCompletion', '@proposalDelegationsCompletion']); + + // Turn off this intercept from here on in + cy.intercept('POST', '/query', (req) => { + if (req.body.operationName === 'Delegations') { + req.continue(); + } + }); +} + +export function getSortOrderOfSuppliedArray(suppliedArray: string[]) { + const tempArray = []; + for (let index = 1; index < suppliedArray.length; index++) { + tempArray.push( + suppliedArray[index - 1].localeCompare(suppliedArray[index]) + ); + } + if (tempArray.every((n) => n <= 0)) return 'ascending'; + else if (tempArray.every((n) => n >= 0)) return 'descending'; + else return 'unsorted'; +} + +export function goToMakeNewProposal(proposalType: string) { + navigateTo(navigation.proposals); + cy.get(newProposalButton).should('be.visible').click(); + cy.url().should('include', '/proposals/propose'); + cy.get('li').should('contain.text', proposalType).and('be.visible'); + cy.get('li').contains(proposalType).click(); +} + +export function waitForProposalSubmitted() { + cy.contains('Awaiting network confirmation', epochTimeout).should( + 'be.visible' + ); + cy.contains('Proposal submitted', proposalTimeout).should('be.visible'); + cy.get(dialogCloseButton).click(); +} + +export function createRawProposal(proposerBalance?: string) { + if (proposerBalance) { + ensureSpecifiedUnstakedTokensAreAssociated(proposerBalance); + } + + goToMakeNewProposal(governanceProposalType.RAW); + enterRawProposalBody(createTenDigitUnixTimeStampForSpecifiedDays(8)); + waitForProposalSubmitted(); + waitForProposalSync(); + navigateTo(navigation.proposals); +} + +export function generateFreeFormProposalTitle() { + const randomNum = Math.floor(Math.random() * 1000) + 1; + return randomNum + ': Freeform e2e proposal'; +} + +export function createFreeformProposal(proposalTitle: string) { + goToMakeNewProposal(governanceProposalType.FREEFORM); + enterUniqueFreeFormProposalBody('50', proposalTitle); + waitForProposalSubmitted(); + waitForProposalSync(); + cy.getByTestId('proposal-title').invoke('text').as('proposalTitle'); + navigateTo(navigation.proposals); +} + +export const governanceProposalType = { + NETWORK_PARAMETER: 'Network parameter', + NEW_MARKET: 'New market', + UPDATE_MARKET: 'Update market', + NEW_ASSET: 'New asset', + FREEFORM: 'Freeform', + RAW: 'raw proposal', +}; diff --git a/apps/governance-e2e/src/support/index.d.ts b/apps/governance-e2e/src/support/index.d.ts new file mode 100644 index 000000000..0ef79cee8 --- /dev/null +++ b/apps/governance-e2e/src/support/index.d.ts @@ -0,0 +1,20 @@ +/// + +declare namespace Cypress { + // specify additional properties in the TestConfig object + // in our case we will add "tags" property + interface SuiteConfigOverrides { + /** + * List of tags for this test + * @example a single tag + * it('logs in', { tags: '@smoke' }, () => { ... }) + * @example multiple tags + * it('works', { tags: ['@smoke', '@slow'] }, () => { ... }) + */ + tags?: string | string[]; + } + + interface Cypress { + grep?: (grep?: string, tags?: string, burn?: string) => void; + } +} diff --git a/apps/governance-e2e/src/support/index.js b/apps/governance-e2e/src/support/index.js index ae744251e..23cada399 100644 --- a/apps/governance-e2e/src/support/index.js +++ b/apps/governance-e2e/src/support/index.js @@ -1,12 +1,12 @@ import '@vegaprotocol/cypress'; import 'cypress-real-events/support'; -import './common.functions.js'; -import './staking.functions.js'; -import './governance.functions.js'; -import './wallet-eth.functions.js'; -import './wallet-teardown.functions.js'; -import './wallet-vega.functions.js'; +import './common.functions.ts'; +import './staking.functions.ts'; +import './governance.functions.ts'; +import './wallet-eth.functions.ts'; +import './wallet-teardown.functions.ts'; +import './wallet-vega.functions.ts'; import './proposal.functions.ts'; import registerCypressGrep from '@cypress/grep'; import { aliasGQLQuery } from '@vegaprotocol/cypress'; diff --git a/apps/governance-e2e/src/support/staking.functions.js b/apps/governance-e2e/src/support/staking.functions.ts similarity index 56% rename from apps/governance-e2e/src/support/staking.functions.js rename to apps/governance-e2e/src/support/staking.functions.ts index 54bd0a7f8..0064e087f 100644 --- a/apps/governance-e2e/src/support/staking.functions.js +++ b/apps/governance-e2e/src/support/staking.functions.ts @@ -1,3 +1,5 @@ +import { vegaWalletTeardown } from './wallet-teardown.functions'; + const tokenAmountInputBox = '[data-testid="token-amount-input"]'; const tokenSubmitButton = '[data-testid="token-input-submit-button"]'; const tokenInputApprove = '[data-testid="token-input-approve-button"]'; @@ -21,44 +23,47 @@ const dialogCloseButton = '[data-testid="dialog-close"]'; const txTimeout = Cypress.env('txTimeout'); const epochTimeout = Cypress.env('epochTimeout'); -Cypress.Commands.add('wait_for_beginning_of_epoch', () => { +export function waitForBeginningOfEpoch() { cy.contains('Waiting for next epoch to start', epochTimeout).should( 'not.exist' ); cy.contains('Waiting for next epoch to start', epochTimeout).should( 'be.visible' ); -}); +} -Cypress.Commands.add('staking_validator_page_add_stake', (stake) => { +export function stakingValidatorPageAddStake(stake: string) { cy.highlight(`Adding a stake of ${stake}`); cy.get(addStakeRadioButton, epochTimeout).click({ force: true }); cy.get(tokenAmountInputBox).type(stake); - cy.wait_for_beginning_of_epoch(); + waitForBeginningOfEpoch(); cy.get(tokenSubmitButton, epochTimeout) .should('be.enabled') .and('contain', `Add ${stake} $VEGA tokens`) .and('be.visible') .click(); -}); +} -Cypress.Commands.add('staking_validator_page_remove_stake', (stake) => { +export function stakingValidatorPageRemoveStake(stake: string) { cy.highlight(`Removing a stake of ${stake}`); cy.get(removeStakeRadioButton, epochTimeout).click(); cy.get(tokenAmountInputBox).type(stake); - cy.wait_for_beginning_of_epoch(); + waitForBeginningOfEpoch(); cy.get(tokenSubmitButton) .should('be.enabled', epochTimeout) .and('contain', `Remove ${stake} $VEGA tokens at the end of epoch`) .and('be.visible') .click(); cy.get(dialogCloseButton).click(); -}); +} -Cypress.Commands.add('staking_page_associate_tokens', (amount, options) => { - let approve = options && options.approve ? options.approve : false; - let type = options && options.type ? options.type : 'wallet'; - let skipConfirmation = +export function stakingPageAssociateTokens( + amount: string, + options?: associateOptions +) { + const approve = options && options.approve ? options.approve : false; + const type = options && options.type ? options.type : 'wallet'; + const skipConfirmation = options && options.skipConfirmation ? options.skipConfirmation : false; cy.highlight(`Associating ${amount} tokens from ${type}`); @@ -94,10 +99,13 @@ Cypress.Commands.add('staking_page_associate_tokens', (amount, options) => { txTimeout ).should('be.visible'); } -}); +} -Cypress.Commands.add('staking_page_disassociate_tokens', (amount, options) => { - let type = options && options.type ? options.type : 'wallet'; +export function stakingPageDisassociateTokens( + amount: string, + options?: associateOptions +) { + const type = options && options.type ? options.type : 'wallet'; cy.highlight( `Disassociating ${amount} tokens via Staking Page back to ${type}` ); @@ -127,92 +135,89 @@ Cypress.Commands.add('staking_page_disassociate_tokens', (amount, options) => { txTimeout ).should('be.visible'); } -}); +} -Cypress.Commands.add( - 'staking_page_disassociate_all_tokens', - (type = 'wallet') => { - cy.highlight(`Disassociating all tokens via Staking Page`); - cy.get(ethWalletDissociateButton).first().click(); - cy.get(stakeMaximumTokens, epochTimeout).click(); - cy.get(tokenSubmitButton, epochTimeout).click(); - if (type === 'wallet') { - cy.contains( - `$VEGA tokens have been returned to Ethereum wallet`, - txTimeout - ).should('be.visible'); - } else if (type === 'contract') { - cy.contains( - `$VEGA tokens have been returned to Vesting contract`, - txTimeout - ).should('be.visible'); - } +export function stakingPageDisassociateAllTokens(type = 'wallet') { + cy.highlight(`Disassociating all tokens via Staking Page`); + cy.get(ethWalletDissociateButton).first().click(); + cy.get(stakeMaximumTokens, epochTimeout).click(); + cy.get(tokenSubmitButton, epochTimeout).click(); + if (type === 'wallet') { + cy.contains( + `$VEGA tokens have been returned to Ethereum wallet`, + txTimeout + ).should('be.visible'); + } else if (type === 'contract') { + cy.contains( + `$VEGA tokens have been returned to Vesting contract`, + txTimeout + ).should('be.visible'); } -); +} -Cypress.Commands.add( - 'click_on_validator_from_list', - (validatorNumber, validatorName = null) => { - cy.contains('Loading...', epochTimeout).should('not.exist'); - cy.wait_for_beginning_of_epoch(); - // below is to ensure validator list is shown - cy.get(stakeValidatorListName, { timeout: 10000 }).should('exist'); - cy.get(stakeValidatorListPendingStake, txTimeout).should( - 'not.contain', - '2,000,000,000,000,000,000.00' // number due to bug #936 +export function clickOnValidatorFromList( + validatorNumber: number, + validatorName = null +) { + cy.contains('Loading...', epochTimeout).should('not.exist'); + waitForBeginningOfEpoch(); + // below is to ensure validator list is shown + cy.get(stakeValidatorListName, { timeout: 10000 }).should('exist'); + cy.get(stakeValidatorListPendingStake, txTimeout).should( + 'not.contain', + '2,000,000,000,000,000,000.00' // number due to bug #936 + ); + if (validatorName) { + cy.contains(validatorName).click(); + } else { + cy.get(`[row-id="${validatorNumber}"]`) + .should('be.visible') + .find(stakeValidatorListName) + .click(); + } +} + +export function validateValidatorListTotalStakeAndShare( + positionOnList: string, + expectedTotalStake: string, + expectedTotalShare: string +) { + cy.contains('Loading...', epochTimeout).should('not.exist'); + waitForBeginningOfEpoch(); + cy.get(`[row-id="${positionOnList}"]`).within(() => { + cy.get(stakeValidatorListTotalStake, epochTimeout).should( + 'have.text', + expectedTotalStake ); - if (validatorName) { - cy.contains(validatorName).click(); - } else { - cy.get(`[row-id="${validatorNumber}"]`) - .should('be.visible') - .find(stakeValidatorListName) - .click(); - } - } -); + cy.get(stakeValidatorListTotalShare, epochTimeout).should( + 'have.text', + expectedTotalShare + ); + }); +} -Cypress.Commands.add( - 'validate_validator_list_total_stake_and_share', - (positionOnList, expectedTotalStake, expectedTotalShare) => { - cy.contains('Loading...', epochTimeout).should('not.exist'); - cy.wait_for_beginning_of_epoch(); - cy.get(`[row-id="${positionOnList}"]`).within(() => { - cy.get(stakeValidatorListTotalStake, epochTimeout).should( - 'have.text', - expectedTotalStake - ); - cy.get(stakeValidatorListTotalShare, epochTimeout).should( - 'have.text', - expectedTotalShare - ); +export function ensureSpecifiedUnstakedTokensAreAssociated( + tokenAmount: string +) { + cy.highlight(`Ensuring ${tokenAmount} token(s) associated`); + cy.get(vegaWalletUnstakedBalance) + .children() + .children() + .eq(1) + .invoke('text') + .then((unstakedBalance) => { + if (parseFloat(unstakedBalance) != parseFloat(tokenAmount)) { + vegaWalletTeardown(); + cy.get(vegaWalletAssociatedBalance, txTimeout).contains( + '0.00', + txTimeout + ); + stakingPageAssociateTokens(tokenAmount); + } }); - } -); +} -Cypress.Commands.add( - 'ensure_specified_unstaked_tokens_are_associated', - (tokenAmount) => { - cy.highlight(`Ensuring ${tokenAmount} token(s) associated`); - cy.get(vegaWalletUnstakedBalance) - .children() - .children() - .eq(1) - .invoke('text') - .then((unstakedBalance) => { - if (parseFloat(unstakedBalance) != parseFloat(tokenAmount)) { - cy.vega_wallet_teardown(); - cy.get(vegaWalletAssociatedBalance, txTimeout).contains( - '0.00', - txTimeout - ); - cy.staking_page_associate_tokens(tokenAmount); - } - }); - } -); - -Cypress.Commands.add('close_staking_dialog', () => { +export function closeStakingDialog() { cy.getByTestId('dialog-title').should( 'contain.text', 'At the beginning of the next epoch' @@ -220,20 +225,26 @@ Cypress.Commands.add('close_staking_dialog', () => { cy.getByTestId('dialog-content').within(() => { cy.get('a').should('have.text', 'Back to Staking').click(); }); -}); +} -Cypress.Commands.add( - 'validate_wallet_currency', - (currencyTitle, expectedAmount) => { - cy.get("[data-testid='currency-title']") - .contains(currencyTitle) - .parent() - .parent() - .within(() => { - cy.getByTestId('currency-value', txTimeout).should( - 'have.text', - expectedAmount - ); - }); - } -); +export function validateWalletCurrency( + currencyTitle: string, + expectedAmount: string +) { + cy.get("[data-testid='currency-title']") + .contains(currencyTitle) + .parent() + .parent() + .within(() => { + cy.getByTestId('currency-value', txTimeout).should( + 'have.text', + expectedAmount + ); + }); +} + +interface associateOptions { + approve?: boolean; + type?: string; + skipConfirmation?: boolean; +} diff --git a/apps/governance-e2e/src/support/wallet-eth.functions.js b/apps/governance-e2e/src/support/wallet-eth.functions.ts similarity index 94% rename from apps/governance-e2e/src/support/wallet-eth.functions.js rename to apps/governance-e2e/src/support/wallet-eth.functions.ts index c02ed1ad9..be28907d2 100644 --- a/apps/governance-e2e/src/support/wallet-eth.functions.js +++ b/apps/governance-e2e/src/support/wallet-eth.functions.ts @@ -3,7 +3,7 @@ const connectToEthButton = '[data-testid="connect-to-eth-wallet-button"]:visible'; const capsuleWalletConnectButton = '[data-testid="web3-connector-Unknown"]'; -Cypress.Commands.add('ethereum_wallet_connect', () => { +export function ethereumWalletConnect() { cy.highlight('Connecting Eth Wallet'); cy.get(connectToEthButton).within(() => { cy.contains('Connect Ethereum wallet to associate $VEGA') @@ -20,4 +20,4 @@ Cypress.Commands.add('ethereum_wallet_connect', () => { // It needs a few seconds before becoming operational // eslint-disable-next-line cypress/no-unnecessary-waiting cy.wait(4000); -}); +} diff --git a/apps/governance-e2e/src/support/wallet-teardown.functions.js b/apps/governance-e2e/src/support/wallet-teardown.functions.js deleted file mode 100644 index 8c9efd33a..000000000 --- a/apps/governance-e2e/src/support/wallet-teardown.functions.js +++ /dev/null @@ -1,197 +0,0 @@ -import { - StakingBridge, - Token, - TokenVesting, - TokenFaucetable, - CollateralBridge, -} from '@vegaprotocol/smart-contracts'; -import { ethers, Wallet } from 'ethers'; - -const vegaWalletContainer = 'aside [data-testid="vega-wallet"]'; -const vegaWalletMnemonic = Cypress.env('vegaWalletMnemonic'); -const vegaWalletPubKey = Cypress.env('vegaWalletPublicKey'); -const vegaTokenContractAddress = Cypress.env('vegaTokenContractAddress'); -const vegaTokenAddress = Cypress.env('vegaTokenAddress'); -const ethWalletPubKey = Cypress.env('ethWalletPublicKey'); -const ethStakingBridgeContractAddress = Cypress.env( - 'ethStakingBridgeContractAddress' -); -const ethProviderUrl = Cypress.env('ethProviderUrl'); -const getAccount = (number = 0) => `m/44'/60'/0'/0/${number}`; -const transactionTimeout = '90000'; -const Erc20BridgeAddress = '0x9708FF7510D4A7B9541e1699d15b53Ecb1AFDc54'; - -before('Vega wallet teardown prep', function () { - cy.wrap(new ethers.providers.JsonRpcProvider({ url: ethProviderUrl }), { - log: false, - }).as('provider'); - - cy.wrap(Wallet.fromMnemonic(vegaWalletMnemonic, getAccount(0)).privateKey, { - log: false, - }).then((privateKey) => { - cy.wrap(new Wallet(privateKey, this.provider), { log: false }).as('signer'); - }); - - cy.get('@signer', { log: false }).then((signer) => { - cy.wrap(new StakingBridge(ethStakingBridgeContractAddress, signer), { - log: false, - }).as('stakingBridgeContract'); - cy.wrap(new TokenVesting(vegaTokenContractAddress, signer), { - log: false, - }).as('vestingContract'); - }); -}); - -beforeEach(function () { - cy.wrap(this.stakingBridgeContract).as('stakingBridgeContract'); - cy.wrap(this.vestingContract).as('vestingContract'); -}); - -Cypress.Commands.add('deposit_asset', function (assetEthAddress, amount) { - cy.highlight('Depositing asset into vegawallet'); - cy.get('@signer', { log: false }).then((signer) => { - // Approve asset - cy.wrap( - new TokenFaucetable(assetEthAddress, signer).approve( - Erc20BridgeAddress, - amount + '0'.repeat(19) - ) - ) - .then((tx) => { - cy.wait_for_transaction(tx); - }) - .then(() => { - cy.wrap(new CollateralBridge(Erc20BridgeAddress, signer), { - log: false, - }).then((bridge) => { - // Deposit asset into vega wallet - cy.wrap( - bridge.deposit_asset( - assetEthAddress, - amount + '0'.repeat(18), - '0x' + vegaWalletPubKey - ), - { timeout: transactionTimeout, log: false } - ).then((tx) => { - cy.wait_for_transaction(tx); - }); - }); - }); - }); -}); - -Cypress.Commands.add('faucet_asset', function (assetEthAddress) { - cy.get('@signer', { log: false }).then((signer) => { - cy.wrap(new TokenFaucetable(assetEthAddress, signer), { log: false }).then( - (token) => { - cy.wrap(token.faucet(), { - timeout: transactionTimeout, - log: false, - }).then((tx) => { - cy.wait_for_transaction(tx); - }); - } - ); - }); -}); - -Cypress.Commands.add('vega_wallet_teardown', function () { - cy.get('aside [data-testid="associated-amount"]') - .should('be.visible') - .invoke('text') - .as('associatedAmount'); - cy.get('body').then(($body) => { - if ( - $body.find('[data-testid="eth-wallet-associated-balances"]').length || - this.associatedAmount != '0.00' - ) { - cy.vega_wallet_teardown_vesting(this.vestingContract); - cy.vega_wallet_teardown_staking(this.stakingBridgeContract); - } - }); - cy.get(vegaWalletContainer).within(() => { - cy.get('[data-testid="vega-wallet-balance-unstaked"]', { - timeout: 30000, - }).should('contain.text', '0.00'); - }); -}); - -Cypress.Commands.add( - 'vega_wallet_set_specified_approval_amount', - function (resetAmount) { - cy.highlight(`Setting token approval amount to ${resetAmount}`); - cy.wrap(new Token(vegaTokenAddress, this.signer), { log: false }).then( - (token) => { - cy.wrap( - token.approve( - ethStakingBridgeContractAddress, - resetAmount.concat('000000000000000000') - ), - { timeout: transactionTimeout, log: false } - ).then((tx) => { - cy.wait_for_transaction(tx); - }); - } - ); - } -); - -Cypress.Commands.add( - 'vega_wallet_teardown_staking', - (stakingBridgeContract) => { - cy.highlight('Tearing down staking tokens from vega wallet if present'); - cy.wrap( - stakingBridgeContract.stake_balance(ethWalletPubKey, vegaWalletPubKey), - { - timeout: transactionTimeout, - log: false, - } - ).then((stake_amount) => { - if (String(stake_amount) != '0') { - cy.wrap( - stakingBridgeContract.remove_stake(stake_amount, vegaWalletPubKey), - { timeout: transactionTimeout, log: false } - ).then((tx) => { - cy.wait_for_transaction(tx); - }); - } - }); - } -); - -Cypress.Commands.add('vega_wallet_teardown_vesting', (vestingContract) => { - cy.highlight('Tearing down vesting tokens from vega wallet if present'); - cy.wrap(vestingContract.stake_balance(ethWalletPubKey, vegaWalletPubKey), { - timeout: transactionTimeout, - log: false, - }).then((vesting_amount) => { - if (String(vesting_amount) != '0') { - cy.wrap(vestingContract.remove_stake(vesting_amount, vegaWalletPubKey), { - timeout: transactionTimeout, - log: false, - }).then((tx) => { - cy.wait_for_transaction(tx); - }); - } - }); -}); - -Cypress.Commands.add('vega_wallet_associate', (amount) => { - amount = amount + '0'.repeat(18); - cy.highlight('Associating tokens'); - cy.get('@stakingBridgeContract').then((stakingBridgeContract) => { - stakingBridgeContract.stake(amount, vegaWalletPubKey); - }); -}); - -Cypress.Commands.add('vega_wallet_disassociate', (amount) => { - amount = amount + '0'.repeat(18); - cy.highlight('Disassociating tokens'); - cy.get('@stakingBridgeContract').then((stakingBridgeContract) => { - stakingBridgeContract.remove_stake(amount, vegaWalletPubKey); - }); -}); - -Cypress.Commands.add('wait_for_transaction', (tx) => { - cy.wrap(tx.wait(1).catch(cy.log), { timeout: transactionTimeout }); -}); diff --git a/apps/governance-e2e/src/support/wallet-teardown.functions.ts b/apps/governance-e2e/src/support/wallet-teardown.functions.ts new file mode 100644 index 000000000..a300cec1a --- /dev/null +++ b/apps/governance-e2e/src/support/wallet-teardown.functions.ts @@ -0,0 +1,146 @@ +import { promiseWithTimeout } from '@vegaprotocol/cypress'; +import { + StakingBridge, + Token, + TokenVesting, + TokenFaucetable, + CollateralBridge, +} from '@vegaprotocol/smart-contracts'; +import { ethers, Wallet } from 'ethers'; + +const vegaWalletContainer = 'aside [data-testid="vega-wallet"]'; +const vegaWalletMnemonic = Cypress.env('vegaWalletMnemonic'); +const vegaWalletPubKey = Cypress.env('vegaWalletPublicKey'); +const vegaTokenContractAddress = Cypress.env('vegaTokenContractAddress'); +const vegaTokenAddress = Cypress.env('vegaTokenAddress'); +const ethWalletPubKey = Cypress.env('ethWalletPublicKey'); +const ethStakingBridgeContractAddress = Cypress.env( + 'ethStakingBridgeContractAddress' +); +const ethProviderUrl = Cypress.env('ethProviderUrl'); +const getAccount = (number = 0) => `m/44'/60'/0'/0/${number}`; +const transactionTimeout = 100000; +const Erc20BridgeAddress = '0x9708FF7510D4A7B9541e1699d15b53Ecb1AFDc54'; + +const provider = new ethers.providers.JsonRpcProvider({ url: ethProviderUrl }); +const privateKey = Wallet.fromMnemonic( + vegaWalletMnemonic, + getAccount(0) +).privateKey; +const signer = new Wallet(privateKey, provider); +const stakingBridgeContract = new StakingBridge( + ethStakingBridgeContractAddress, + signer +); +const vestingContract = new TokenVesting(vegaTokenContractAddress, signer); + +export async function depositAsset(assetEthAddress: string, amount: string) { + // Approve asset + const faucet = new TokenFaucetable(assetEthAddress, signer); + cy.wrap(faucet.approve(Erc20BridgeAddress, amount + '0'.repeat(19)), { + timeout: transactionTimeout, + log: false, + }).then(() => { + const collateralBridge = new CollateralBridge(Erc20BridgeAddress, signer); + cy.wrap( + collateralBridge.deposit_asset( + assetEthAddress, + amount + '0'.repeat(18), + '0x' + vegaWalletPubKey + ), + { timeout: transactionTimeout, log: false } + ); + }); +} + +export async function faucetAsset(assetEthAddress: string) { + const faucet = new TokenFaucetable(assetEthAddress, signer); + await promiseWithTimeout(faucet.faucet(), 10 * 60 * 1000, 'faucet asset'); +} + +export async function vegaWalletTeardown() { + cy.get('[data-testid="associated-amount"]') + .should('be.visible') + .invoke('text') + .then((associatedAmount) => { + cy.get('body').then(($body) => { + if ( + $body.find('[data-testid="eth-wallet-associated-balances"]').length || + associatedAmount != '0.00' + ) { + vegaWalletTeardownVesting(vestingContract); + vegaWalletTeardownStaking(stakingBridgeContract); + } + }); + cy.get(vegaWalletContainer).within(() => { + cy.getByTestId('vega-wallet-balance-staked-validators', { + timeout: transactionTimeout, + }).should('not.exist'); + cy.getByTestId('associated-amount', { + timeout: transactionTimeout, + }).contains('0.00', { + timeout: transactionTimeout, + }); + }); + }); +} + +export async function vegaWalletSetSpecifiedApprovalAmount( + resetAmount: string +) { + cy.highlight(`Setting token approval amount to ${resetAmount}`); + const token = new Token(vegaTokenAddress, signer); + await promiseWithTimeout( + token.approve( + ethStakingBridgeContractAddress, + resetAmount.concat('000000000000000000') + ), + 10 * 60 * 1000, + 'set approval amount' + ); +} + +async function vegaWalletTeardownStaking(stakingBridgeContract: StakingBridge) { + cy.highlight('Tearing down staking tokens from vega wallet if present'); + cy.wrap( + stakingBridgeContract.stake_balance(ethWalletPubKey, vegaWalletPubKey), + { timeout: transactionTimeout, log: false } + ).then((stakeBalance) => { + if (Number(stakeBalance) != 0) { + cy.wrap( + stakingBridgeContract.remove_stake( + String(stakeBalance), + vegaWalletPubKey + ), + { timeout: transactionTimeout, log: false } + ); + } + }); +} + +async function vegaWalletTeardownVesting(vestingContract: TokenVesting) { + cy.highlight('Tearing down vesting tokens from vega wallet if present'); + cy.wrap(vestingContract.stake_balance(ethWalletPubKey, vegaWalletPubKey), { + timeout: transactionTimeout, + log: false, + }).then((vestingAmount) => { + if (Number(vestingAmount) != 0) { + cy.wrap( + vestingContract.remove_stake(String(vestingAmount), vegaWalletPubKey), + { timeout: transactionTimeout, log: false } + ); + } + }); +} + +export async function vegaWalletAssociate(amount: string) { + cy.highlight('Associating tokens'); + amount = amount + '0'.repeat(18); + stakingBridgeContract.stake(amount, vegaWalletPubKey); +} + +export async function vegaWalletDisassociate(amount: string) { + cy.highlight('Disassociating tokens'); + amount = amount + '0'.repeat(18); + stakingBridgeContract.remove_stake(amount, vegaWalletPubKey); +} diff --git a/apps/governance-e2e/src/support/wallet-vega.functions.js b/apps/governance-e2e/src/support/wallet-vega.functions.js deleted file mode 100644 index 59f2e9e3e..000000000 --- a/apps/governance-e2e/src/support/wallet-vega.functions.js +++ /dev/null @@ -1,17 +0,0 @@ -Cypress.Commands.add( - 'vega_wallet_faucet_assets_without_check', - function (asset, amount, vegaWalletPublicKey) { - cy.highlight(`Topping up vega wallet with ${asset}, amount: ${amount}`); - cy.exec( - `curl -X POST -d '{"amount": "${amount}", "asset": "${asset}", "party": "${vegaWalletPublicKey}"}' http://localhost:1790/api/v1/mint` - ) - .its('stdout') - .then((response) => { - assert.include( - response, - `"success":true`, - 'Ensuring curl command was successfully undertaken' - ); - }); - } -); diff --git a/apps/governance-e2e/src/support/wallet-vega.functions.ts b/apps/governance-e2e/src/support/wallet-vega.functions.ts new file mode 100644 index 000000000..b1b761401 --- /dev/null +++ b/apps/governance-e2e/src/support/wallet-vega.functions.ts @@ -0,0 +1,18 @@ +export function vegaWalletFaucetAssetsWithoutCheck( + asset: string, + amount: string, + vegaWalletPublicKey: string +) { + cy.highlight(`Topping up vega wallet with ${asset}, amount: ${amount}`); + cy.exec( + `curl -X POST -d '{"amount": "${amount}", "asset": "${asset}", "party": "${vegaWalletPublicKey}"}' http://localhost:1790/api/v1/mint` + ) + .its('stdout') + .then((response) => { + assert.include( + response, + `"success":true`, + 'Ensuring curl command was successfully undertaken' + ); + }); +} diff --git a/apps/governance-e2e/tsconfig.json b/apps/governance-e2e/tsconfig.json index 6a18fc02a..23728f8a1 100644 --- a/apps/governance-e2e/tsconfig.json +++ b/apps/governance-e2e/tsconfig.json @@ -1,6 +1,8 @@ { "extends": "../../tsconfig.base.json", "compilerOptions": { + "target": "es5", + "lib": ["es5", "dom", "es2021"], "strict": true, "jsx": "react-jsx", "sourceMap": false, diff --git a/apps/governance/src/components/eth-wallet/eth-wallet.tsx b/apps/governance/src/components/eth-wallet/eth-wallet.tsx index 42250c0e1..071ce9a6b 100644 --- a/apps/governance/src/components/eth-wallet/eth-wallet.tsx +++ b/apps/governance/src/components/eth-wallet/eth-wallet.tsx @@ -165,7 +165,7 @@ const ConnectedKey = () => { - diff --git a/libs/cypress/src/index.ts b/libs/cypress/src/index.ts index 7876fe854..20bd283c1 100644 --- a/libs/cypress/src/index.ts +++ b/libs/cypress/src/index.ts @@ -22,6 +22,8 @@ import { addVegaWalletSubmitProposal } from './lib/commands/vega-wallet-submit-p import { addGetNodes } from './lib/commands/get-nodes'; import { addVegaWalletSubmitLiquidityProvision } from './lib/commands/vega-wallet-submit-liquidity-provision'; import { addImportNodeWallets } from './lib/commands/import-node-wallets'; +import { addVegaWalletTopUpRewardsPool } from './lib/commands/vega-wallet-top-up-rewards-pool'; +import { addAssociateTokensToVegaWallet } from './lib/commands/associate-tokens-to-vega-wallet'; addGetTestIdcommand(); addSlackCommand(); @@ -45,6 +47,8 @@ addValidatorsSelfDelegate(); addVegaWalletSubmitProposal(); addVegaWalletSubmitLiquidityProvision(); addImportNodeWallets(); +addVegaWalletTopUpRewardsPool(); +addAssociateTokensToVegaWallet(); export { mockConnectWallet, diff --git a/libs/cypress/src/lib/capsule/ethereum-setup.ts b/libs/cypress/src/lib/capsule/ethereum-setup.ts index fbd726b05..88f405c8f 100644 --- a/libs/cypress/src/lib/capsule/ethereum-setup.ts +++ b/libs/cypress/src/lib/capsule/ethereum-setup.ts @@ -34,7 +34,7 @@ export async function stakeForVegaPublicKey( ethereumConfig.staking_bridge_contract.address, amount + '0'.repeat(19) ), - 1000, + 10 * 60 * 1000, 'approve staking tx' ); diff --git a/libs/cypress/src/lib/commands/add-validators-to-multisig.ts b/libs/cypress/src/lib/commands/add-validators-to-multisig.ts index 4bad73e22..0a05ff16d 100644 --- a/libs/cypress/src/lib/commands/add-validators-to-multisig.ts +++ b/libs/cypress/src/lib/commands/add-validators-to-multisig.ts @@ -3,7 +3,7 @@ declare global { namespace Cypress { // eslint-disable-next-line @typescript-eslint/no-unused-vars interface Chainable { - updateCapsuleMultiSig(): void; + updateCapsuleMultiSig(): Chainable; } } } diff --git a/libs/cypress/src/lib/commands/associate-tokens-to-vega-wallet.ts b/libs/cypress/src/lib/commands/associate-tokens-to-vega-wallet.ts new file mode 100644 index 000000000..b49331b5b --- /dev/null +++ b/libs/cypress/src/lib/commands/associate-tokens-to-vega-wallet.ts @@ -0,0 +1,33 @@ +import { stakeForVegaPublicKey } from '../capsule/ethereum-setup'; +import { createEthereumWallet } from '../capsule/ethereum-wallet'; +import { setGraphQLEndpoint } from '../capsule/request'; +import { createWalletClient } from '../capsule/wallet-client'; + +declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace Cypress { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + interface Chainable { + associateTokensToVegaWallet(amount: string): void; + } + } +} + +export function addAssociateTokensToVegaWallet() { + Cypress.Commands.add('associateTokensToVegaWallet', (amount) => { + const ethWalletMnemonic = Cypress.env('ETH_WALLET_MNEMONIC'); + const ethereumProviderUrl = Cypress.env('ETHEREUM_PROVIDER_URL'); + const vegaWalletUrl = Cypress.env('VEGA_WALLET_URL'); + const vegaUrl = Cypress.env('VEGA_URL'); + const vegaPubKey = Cypress.env('VEGA_PUBLIC_KEY'); + const apiToken = Cypress.env('VEGA_WALLET_API_TOKEN'); + + setGraphQLEndpoint(vegaUrl); + createWalletClient(vegaWalletUrl, apiToken); + createEthereumWallet(ethWalletMnemonic, ethereumProviderUrl); + + cy.highlight('Perform Eth tx at start of test'); + + cy.wrap(stakeForVegaPublicKey(vegaPubKey, amount), { timeout: 60000 }); + }); +} diff --git a/libs/cypress/src/lib/commands/contains-exactly.ts b/libs/cypress/src/lib/commands/contains-exactly.ts index f5efdbba4..7c294e030 100644 --- a/libs/cypress/src/lib/commands/contains-exactly.ts +++ b/libs/cypress/src/lib/commands/contains-exactly.ts @@ -3,7 +3,7 @@ declare global { namespace Cypress { // eslint-disable-next-line @typescript-eslint/no-unused-vars interface Chainable { - contains_exactly(expected_result: string): void; + contains_exactly(expected_result: string): Chainable; } } } diff --git a/libs/cypress/src/lib/commands/get-network-parameters.ts b/libs/cypress/src/lib/commands/get-network-parameters.ts index 3fd91f8da..9fa5e8871 100644 --- a/libs/cypress/src/lib/commands/get-network-parameters.ts +++ b/libs/cypress/src/lib/commands/get-network-parameters.ts @@ -3,7 +3,7 @@ declare global { namespace Cypress { // eslint-disable-next-line @typescript-eslint/no-unused-vars interface Chainable { - get_network_parameters(): void; + get_network_parameters(): Chainable; } } } @@ -38,7 +38,126 @@ export function addGetNetworkParameters() { r[key] = value; return r; }, {}); - return object; + return cy.wrap(object); }); }); } + +interface networkParameters { + 'blockchains.ethereumConfig': string; + 'governance.proposal.asset.maxClose': string; + 'governance.proposal.asset.maxEnact': string; + 'governance.proposal.asset.minClose': string; + 'governance.proposal.asset.minEnact': string; + 'governance.proposal.asset.minProposerBalance': string; + 'governance.proposal.asset.minVoterBalance': string; + 'governance.proposal.asset.requiredMajority': string; + 'governance.proposal.asset.requiredParticipation': string; + 'governance.proposal.freeform.maxClose': string; + 'governance.proposal.freeform.minClose': string; + 'governance.proposal.freeform.minProposerBalance': string; + 'governance.proposal.freeform.minVoterBalance': string; + 'governance.proposal.freeform.requiredMajority': string; + 'governance.proposal.freeform.requiredParticipation': string; + 'governance.proposal.market.maxClose': string; + 'governance.proposal.market.maxEnact': string; + 'governance.proposal.market.minClose': string; + 'governance.proposal.market.minEnact': string; + 'governance.proposal.market.minProposerBalance': string; + 'governance.proposal.market.minVoterBalance': string; + 'governance.proposal.market.requiredMajority': string; + 'governance.proposal.market.requiredParticipation': string; + 'governance.proposal.updateAsset.maxClose': string; + 'governance.proposal.updateAsset.maxEnact': string; + 'governance.proposal.updateAsset.minClose': string; + 'governance.proposal.updateAsset.minEnact': string; + 'governance.proposal.updateAsset.minProposerBalance': string; + 'governance.proposal.updateAsset.minVoterBalance': string; + 'governance.proposal.updateAsset.requiredMajority': string; + 'governance.proposal.updateAsset.requiredParticipation': string; + 'governance.proposal.updateMarket.maxClose': string; + 'governance.proposal.updateMarket.maxEnact': string; + 'governance.proposal.updateMarket.minClose': string; + 'governance.proposal.updateMarket.minEnact': string; + 'governance.proposal.updateMarket.minProposerBalance': string; + 'governance.proposal.updateMarket.minProposerEquityLikeShare': string; + 'governance.proposal.updateMarket.minVoterBalance': string; + 'governance.proposal.updateMarket.requiredMajority': string; + 'governance.proposal.updateMarket.requiredMajorityLP': string; + 'governance.proposal.updateMarket.requiredParticipation': string; + 'governance.proposal.updateMarket.requiredParticipationLP': string; + 'governance.proposal.updateNetParam.maxClose': string; + 'governance.proposal.updateNetParam.maxEnact': string; + 'governance.proposal.updateNetParam.minClose': string; + 'governance.proposal.updateNetParam.minEnact': string; + 'governance.proposal.updateNetParam.minProposerBalance': string; + 'governance.proposal.updateNetParam.minVoterBalance': string; + 'governance.proposal.updateNetParam.requiredMajority': string; + 'governance.proposal.updateNetParam.requiredParticipation': string; + 'limits.assets.proposeEnabledFrom': string; + 'limits.markets.maxPeggedOrders': string; + 'limits.markets.proposeEnabledFrom': string; + 'market.auction.maximumDuration': string; + 'market.auction.minimumDuration': string; + 'market.fee.factors.infrastructureFee': string; + 'market.fee.factors.makerFee': string; + 'market.liquidity.bondPenaltyParameter': string; + 'market.liquidity.maximumLiquidityFeeFactorLevel': string; + 'market.liquidity.minimum.probabilityOfTrading.lpOrders': string; + 'market.liquidity.probabilityOfTrading.tau.scaling': string; + 'market.liquidity.providers.fee.distributionTimeStep': string; + 'market.liquidity.stakeToCcyVolume': string; + 'market.liquidity.targetstake.triggering.ratio': string; + 'market.liquidityProvision.minLpStakeQuantumMultiple': string; + 'market.liquidityProvision.shapes.maxSize': string; + 'market.margin.scalingFactors': string; + 'market.monitor.price.defaultParameters': string; + 'market.stake.target.scalingFactor': string; + 'market.stake.target.timeWindow': string; + 'market.value.windowLength': string; + 'network.checkpoint.timeElapsedBetweenCheckpoints': string; + 'network.floatingPointUpdates.delay': string; + 'network.markPriceUpdateMaximumFrequency': string; + 'network.transaction.defaultgas': string; + 'network.transactions.maxgasperblock': string; + 'network.transactions.minBlockCapacity': string; + 'network.validators.ersatz.multipleOfTendermintValidators': string; + 'network.validators.ersatz.rewardFactor': string; + 'network.validators.incumbentBonus': string; + 'network.validators.minimumEthereumEventsForNewValidator': string; + 'network.validators.multisig.numberOfSigners': string; + 'network.validators.tendermint.number': string; + 'reward.asset': string; + 'reward.staking.delegation.competitionLevel': string; + 'reward.staking.delegation.delegatorShare': string; + 'reward.staking.delegation.maxPayoutPerEpoch': string; + 'reward.staking.delegation.maxPayoutPerParticipant': string; + 'reward.staking.delegation.minValidators': string; + 'reward.staking.delegation.minimumValidatorStake': string; + 'reward.staking.delegation.optimalStakeMultiplier': string; + 'reward.staking.delegation.payoutDelay': string; + 'reward.staking.delegation.payoutFraction': string; + 'rewards.marketCreationQuantumMultiple': string; + 'snapshot.interval.length': string; + 'spam.pow.difficulty': string; + 'spam.pow.hashFunction': string; + 'spam.pow.increaseDifficulty': string; + 'spam.pow.numberOfPastBlocks': string; + 'spam.pow.numberOfTxPerBlock': string; + 'spam.protection.delegation.min.tokens': string; + 'spam.protection.max.batchSize': string; + 'spam.protection.max.delegations': string; + 'spam.protection.max.proposals': string; + 'spam.protection.max.votes': string; + 'spam.protection.maxUserTransfersPerEpoch': string; + 'spam.protection.minMultisigUpdates': string; + 'spam.protection.minimumWithdrawalQuantumMultiple': string; + 'spam.protection.proposal.min.tokens': string; + 'spam.protection.voting.min.tokens': string; + 'transfer.fee.factor': string; + 'transfer.minTransferQuantumMultiple': string; + 'validator.performance.scaling.factor': string; + 'validators.delegation.minAmount': string; + 'validators.epoch.length': string; + 'validators.vote.required': string; +} diff --git a/libs/cypress/src/lib/commands/vega-wallet-receive-fauceted-asset.ts b/libs/cypress/src/lib/commands/vega-wallet-receive-fauceted-asset.ts index adb617278..0c88c61f6 100644 --- a/libs/cypress/src/lib/commands/vega-wallet-receive-fauceted-asset.ts +++ b/libs/cypress/src/lib/commands/vega-wallet-receive-fauceted-asset.ts @@ -21,10 +21,10 @@ export function addVegaWalletReceiveFaucetedAsset() { `Topping up vega wallet with ${assetName}, amount: ${amount}` ); // @ts-ignore - ignoring Cypress type error which gets resolved when Cypress uses the command - cy.getAssets().then((assets) => { - console.log(assets); - const asset = assets.find((a) => a.name === assetName); - if (asset) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + cy.getAssets().then((assets: any) => { + const asset = assets[assetName]; + if (assets[assetName] !== undefined) { for (let i = 0; i < asset.decimals; i++) amount += '0'; cy.exec( `curl -X POST -d '{"amount": "${amount}", "asset": "${asset.id}", "party": "${vegaWalletPublicKey}"}' http://localhost:1790/api/v1/mint` @@ -38,7 +38,10 @@ export function addVegaWalletReceiveFaucetedAsset() { ); }); } else { - const validAssets = assets.filter((a) => a.name.includes('fake')); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const validAssets = assets.filter((a: any) => + a.name.includes('fake') + ); assert.exists( asset, `${assetName} is not a faucet-able asset, only the following assets can be faucet-ed: ${validAssets}` diff --git a/libs/cypress/src/lib/commands/vega-wallet-top-up-rewards-pool.ts b/libs/cypress/src/lib/commands/vega-wallet-top-up-rewards-pool.ts new file mode 100644 index 000000000..4b06b3e2e --- /dev/null +++ b/libs/cypress/src/lib/commands/vega-wallet-top-up-rewards-pool.ts @@ -0,0 +1,50 @@ +import { AccountType } from '@vegaprotocol/types'; +import type { TransferBody } from '@vegaprotocol/wallet'; +import { createWalletClient, sendVegaTx } from '../capsule/wallet-client'; + +declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace Cypress { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + interface Chainable { + VegaWalletTopUpRewardsPool( + transferStartEpoch: number, + transferEndEpoch: number + ): void; + } + } +} + +export function addVegaWalletTopUpRewardsPool() { + Cypress.Commands.add( + 'VegaWalletTopUpRewardsPool', + (transferStartEpoch, transferEndEpoch) => { + const vegaWalletUrl = Cypress.env('VEGA_WALLET_URL'); + const token = Cypress.env('VEGA_WALLET_API_TOKEN'); + const vegaPubKey = Cypress.env('VEGA_PUBLIC_KEY'); + const assetAddress = + 'b4f2726571fbe8e33b442dc92ed2d7f0d810e21835b7371a7915a365f07ccd9b'; + + createWalletClient(vegaWalletUrl, token); + + const transactionBody: TransferBody = { + transfer: { + fromAccountType: AccountType.ACCOUNT_TYPE_GENERAL, + toAccountType: AccountType.ACCOUNT_TYPE_GLOBAL_REWARD, + to: '0000000000000000000000000000000000000000000000000000000000000000', + asset: assetAddress, + amount: '1000000000000000000', + recurring: { + factor: '1', + startEpoch: transferStartEpoch, + endEpoch: transferEndEpoch, + }, + }, + }; + + cy.highlight('Topping up rewards pool'); + + sendVegaTx(vegaPubKey, transactionBody); + } + ); +} diff --git a/vegacapsule/node_set_templates/default/data_node_full_external_postgres.tmpl b/vegacapsule/node_set_templates/default/data_node_full_external_postgres.tmpl index 237249399..6f6629aa4 100644 --- a/vegacapsule/node_set_templates/default/data_node_full_external_postgres.tmpl +++ b/vegacapsule/node_set_templates/default/data_node_full_external_postgres.tmpl @@ -37,7 +37,7 @@ GatewayEnabled = true Port = {{add 210 .NodeNumber}}2 Enabled = false [Broker] - Level = "Info" + Level = "Debug" UseEventFile = false [Broker.SocketConfig] Port = {{add 300 .NodeNumber}}5 @@ -54,6 +54,7 @@ GatewayEnabled = true {{- end -}}] UseIpfsDefaultPeers = false - SwarmPort = 40{{.NodeNumber}}5 + SwarmPort = {{add 400 .NodeNumber}}5 StartWebUI = false - WebUIPort = 50{{.NodeNumber}}5 + WebUIPort = {{add 500 .NodeNumber}}5 + SwarmKeyOverride = "{{ .NodeSet.DataNode.UniqueSwarmKey }}" diff --git a/vegacapsule/node_set_templates/default/data_node_full_snapshots.tmpl b/vegacapsule/node_set_templates/default/data_node_full_snapshots.tmpl index c89aa82fc..8b5a68432 100644 --- a/vegacapsule/node_set_templates/default/data_node_full_snapshots.tmpl +++ b/vegacapsule/node_set_templates/default/data_node_full_snapshots.tmpl @@ -60,6 +60,7 @@ GatewayEnabled = true SwarmPort = {{add 400 .NodeNumber}}5 StartWebUI = false WebUIPort = {{add 500 .NodeNumber}}5 + SwarmKeyOverride = "{{ .NodeSet.DataNode.UniqueSwarmKey }}" [NetworkHistory.Snapshot] PanicOnSnapshotCreationError = true WaitForCreationLockTimeout = "5s" diff --git a/vegacapsule/node_set_templates/default/tendermint_full.tmpl b/vegacapsule/node_set_templates/default/tendermint_full.tmpl index 79fbbf697..07e10a480 100644 --- a/vegacapsule/node_set_templates/default/tendermint_full.tmpl +++ b/vegacapsule/node_set_templates/default/tendermint_full.tmpl @@ -1,29 +1,35 @@ log_level = "info" -proxy_app = "tcp://127.0.0.1:{{add 2660 .NodeNumber}}8" +proxy_app = "tcp://127.0.0.1:26{{ printf "%02d" (add .NodeNumber 60) }}8" moniker = "{{.TendermintNodePrefix}}-{{.NodeNumber}}" [rpc] - laddr = "tcp://0.0.0.0:{{add 2660 .NodeNumber}}7" + laddr = "tcp://0.0.0.0:26{{ printf "%02d" (add .NodeNumber 60) }}7" unsafe = true - cors_allowed_origins = ["*"] - cors_allowed_methods = ["HEAD", "GET", "POST", ] - cors_allowed_headers = ["Origin", "Accept", "Content-Type", "X-Requested-With", "X-Server-Time", ] [p2p] - laddr = "tcp://0.0.0.0:{{add 2660 .NodeNumber}}6" + laddr = "tcp://0.0.0.0:26{{ printf "%02d" (add .NodeNumber 60) }}6" addr_book_strict = false max_packet_msg_payload_size = 4096 pex = false allow_duplicate_ip = true persistent_peers = "{{- range $i, $peer := .NodePeers -}} - {{- if ne $i 0 }},{{end -}} - {{- $peer.ID}}@127.0.0.1:{{add 2660 $peer.Index}}6 + {{- if ne $i 0 }},{{end -}} + {{- $peer.ID}}@127.0.0.1:26{{ printf "%02d" (add $peer.Index 60) }}6 {{- end -}}" + persistent_peers_max_dial_period = "5s" + [mempool] size = 10000 cache_size = 20000 [consensus] skip_timeout_commit = true + +[statesync] + enable = false + rpc_servers = "{{- range $i, $peer := .NodePeers -}} + {{- if ne $i 0 }},{{end -}} + 127.0.0.1:26{{ printf "%02d" (add $peer.Index 60) }}7 + {{- end -}}" diff --git a/vegacapsule/node_set_templates/default/vega_full.tmpl b/vegacapsule/node_set_templates/default/vega_full.tmpl index bcdd52692..cd1607a19 100644 --- a/vegacapsule/node_set_templates/default/vega_full.tmpl +++ b/vegacapsule/node_set_templates/default/vega_full.tmpl @@ -1,32 +1,133 @@ [Admin] - [Admin.Server] - SocketPath = "/tmp/vega-{{.NodeNumber}}.sock" - Enabled = true + [Admin.Server] + SocketPath = "{{.NodeHomeDir}}/vega.sock" + Enabled = true [API] - Port = {{add 300 .NodeNumber}}2 + Level = "Info" + Port = 3{{ printf "%02d" .NodeNumber }}2 [API.REST] - Port = {{add 300 .NodeNumber}}3 + Port = 3{{ printf "%02d" .NodeNumber }}3 [Blockchain] + Level = "Info" [Blockchain.Tendermint] - RPCAddr = "tcp://127.0.0.1:{{add 2660 .NodeNumber}}7" + Level = "Info" + RPCAddr = "tcp://127.0.0.1:26{{ printf "%02d" (add .NodeNumber 60) }}7" [Blockchain.Null] - Port = {{add 310 .NodeNumber}}1 + Level = "Info" + Port = 3{{ printf "%02d" (add .NodeNumber 10) }}1 + +[Collateral] + Level = "Info" + +[CoreAPI] + LogLevel = "Info" + +[Execution] + Level = "Info" + [Execution.Matching] + Level = "Info" + [Execution.Risk] + Level = "Info" + [Execution.Position] + Level = "Info" + LogPositionUpdate = true + [Execution.Settlement] + Level = "Info" + [Execution.Fee] + Level = "Info" + [Execution.Liquidity] + Level = "Info" [EvtForward] Level = "Info" RetryRate = "1s" + [EvtForward.Ethereum] + Level = "Info" [Ethereum] RPCEndpoint = "{{.ETHEndpoint}}" +[NodeWallet] + Level = "Info" + [NodeWallet.ETH] + Level = "Info" + [Processor] + Level = "Info" [Processor.Ratelimit] Requests = 10000 PerNBlocks = 1 +[Oracles] + Level = "Info" + +[Time] + Level = "Info" + +[Epoch] + Level = "Info" + +[Monitoring] + Level = "Info" + +[Metrics] + Level = "Info" + +[Governance] + Level = "Info" +[Assets] + Level = "Info" + +[Notary] + Level = "Info" + +[Genesis] + Level = "Info" + +[Validators] + Level = "Info" + +[Banking] + Level = "Info" + +[Stats] + Level = "Info" + +[NetworkParameters] + Level = "Info" + +[Limits] + Level = "Info" + +[Checkpoint] + Level = "Info" + +[Staking] + Level = "Info" + [Broker] - [Broker.Socket] - Port = {{add 300 .NodeNumber}}5 - Enabled = true + Level = "Info" + [Broker.Socket] + Port = 3{{ printf "%02d" .NodeNumber }}5 + Enabled = true + + +[Rewards] + Level = "Info" + +[Delegation] + Level = "Info" + +[Spam] + Level = "Info" + +[Snapshot] + Level = "Info" + +[StateVar] + Level = "Info" + +[Pprof] + Level = "Info"