From 181819fb2482aaad57ffc8d744a013f5682f000f Mon Sep 17 00:00:00 2001 From: Joe Tsang <30622993+jtsang586@users.noreply.github.com> Date: Fri, 5 Aug 2022 17:59:44 +0100 Subject: [PATCH] Test/868 staking ACs (#939) * test: staking validation tests * chore: standardise codes * chore: standardise codes * test: additional ACs added and view tests mostly done * chore: update codes * test: staking tests passing * chore: remove comments and formatting * test: fix staking view tests * fix: empty string assertion * fix: lint * chore: remove unnecessary assertions Co-authored-by: Edd --- apps/token-e2e/cypress.config.js | 2 + .../src/integration/flow/staking-flow.cy.js | 255 +++++++++--------- .../src/integration/view/staking.cy.js | 182 ++++++++++++- .../src/support/staking.functions.js | 55 +++- .../src/routes/staking/validator-table.tsx | 40 ++- 5 files changed, 382 insertions(+), 152 deletions(-) diff --git a/apps/token-e2e/cypress.config.js b/apps/token-e2e/cypress.config.js index 56171865b..72f5a6654 100644 --- a/apps/token-e2e/cypress.config.js +++ b/apps/token-e2e/cypress.config.js @@ -40,5 +40,7 @@ module.exports = defineConfig({ vegaWalletPublicKeyShort: '02ecea…2f65', vegaTokenContractAddress: '0xF41bD86d462D36b997C0bbb4D97a0a3382f205B7', vegaTokenAddress: '0x67175Da1D5e966e40D11c4B2519392B2058373de', + epochTimeout: { timeout: 10000 }, + txTimeout: { timeout: 40000 }, }, }); diff --git a/apps/token-e2e/src/integration/flow/staking-flow.cy.js b/apps/token-e2e/src/integration/flow/staking-flow.cy.js index 0d7d826bd..e649a7df3 100644 --- a/apps/token-e2e/src/integration/flow/staking-flow.cy.js +++ b/apps/token-e2e/src/integration/flow/staking-flow.cy.js @@ -1,6 +1,7 @@ /// -const stakeValidatorList = '[data-testid="node-list-item-name"]'; -const stakeValidatorWithinList = '[data-testid="node-list-item"]'; +const stakeValidatorListTotalStake = '[col-id="totalStakeThisEpoch"]'; +const stakeValidatorListTotalShare = '[col-id="share"]'; +const stakeValdatorListValidatorStake = '[col-id="validatorStake"]'; const stakeRemoveStakeRadioButton = '[data-testid="remove-stake-radio"]'; const stakeTokenAmountInputBox = '[data-testid="token-amount-input"]'; const stakeTokenSubmitButton = '[data-testid="token-input-submit-button"]'; @@ -8,6 +9,8 @@ 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 = @@ -22,11 +25,12 @@ const ethWalletAssociatedBalances = '[data-testid="eth-wallet-associated-balances"]'; const ethWalletTotalAssociatedBalance = '[data-testid="currency-locked"]'; const ethWalletContainer = '[data-testid="ethereum-wallet"]'; -const txTimeout = { timeout: 40000 }; -const epochTimeout = { timeout: 10000 }; +const partValidatorId = '…'; +const txTimeout = Cypress.env('txTimeout'); +const epochTimeout = Cypress.env('epochTimeout'); -// Tests skipped because of change of the UI of data nodes -context.skip('Staking Tab - with eth and vega wallets connected', function () { +context('Staking Tab - with eth and vega wallets connected', function () { + // 1002-STKE-002, 1002-STKE-032 before('visit staking tab and connect vega wallet', function () { cy.vega_wallet_import(); cy.visit('/'); @@ -38,8 +42,6 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () { cy.ethereum_wallet_connect(); cy.navigate_to('staking'); cy.wait_for_spinner(); - cy.get(stakeValidatorList).first().invoke('text').as('validatorName'); - cy.get(stakeValidatorList).last().invoke('text').as('otherValidatorName'); }); describe('Eth wallet - contains VEGA tokens', function () { @@ -51,6 +53,7 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () { } ); + // 1002-STKE-004 it('Able to stake against a validator', function () { cy.staking_page_associate_tokens('3'); @@ -71,13 +74,16 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () { cy.get('button').contains('Select a validator to nominate').click(); - cy.get(stakeValidatorList).contains(this.validatorName).click(); + // 1002-STKE-031 + cy.click_on_validator_from_list(0); + // 1002-STKE-033, 1002-STKE-034, 1002-STKE-037 cy.staking_validator_page_add_stake('2'); + // 1002-STKE-038 cy.get(vegaWalletNextEpochBalances, txTimeout) .should('contain', 2.0, txTimeout) - .and('contain', this.validatorName) + .and('contain', partValidatorId) .and('contain', 'Next epoch'); cy.get(vegaWalletUnstakedBalance, txTimeout).should( @@ -86,30 +92,25 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () { txTimeout ); + // 1002-STKE-039 cy.get(vegaWalletStakedBalances, txTimeout) .should('contain', 2.0, txTimeout) - .and('contain', this.validatorName); + .and('contain', partValidatorId); - cy.get(stakeNextEpochValue, epochTimeout) + cy.get(stakeNextEpochValue, epochTimeout) // 1002-STKE-016 .contains(2.0, epochTimeout) .should('be.visible'); - cy.get(stakeThisEpochValue, epochTimeout) + cy.get(stakeThisEpochValue, epochTimeout) // 1002-STKE-013 .contains(2.0, epochTimeout) .should('be.visible'); cy.navigate_to('staking'); - cy.get(stakeValidatorWithinList, epochTimeout) - .contains(this.validatorName) - .parent() - .contains('Total stake') - .parent() - .should('contain', '2.0') - .and('contain', '100%'); + cy.validate_validator_list_total_stake_and_share('0', '', '2.00', '100%'); }); - it('Able to stake against mulitple validators', function () { + it('Able to stake against multiple validators', function () { cy.staking_page_associate_tokens('5'); cy.get(vegaWalletUnstakedBalance, txTimeout).should( @@ -119,30 +120,29 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () { ); cy.get('button').contains('Select a validator to nominate').click(); - cy.get(stakeValidatorList).contains(this.validatorName).click(); + + cy.click_on_validator_from_list(0); cy.staking_validator_page_add_stake('2'); cy.get(vegaWalletStakedBalances, txTimeout) - .contains(this.validatorName, txTimeout) .parent() .should('contain', 2.0, txTimeout); cy.navigate_to('staking'); - cy.get(stakeValidatorList).contains(this.otherValidatorName).click(); + + cy.click_on_validator_from_list(1); cy.staking_validator_page_add_stake('1'); cy.get(vegaWalletStakedBalances, txTimeout) .should('have.length', 2, txTimeout) - .contains(this.otherValidatorName, txTimeout) - .parent() - .should('contain', 1.0, txTimeout); + .eq(0) + .should('contain', 2.0, txTimeout); cy.get(vegaWalletStakedBalances, txTimeout) - .contains(this.validatorName, txTimeout) - .parent() - .should('contain', 2.0, txTimeout); + .eq(1) + .should('contain', 1.0, txTimeout); cy.get(vegaWalletUnstakedBalance, txTimeout).should( 'contain', @@ -152,23 +152,20 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () { cy.navigate_to('staking'); - cy.get(stakeValidatorWithinList, epochTimeout) - .contains(this.validatorName) - .parent() - .contains('Total stake') - .parent() - .should('contain', '2.0') - .and('contain', '66.67%'); + cy.get(`[row-id="${0}"]`).within(() => { + cy.get(stakeValidatorListTotalStake).should('have.text', '3.00'); + cy.get(stakeValidatorListTotalShare).should('have.text', '66.67%'); + cy.get(stakeValdatorListValidatorStake).should('have.text', '2.00'); + }); - cy.get(stakeValidatorWithinList, epochTimeout) - .contains(this.otherValidatorName) - .parent() - .contains('Total stake') - .parent() - .should('contain', '1.0') - .and('contain', '33.33%'); + cy.get(`[row-id="${1}"]`).within(() => { + cy.get(stakeValidatorListTotalStake).should('have.text', '3.00'); + cy.get(stakeValidatorListTotalShare).should('have.text', '33.33%'); + cy.get(stakeValdatorListValidatorStake).should('have.text', '1.00'); + }); }); + // 1002-STKE-041 it('Able to remove part of a stake against a validator', function () { cy.staking_page_associate_tokens('4'); @@ -179,7 +176,8 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () { ); cy.get('button').contains('Select a validator to nominate').click(); - cy.get(stakeValidatorList).contains(this.validatorName).click(); + + cy.click_on_validator_from_list(0); cy.staking_validator_page_add_stake('3'); @@ -187,10 +185,11 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () { .contains(3.0, epochTimeout) .should('be.visible'); - cy.get(vegaWalletNextEpochBalances, txTimeout) - .should('contain', 3.0, txTimeout) - .and('contain', this.validatorName) - .and('contain', 'Next epoch'); + cy.get(vegaWalletNextEpochBalances, txTimeout).should( + 'contain', + 3.0, + txTimeout + ); cy.get(vegaWalletUnstakedBalance, txTimeout).should( 'contain', @@ -199,22 +198,24 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () { ); cy.navigate_to('staking'); - cy.get(stakeValidatorList).contains(this.validatorName).click(); + // 1002-STKE-040 + cy.click_on_validator_from_list(0); + // 1002-STKE-044, 1002-STKE-048 cy.staking_validator_page_remove_stake('1'); - cy.get(stakeNextEpochValue, epochTimeout) - .contains(2.0, epochTimeout) - .should('be.visible'); + // 1002-STKE-049 + cy.get(stakeNextEpochValue, epochTimeout).contains(2.0, epochTimeout); - cy.get(vegaWalletNextEpochBalances, txTimeout) - .should('contain', 2.0, txTimeout) - .and('contain', this.validatorName) - .and('contain', 'Next epoch'); + cy.get(vegaWalletNextEpochBalances, txTimeout).should( + 'contain', + 2.0, + txTimeout + ); cy.get(vegaWalletThisEpochBalances, txTimeout) .should('contain', 3.0, txTimeout) - .and('contain', this.validatorName) + .and('contain', partValidatorId) .and('contain', 'This Epoch'); cy.get(vegaWalletUnstakedBalance, txTimeout).should( @@ -223,9 +224,11 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () { txTimeout ); - cy.get(vegaWalletStakedBalances, txTimeout) - .should('contain', 2.0, txTimeout) - .and('contain', this.validatorName); + cy.get(vegaWalletStakedBalances, txTimeout).should( + 'contain', + 2.0, + txTimeout + ); cy.get(stakeNextEpochValue, epochTimeout) .contains(2.0, epochTimeout) @@ -235,15 +238,13 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () { .contains(2.0, epochTimeout) .should('be.visible'); + cy.get(totalStake).should('have.text', '2'); + + cy.get(stakeShare).should('have.text', '100%'); + cy.navigate_to('staking'); - cy.get(stakeValidatorWithinList, epochTimeout) - .contains(this.validatorName) - .parent() - .contains('Total stake') - .parent() - .should('contain', '2.0') - .and('contain', '100%'); + cy.validate_validator_list_total_stake_and_share('0', '', '2.00', '100%'); }); it('Able to remove a full stake against a validator', function () { @@ -257,14 +258,15 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () { cy.get('button').contains('Select a validator to nominate').click(); - cy.get(stakeValidatorList).contains(this.validatorName).click(); + cy.click_on_validator_from_list(0); cy.staking_validator_page_add_stake('1'); - cy.get(vegaWalletNextEpochBalances, txTimeout) - .should('contain', 1.0, txTimeout) - .and('contain', this.validatorName) - .and('contain', 'Next epoch'); + cy.get(vegaWalletNextEpochBalances, txTimeout).should( + 'contain', + 1.0, + txTimeout + ); cy.get(vegaWalletUnstakedBalance, txTimeout).should( 'contain', @@ -274,7 +276,7 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () { cy.navigate_to('staking'); - cy.get(stakeValidatorList).contains(this.validatorName).click(); + cy.click_on_validator_from_list('0'); cy.staking_validator_page_remove_stake('1'); @@ -282,15 +284,17 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () { .contains(0.0, epochTimeout) .should('be.visible'); - cy.get(vegaWalletThisEpochBalances, txTimeout) - .should('contain', 1.0, txTimeout) - .and('contain', this.validatorName) - .and('contain', 'This Epoch'); + cy.get(vegaWalletThisEpochBalances, txTimeout).should( + 'contain', + 1.0, + txTimeout + ); - cy.get(vegaWalletNextEpochBalances, txTimeout) - .should('contain', 0.0, txTimeout) - .and('contain', this.validatorName) - .and('contain', 'Next epoch'); + cy.get(vegaWalletNextEpochBalances, txTimeout).should( + 'contain', + 0.0, + txTimeout + ); cy.get(vegaWalletUnstakedBalance, txTimeout).should( 'contain', @@ -307,17 +311,12 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () { .should('be.visible'); cy.get(vegaWalletStakedBalances, txTimeout) - .contains(this.validatorName, txTimeout) + .contains(partValidatorId, txTimeout) .should('not.exist', txTimeout); cy.navigate_to('staking'); - cy.get(stakeValidatorWithinList, epochTimeout) - .contains(this.validatorName) - .parent() - .contains('Total stake') - .parent() - .should('contain', '0.0'); + cy.validate_validator_list_total_stake_and_share('0', '', '0.00', '-'); }); it('Unable to remove a stake with a negative value for a validator', function () { @@ -331,7 +330,7 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () { cy.get('button').contains('Select a validator to nominate').click(); - cy.get(stakeValidatorList).contains(this.validatorName).click(); + cy.click_on_validator_from_list(0); cy.staking_validator_page_add_stake('2'); @@ -339,10 +338,11 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () { .contains(2.0, epochTimeout) .should('be.visible'); - cy.get(vegaWalletNextEpochBalances, txTimeout) - .should('contain', 2.0, txTimeout) - .and('contain', this.validatorName) - .and('contain', 'Next epoch'); + cy.get(vegaWalletNextEpochBalances, txTimeout).should( + 'contain', + 2.0, + txTimeout + ); cy.get(vegaWalletUnstakedBalance, txTimeout).should( 'contain', @@ -352,9 +352,9 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () { cy.navigate_to('staking'); - cy.get(stakeValidatorList).contains(this.validatorName).click(); + cy.click_on_validator_from_list(0); - cy.get(stakeRemoveStakeRadioButton).click({ force: true }); + cy.get(stakeRemoveStakeRadioButton, txTimeout).click(); cy.get(stakeTokenAmountInputBox).type('-0.1'); @@ -377,7 +377,7 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () { cy.get('button').contains('Select a validator to nominate').click(); - cy.get(stakeValidatorList).contains(this.validatorName).click(); + cy.click_on_validator_from_list(0); cy.staking_validator_page_add_stake('2'); @@ -387,8 +387,7 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () { cy.get(vegaWalletNextEpochBalances, txTimeout) .should('contain', 2.0, txTimeout) - .and('contain', this.validatorName) - .and('contain', 'Next epoch'); + .and('contain', partValidatorId); cy.get(vegaWalletUnstakedBalance, txTimeout).should( 'contain', @@ -398,9 +397,9 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () { cy.navigate_to('staking'); - cy.get(stakeValidatorList).contains(this.validatorName).click(); + cy.click_on_validator_from_list(0); - cy.get(stakeRemoveStakeRadioButton).click({ force: true }); + cy.get(stakeRemoveStakeRadioButton).click(); cy.get(stakeTokenAmountInputBox).type(4); @@ -412,7 +411,7 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () { .and('be.visible'); }); - it.skip('Disassociating all tokens max - removes all staked tokens', function () { + it('Disassociating all tokens max - removes all staked tokens', function () { cy.staking_page_associate_tokens('3'); cy.get(vegaWalletUnstakedBalance, txTimeout).should( @@ -423,7 +422,7 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () { cy.get('button').contains('Select a validator to nominate').click(); - cy.get(stakeValidatorList).contains(this.validatorName).click(); + cy.click_on_validator_from_list('1'); cy.staking_validator_page_add_stake('2'); @@ -433,9 +432,11 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () { txTimeout ); - cy.get(vegaWalletStakedBalances, txTimeout) - .should('contain', 2.0, txTimeout) - .and('contain', this.validatorName); + cy.get(vegaWalletStakedBalances, txTimeout).should( + 'contain', + 2.0, + txTimeout + ); cy.navigate_to('staking'); @@ -457,18 +458,14 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () { txTimeout ); - cy.get(vegaWalletStakedBalances, txTimeout) - .contains(this.validatorName, txTimeout) - .should('not.exist', txTimeout); + cy.get(vegaWalletStakedBalances, txTimeout).should( + 'not.exist', + txTimeout + ); cy.navigate_to('staking'); - cy.get(stakeValidatorWithinList, epochTimeout) - .contains(this.validatorName) - .parent() - .contains('Total stake') - .parent() - .should('contain', '0.0'); + cy.validate_validator_list_total_stake_and_share('0', '', '0.00', '-'); }); it('Disassociating some tokens - prioritizes unstaked tokens', function () { @@ -481,7 +478,7 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () { ); cy.get('button').contains('Select a validator to nominate').click(); - cy.get(stakeValidatorList).contains(this.validatorName).click(); + cy.click_on_validator_from_list(0); cy.staking_validator_page_add_stake('2'); cy.get(vegaWalletUnstakedBalance, txTimeout).should( @@ -490,9 +487,11 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () { txTimeout ); - cy.get(vegaWalletStakedBalances, txTimeout) - .should('contain', 2.0, txTimeout) - .and('contain', this.validatorName); + cy.get(vegaWalletStakedBalances, txTimeout).should( + 'contain', + 2.0, + txTimeout + ); cy.navigate_to('staking'); @@ -510,20 +509,14 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () { cy.get(vegaWalletStakedBalances, txTimeout) .should('contain', 2.0, txTimeout) - .and('contain', this.validatorName); + .and('contain', partValidatorId); cy.navigate_to('staking'); - cy.get(stakeValidatorWithinList, epochTimeout) - .contains(this.validatorName) - .parent() - .contains('Total stake') - .parent() - .should('contain', '2.0') - .and('contain', '100%'); + cy.validate_validator_list_total_stake_and_share('0', '', '2.00', '100%'); }); - it('Selecting use maximum where tokens are allready staked - suggests the unstaked token amount', function () { + 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( @@ -533,7 +526,7 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () { ); cy.get('button').contains('Select a validator to nominate').click(); - cy.get(stakeValidatorList).contains(this.validatorName).click(); + cy.click_on_validator_from_list(0); cy.staking_validator_page_add_stake('2'); @@ -545,9 +538,9 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () { cy.navigate_to('staking'); - cy.get(stakeValidatorList).contains(this.otherValidatorName).click(); + cy.click_on_validator_from_list(0); - cy.get(stakeAddStakeRadioButton).click({ force: true }); + cy.get(stakeAddStakeRadioButton).click(); cy.get(stakeMaximumTokens, { timeout: 60000 }).click(); diff --git a/apps/token-e2e/src/integration/view/staking.cy.js b/apps/token-e2e/src/integration/view/staking.cy.js index 28c3e0506..f601f64ce 100644 --- a/apps/token-e2e/src/integration/view/staking.cy.js +++ b/apps/token-e2e/src/integration/view/staking.cy.js @@ -1,5 +1,18 @@ +/// const guideLink = '[data-testid="staking-guide-link"]'; -const validators = '[data-testid="validators-grid"]'; +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 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 epochCountDown = '[data-testid="epoch-countdown"]'; +const stakeNumberRegex = /^\d*\.?\d*$/; +const ownStake = '[data-testid="own-stake"]'; +const nominatedStake = '[data-testid="nominated-stake"]'; context('Staking Page - verify elements on page', function () { before('navigate to staking page', function () { @@ -17,6 +30,7 @@ context('Staking Page - verify elements on page', function () { }); it('should have Staking Guide link visible', function () { + // 1002-STKE-003 cy.get(guideLink) .should('be.visible') .and('have.text', 'Read more about staking on Vega') @@ -27,9 +41,169 @@ context('Staking Page - verify elements on page', function () { ); }); }); - describe('validators section', function () { - it('should be visible', function () { - cy.get(validators).should('be.visible'); + + describe('Should be able to see validator list from the staking page', function () { + // 1002-STKE-050 + it('Should be able to see validator names', function () { + cy.get('[col-id="validator"]') + .should('have.length.at.least', 1) + .each(($name) => { + cy.wrap($name).should('not.be.empty'); + }); + }); + + it('Should be able to see validator status', function () { + cy.get('[col-id="status"]') + .should('have.length.at.least', 1) + .each(($status) => { + cy.wrap($status).should('not.be.empty'); + }); + }); + + it('Should be able to see total stake for this epoch', function () { + cy.get('[col-id="totalStakeThisEpoch"]') + .should('have.length.at.least', 1) + .each(($totalStaked) => { + cy.wrap($totalStaked).should('not.be.empty'); + }); + }); + + it('Should be able to see validator staked for this epoch', function () { + cy.get('[col-id="validatorStake"]') + .should('have.length.at.least', 1) + .each(($validatorStake) => { + cy.wrap($validatorStake).should('not.be.empty'); + }); + }); + + it('Should be able to see validator staked for next epoch', function () { + cy.get('[col-id="pendingStake"]') + .should('have.length.at.least', 1) + .each(($pendingStake) => { + cy.wrap($pendingStake).should('not.be.empty'); + }); + }); + + // 1002-STKE-021 + it('Should be able to see validator ranking score', function () { + // + cy.get('[col-id="rankingScore"]') + .should('have.length.at.least', 1) + .each(($rankingScore) => { + cy.wrap($rankingScore).should('not.be.empty'); + }); + }); + + // 1002-STKE-022 + it('Should be able to see validator stake score', function () { + cy.get('[col-id="stakeScore"]') + .should('have.length.at.least', 1) + .each(($stakeScore) => { + cy.wrap($stakeScore).should('not.be.empty'); + }); + }); + + // 1002-STKE-023 + it('Should be able to see validator performance score', function () { + cy.get('[col-id="performanceScore"]') + .should('have.length.at.least', 1) + .each(($performanceScore) => { + cy.wrap($performanceScore).should('not.be.empty'); + }); + }); + + // 1002-STKE-024 + it('Should be able to see validator voting power score', function () { + cy.get('.ag-body-horizontal-scroll-viewport').scrollTo('right'); + cy.get('[col-id="votingPower"]') + .should('have.length.at.least', 1) + .each(($votingPower) => { + cy.wrap($votingPower).should('not.be.empty'); + }); + }); + }); + }); + + // 1002-STKE-050 + describe('Should be able to see static information about a validator', function () { + before('connect wallets and click on validator', function () { + cy.vega_wallet_import(); + cy.vega_wallet_connect(); + cy.click_on_validator_from_list(0); + }); + + // 1002-STKE-005 + it('Should be able to see validator name', function () { + cy.get(validatorTitle).should('not.be.empty'); + }); + + // 1002-STKE-007 + it('Should be able to see validator id', function () { + cy.get(validatorId).should('not.be.empty'); + }); + + // 1002-STKE-008 + it('Should be able to see validator public key', function () { + cy.get(validatorPubKey).should('not.be.empty'); + }); + + // 1002-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 1002-STKE-09 + + // 1002-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); + }); + + // 1002-STKE-051 + it('Should be able to see stake share in percentage', function () { + cy.get(stakeShare) + .invoke('text') + .then(($stakePercentage) => { + if ($stakePercentage != '-') { + cy.wrap($stakePercentage).should( + 'match', + /\b(? { + cy.get(epochTitle).should('not.be.empty'); + cy.get(nextEpochInfo).should('contain.text', 'Next epoch'); }); }); }); diff --git a/apps/token-e2e/src/support/staking.functions.js b/apps/token-e2e/src/support/staking.functions.js index 40bd9fa0a..f439c4945 100644 --- a/apps/token-e2e/src/support/staking.functions.js +++ b/apps/token-e2e/src/support/staking.functions.js @@ -7,6 +7,11 @@ const ethWalletAssociateButton = '[href="/staking/associate"]'; const ethWalletDissociateButton = '[href="/staking/disassociate"]'; const associateWalletRadioButton = '[data-testid="associate-radio-wallet"]'; const stakeMaximumTokens = '[data-testid="token-amount-use-maximum"]'; +const stakeValidatorListPendingStake = '[col-id="pendingStake"]'; +const stakeValidatorListTotalStake = '[col-id="totalStakeThisEpoch"]'; +const stakeValidatorListTotalShare = '[col-id="share"]'; +const stakeValidatorListName = '[col-id="validator"]'; +const txTimeout = Cypress.env('txTimeout'); Cypress.Commands.add('wait_for_begining_of_epoch', () => { cy.contains('Waiting for next epoch to start', { timeout: 10000 }).should( @@ -29,7 +34,7 @@ Cypress.Commands.add('staking_validator_page_add_stake', (stake) => { Cypress.Commands.add('staking_validator_page_remove_stake', (stake) => { cy.highlight(`Removing a stake of ${stake}`); - cy.get(removeStakeRadioButton).click({ force: true }); + cy.get(removeStakeRadioButton).click(); cy.get(tokenAmountInputBox).type(stake); cy.wait_for_begining_of_epoch(); cy.get(tokenSubmitButton) @@ -47,9 +52,7 @@ Cypress.Commands.add( cy.get(associateWalletRadioButton, { timeout: 30000 }).click(); cy.get(tokenAmountInputBox, { timeout: 10000 }).type(amount); if (approve) { - cy.get(tokenInputApprove, { timeout: 40000 }) - .should('be.enabled') - .click(); + cy.get(tokenInputApprove, txTimeout).should('be.enabled').click(); cy.contains('Approve $VEGA Tokens for staking on Vega').should( 'be.visible' ); @@ -57,7 +60,7 @@ Cypress.Commands.add( timeout: 40000, }).should('not.exist'); } - cy.get(tokenSubmitButton, { timeout: 40000 }).should('be.enabled').click(); + cy.get(tokenSubmitButton, txTimeout).should('be.enabled').click(); cy.contains('can now participate in governance and nominate a validator', { timeout: 60000, }).should('be.visible'); @@ -70,7 +73,7 @@ Cypress.Commands.add('staking_page_disassociate_tokens', (amount) => { cy.get(associateWalletRadioButton, { timeout: 30000 }).click(); cy.get(tokenAmountInputBox, { timeout: 10000 }).type(amount); - cy.get(tokenSubmitButton, { timeout: 40000 }).should('be.enabled').click(); + cy.get(tokenSubmitButton, txTimeout).should('be.enabled').click(); cy.contains(`${amount} $VEGA tokens have been returned to Ethereum wallet`, { timeout: 60000, }).should('be.visible'); @@ -86,3 +89,43 @@ Cypress.Commands.add('staking_page_disassociate_all_tokens', () => { timeout: 60000, }).should('be.visible'); }); + +Cypress.Commands.add( + 'click_on_validator_from_list', + (validatorNumber, validatorName = null) => { + cy.contains('Waiting for next epoch to start').should('not.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}"]`) + .find(stakeValidatorListName) + .click(); + } + } +); + +Cypress.Commands.add( + 'validate_validator_list_total_stake_and_share', + ( + positionOnList, + expectedValidatorName, + expectedTotalStake, + expectedTotalShare + ) => { + cy.get(`[row-id="${positionOnList}"]`).within(() => { + cy.get(stakeValidatorListName).should('have.text', expectedValidatorName); + cy.get(stakeValidatorListTotalStake).should( + 'have.text', + expectedTotalStake + ); + cy.get(stakeValidatorListTotalShare).should( + 'have.text', + expectedTotalShare + ); + }); + } +); diff --git a/apps/token/src/routes/staking/validator-table.tsx b/apps/token/src/routes/staking/validator-table.tsx index 2ebe3abda..0e6df03db 100644 --- a/apps/token/src/routes/staking/validator-table.tsx +++ b/apps/token/src/routes/staking/validator-table.tsx @@ -8,8 +8,16 @@ import { BigNumber } from '../../lib/bignumber'; import { formatNumber } from '../../lib/format-number'; import type { Staking_nodes } from './__generated__/Staking'; -const ValidatorTableCell = ({ children }: { children: React.ReactNode }) => ( - {children} +const ValidatorTableCell = ({ + children, + dataTestId, +}: { + children: React.ReactNode; + dataTestId?: string; +}) => ( + + {children} + ); export interface ValidatorTableProps { @@ -39,11 +47,15 @@ export const ValidatorTable = ({ {t('id')}: - {node.id} + + {node.id} + {t('VEGA ADDRESS / PUBLIC KEY')} - {node.pubkey} + + {node.pubkey} + {t('ABOUT THIS VALIDATOR')} @@ -69,31 +81,37 @@ export const ValidatorTable = ({ {t('TOTAL STAKE')} - {node.stakedTotalFormatted} + {node.stakedTotalFormatted} {t('PENDING STAKE')} - {node.pendingStakeFormatted} + {node.pendingStakeFormatted} {t('STAKED BY OPERATOR')} - {node.stakedByOperatorFormatted} + + {node.stakedByOperatorFormatted} + {t('STAKED BY DELEGATES')} - {node.stakedByDelegatesFormatted} + + {node.stakedByDelegatesFormatted} + {t('STAKE SHARE')} - {stakePercentage} + {stakePercentage} {t('OWN STAKE (THIS EPOCH)')} - {formatNumber(stakeThisEpoch)} + {formatNumber(stakeThisEpoch)} {t('NOMINATED (THIS EPOCH)')} - {node.stakedByDelegatesFormatted} + + {node.stakedByDelegatesFormatted} + );