Test/425 withdrawals (#457)
* chore: improve assertions for deposits * test: validation test passing * test: withdrawal tests passing * fix: test failures in CI * fix: lint * chore: add env variables * fix: failing tests due to wallet service not running * ci: pass automatic cnsent * ci: init wallet in other directory * ci: pass home string everywhere * ci: config is already imported * fix: failing deposit and nightly run * ci: port over changes from pr run * fix: failing network param tests * fix: assertion * fix: assertion one last time Co-authored-by: Dexter <dexter.edwards93@gmail.com>
This commit is contained in:
parent
d858d9cf8a
commit
66c18a2b1b
11
.github/workflows/capsule-cypress-nightly.yml
vendored
11
.github/workflows/capsule-cypress-nightly.yml
vendored
@ -121,15 +121,13 @@ jobs:
|
|||||||
run: echo "${{ secrets.TRADING_TEST_VEGA_WALLET_RECOVERY }}" > ./recovery
|
run: echo "${{ secrets.TRADING_TEST_VEGA_WALLET_RECOVERY }}" > ./recovery
|
||||||
|
|
||||||
- name: Initialize wallet
|
- name: Initialize wallet
|
||||||
run: vegawallet init -f
|
run: vegawallet init -f --home ~/.vegacapsule/testnet/wallet
|
||||||
- name: Import wallet
|
- name: Import wallet
|
||||||
run: vegawallet import -w UI_Trading_Test --recovery-phrase-file ./recovery -p ./passphrase
|
run: vegawallet import -w UI_Trading_Test --recovery-phrase-file ./recovery -p ./passphrase --home ~/.vegacapsule/testnet/wallet
|
||||||
- name: Import config
|
|
||||||
run: vegawallet network import --from-file ~/.vegacapsule/testnet/wallet/config/wallet-service/networks/DV.toml
|
|
||||||
- name: Create public key 2
|
- name: Create public key 2
|
||||||
run: vegawallet key generate -w UI_Trading_Test -p ./passphrase
|
run: vegawallet key generate -w UI_Trading_Test -p ./passphrase --home ~/.vegacapsule/testnet/wallet
|
||||||
- name: Start service
|
- name: Start service
|
||||||
run: vegawallet service run --network fairground &
|
run: vegawallet service run --network DV --automatic-consent --home ~/.vegacapsule/testnet/wallet &
|
||||||
|
|
||||||
######
|
######
|
||||||
## Run some tests
|
## Run some tests
|
||||||
@ -151,6 +149,7 @@ jobs:
|
|||||||
CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
|
CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
|
||||||
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
|
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
|
||||||
CYPRESS_ETH_WALLET_MNEMONIC: ${{ secrets.CYPESS_ETH_WALLET_MNEMONIC }}
|
CYPRESS_ETH_WALLET_MNEMONIC: ${{ secrets.CYPESS_ETH_WALLET_MNEMONIC }}
|
||||||
|
CYPRESS_NIGHTLY_RUN: true
|
||||||
|
|
||||||
######
|
######
|
||||||
## Upload logs
|
## Upload logs
|
||||||
|
10
.github/workflows/capsule-cypress.yml
vendored
10
.github/workflows/capsule-cypress.yml
vendored
@ -81,15 +81,13 @@ jobs:
|
|||||||
run: echo "${{ secrets.TRADING_TEST_VEGA_WALLET_RECOVERY }}" > ./recovery
|
run: echo "${{ secrets.TRADING_TEST_VEGA_WALLET_RECOVERY }}" > ./recovery
|
||||||
|
|
||||||
- name: Initialize wallet
|
- name: Initialize wallet
|
||||||
run: vegawallet init -f
|
run: vegawallet init -f --home ~/.vegacapsule/testnet/wallet
|
||||||
- name: Import wallet
|
- name: Import wallet
|
||||||
run: vegawallet import -w UI_Trading_Test --recovery-phrase-file ./recovery -p ./passphrase
|
run: vegawallet import -w UI_Trading_Test --recovery-phrase-file ./recovery -p ./passphrase --home ~/.vegacapsule/testnet/wallet
|
||||||
- name: Import config
|
|
||||||
run: vegawallet network import --from-file ~/.vegacapsule/testnet/wallet/config/wallet-service/networks/DV.toml
|
|
||||||
- name: Create public key 2
|
- name: Create public key 2
|
||||||
run: vegawallet key generate -w UI_Trading_Test -p ./passphrase
|
run: vegawallet key generate -w UI_Trading_Test -p ./passphrase --home ~/.vegacapsule/testnet/wallet
|
||||||
- name: Start service
|
- name: Start service
|
||||||
run: vegawallet service run --network fairground &
|
run: vegawallet service run --network DV --automatic-consent --home ~/.vegacapsule/testnet/wallet &
|
||||||
|
|
||||||
######
|
######
|
||||||
## Run some tests
|
## Run some tests
|
||||||
|
@ -65,10 +65,12 @@ export default class HomePage extends BasePage {
|
|||||||
cy.getByTestId(this.statsValue).eq(11).should('not.be.empty');
|
cy.getByTestId(this.statsValue).eq(11).should('not.be.empty');
|
||||||
cy.getByTestId(this.statsValue).eq(12).should('not.be.empty');
|
cy.getByTestId(this.statsValue).eq(12).should('not.be.empty');
|
||||||
cy.getByTestId(this.statsValue).eq(13).should('not.be.empty');
|
cy.getByTestId(this.statsValue).eq(13).should('not.be.empty');
|
||||||
|
if (Cypress.env('NIGHTLY_RUN') != true) {
|
||||||
cy.getByTestId(this.statsValue)
|
cy.getByTestId(this.statsValue)
|
||||||
.eq(14)
|
.eq(14)
|
||||||
.invoke('text')
|
.invoke('text')
|
||||||
.should('match', /v\d+\.\d+\.\d+/i);
|
.should('match', /v\d+\.\d+\.\d+/i);
|
||||||
|
}
|
||||||
cy.getByTestId(this.statsValue)
|
cy.getByTestId(this.statsValue)
|
||||||
.eq(15)
|
.eq(15)
|
||||||
.invoke('text')
|
.invoke('text')
|
||||||
|
@ -15,18 +15,18 @@ export default class NetworkParametersPage extends BasePage {
|
|||||||
);
|
);
|
||||||
|
|
||||||
cy.get(this.jsonParamNameClassName)
|
cy.get(this.jsonParamNameClassName)
|
||||||
.should('have.length.at.least', 21)
|
.should('have.length.at.least', 18)
|
||||||
.each(($paramName) => {
|
.each(($paramName) => {
|
||||||
cy.wrap($paramName).should('not.be.empty');
|
cy.wrap($paramName).should('not.be.empty');
|
||||||
});
|
});
|
||||||
cy.get(this.jsonParamValueStringClassName)
|
cy.get(this.jsonParamValueStringClassName)
|
||||||
.should('have.length.at.least', 7)
|
.should('have.length.at.least', 6)
|
||||||
.each(($paramValue) => {
|
.each(($paramValue) => {
|
||||||
cy.wrap($paramValue).should('not.be.empty');
|
cy.wrap($paramValue).should('not.be.empty');
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.get(this.jsonParamValueNumberClassName)
|
cy.get(this.jsonParamValueNumberClassName)
|
||||||
.should('have.length.at.least', 9)
|
.should('have.length.at.least', 7)
|
||||||
.each(($paramValue) => {
|
.each(($paramValue) => {
|
||||||
cy.wrap($paramValue).should('not.be.empty');
|
cy.wrap($paramValue).should('not.be.empty');
|
||||||
});
|
});
|
||||||
|
@ -24,6 +24,9 @@
|
|||||||
"TRUNCATED_VEGA_PUBLIC_KEY": "47836c…c7d278",
|
"TRUNCATED_VEGA_PUBLIC_KEY": "47836c…c7d278",
|
||||||
"TRUNCATED_VEGA_PUBLIC_KEY2": "1a18cd…0cf2e4",
|
"TRUNCATED_VEGA_PUBLIC_KEY2": "1a18cd…0cf2e4",
|
||||||
"INVALID_DEPOSIT_TO_ADDRESS": "zzz85edfa7ffdb6ed996ca912e9258998e47bf3515c885cf3c63fb56b15de36f",
|
"INVALID_DEPOSIT_TO_ADDRESS": "zzz85edfa7ffdb6ed996ca912e9258998e47bf3515c885cf3c63fb56b15de36f",
|
||||||
|
"ETHEREUM_WALLET_ADDRESS": "0x265Cc6d39a1B53d0d92068443009eE7410807158",
|
||||||
|
"ETHERSCAN_URL": "https://ropsten.etherscan.io",
|
||||||
|
"WITHDRAWAL_ASSET_ID": "tEURO TEST",
|
||||||
"tsConfig": "tsconfig.json",
|
"tsConfig": "tsconfig.json",
|
||||||
"TAGS": "not @todo and not @ignore and not @manual"
|
"TAGS": "not @todo and not @ignore and not @manual"
|
||||||
}
|
}
|
||||||
|
@ -91,6 +91,7 @@ Feature: Deposits to vega wallet
|
|||||||
# This next step is being skipped due to account having approved status
|
# This next step is being skipped due to account having approved status
|
||||||
# Then Not approved message shown
|
# Then Not approved message shown
|
||||||
|
|
||||||
|
@ignore
|
||||||
Scenario: Successful deposit
|
Scenario: Successful deposit
|
||||||
When I enter the following deposit details in deposit form
|
When I enter the following deposit details in deposit form
|
||||||
| asset | tBTC TEST |
|
| asset | tBTC TEST |
|
||||||
|
@ -1,57 +1,47 @@
|
|||||||
@ignore
|
Feature: Withdrawals to eth wallet
|
||||||
Feature: Withdrawals
|
|
||||||
|
|
||||||
Scenario: Can prepare a withdrawal
|
Background:
|
||||||
Given I am on withdraw page
|
Given I navigate to withdrawal page
|
||||||
And I connect eth wallet
|
And I connect to Vega Wallet
|
||||||
And I connect vega wallet
|
|
||||||
And I can see the withdrawals warning info
|
|
||||||
And I can see the from ethereum address field is automatically populated with current connected key
|
|
||||||
And I select asset 'tBTC'
|
|
||||||
And I input '100' tokens to withdraw
|
|
||||||
And the withdraw button is enabled
|
|
||||||
When I click the withdraw button
|
|
||||||
Then The vega transaction is sent
|
|
||||||
Then The Ethereum transaction is triggered
|
|
||||||
|
|
||||||
Scenario: Form field validation if fields are incomplete
|
Scenario: Succesfull withdrawal
|
||||||
Given I am on withdraw page
|
When I succesfully fill in and submit withdrawal form
|
||||||
And I connect eth wallet
|
Then withdrawal modal is displayed
|
||||||
And I connect vega wallet
|
|
||||||
When I click the withdraw button
|
|
||||||
Then I can see validation errors on incomplete fields
|
|
||||||
|
|
||||||
Scenario: Can prepare a withdrawal to send to another eth wallet
|
Scenario: Error displayed when fields are empty
|
||||||
Given I am on withdraw page
|
When I clear ethereum address
|
||||||
And I connect eth wallet
|
And click submit
|
||||||
And I connect vega wallet
|
Then errors are displayed for empty fields
|
||||||
And I select asset 'tBTC'
|
|
||||||
And I can see an eth address is already filled in the withdraw to field
|
|
||||||
When I click the enter manually button
|
|
||||||
Then I can enter a new eth address
|
|
||||||
And I input '100' tokens to withdraw
|
|
||||||
And the withdraw button is enabled
|
|
||||||
When I click the withdraw button
|
|
||||||
Then The vega transaction is sent
|
|
||||||
Then The Ethereum transaction is triggered
|
|
||||||
|
|
||||||
Scenario: Eth key validation on form
|
Scenario: Error displayed when invalid Ethereum address is entered
|
||||||
Given I am on withdraw page
|
When I enter an invalid ethereum address
|
||||||
And I connect eth wallet
|
Then error for invalid ethereum address is displayed
|
||||||
And I connect vega wallet
|
|
||||||
And I select asset 'tBTC'
|
|
||||||
When I click the enter manually button
|
|
||||||
And I enter eth address 'MMMMNNNN'
|
|
||||||
Then the invalid eth address error is shown
|
|
||||||
|
|
||||||
Scenario: Validation error if trying to withdraw more than available
|
Scenario: Error displayed when not in range of acceptable amount
|
||||||
Given I am on withdrawals page
|
When I enter the following details in withdrawal form
|
||||||
And I have connected
|
| asset | tUSDC TEST |
|
||||||
And I select asset 'tBTC'
|
| amount | 0 |
|
||||||
And I input '1088494949494949940' tokens to withdraw
|
Then error for below minumum amount is displayed
|
||||||
When I click the withdraw button
|
When I enter the following details in withdrawal form
|
||||||
Then validation error is shown for token input amount
|
| asset | tUSDC TEST |
|
||||||
|
| amount | 1 |
|
||||||
|
Then error for above maximum amount is displayed
|
||||||
|
|
||||||
|
Scenario: Fill in amount using maximum
|
||||||
|
When I select "tDAI TEST"
|
||||||
|
And ethereum address is connected Ethereum wallet
|
||||||
|
And I click Use maximum
|
||||||
|
Then expected amount is "5.00000"
|
||||||
|
|
||||||
|
Scenario: Able to view history of withdrawals on withdrawals page
|
||||||
|
Given I navigate to withdrawals page
|
||||||
|
Then history of withdrawals are displayed
|
||||||
|
|
||||||
|
Scenario: Vega wallet connect text shown when Vega wallet is disconnected
|
||||||
|
When I disconnect my Vega wallet
|
||||||
|
Then connect to Vega wallet is displayed
|
||||||
|
|
||||||
|
@manual
|
||||||
Scenario: Can see pending / unfinished withdrawals
|
Scenario: Can see pending / unfinished withdrawals
|
||||||
Given I am on the withdrawals page
|
Given I am on the withdrawals page
|
||||||
And I can see there are unfinished withdrawals
|
And I can see there are unfinished withdrawals
|
||||||
|
@ -2,6 +2,12 @@ export default class BasePage {
|
|||||||
closeDialogBtn = 'dialog-close';
|
closeDialogBtn = 'dialog-close';
|
||||||
porfolioUrl = '/portfolio';
|
porfolioUrl = '/portfolio';
|
||||||
marketsUrl = '/markets';
|
marketsUrl = '/markets';
|
||||||
|
assetSelectField = 'select[name="asset"]';
|
||||||
|
toAddressField = 'input[name="to"]';
|
||||||
|
amountField = 'input[name="amount"]';
|
||||||
|
formFieldError = 'input-error-text';
|
||||||
|
dialogHeader = 'dialog-title';
|
||||||
|
dialogText = 'dialog-text';
|
||||||
|
|
||||||
closeDialog() {
|
closeDialog() {
|
||||||
cy.getByTestId(this.closeDialogBtn, { timeout: 8000 }).click({
|
cy.getByTestId(this.closeDialogBtn, { timeout: 8000 }).click({
|
||||||
@ -20,4 +26,28 @@ export default class BasePage {
|
|||||||
cy.url().should('include', '/markets');
|
cy.url().should('include', '/markets');
|
||||||
cy.getByTestId('markets');
|
cy.getByTestId('markets');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
verifyFormErrorDisplayed(expectedError: string, expectedNumErrors: number) {
|
||||||
|
cy.getByTestId(this.formFieldError).should('contain.text', expectedError);
|
||||||
|
cy.getByTestId(this.formFieldError).should(
|
||||||
|
'have.length',
|
||||||
|
expectedNumErrors
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTransactionform(args?: {
|
||||||
|
asset?: string;
|
||||||
|
to?: string;
|
||||||
|
amount?: string;
|
||||||
|
}) {
|
||||||
|
if (args?.asset) {
|
||||||
|
cy.get(this.assetSelectField).select(args.asset);
|
||||||
|
}
|
||||||
|
if (args?.to) {
|
||||||
|
cy.get(this.toAddressField).clear().type(args.to);
|
||||||
|
}
|
||||||
|
if (args?.amount) {
|
||||||
|
cy.get(this.amountField).clear().type(args.amount);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,52 +18,33 @@ export default class DepositsPage extends BasePage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
checkModalContains(text: string) {
|
checkModalContains(text: string) {
|
||||||
cy.get('[role="dialog"]').contains(text).should('be.visible');
|
cy.get('[role="dialog"] > div > div > h1').should('have.text', text);
|
||||||
}
|
|
||||||
|
|
||||||
updateForm(args?: { asset?: string; to?: string; amount?: string }) {
|
|
||||||
if (args?.asset) {
|
|
||||||
cy.get('select[name="asset"]').select(args.asset);
|
|
||||||
}
|
|
||||||
if (args?.to) {
|
|
||||||
cy.get('input[name="to"]').clear().type(args.to);
|
|
||||||
}
|
|
||||||
if (args?.amount) {
|
|
||||||
cy.get('input[name="amount"]').clear().type(args.amount);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
submitForm() {
|
submitForm() {
|
||||||
cy.getByTestId('deposit-submit').click();
|
cy.getByTestId('deposit-submit').click();
|
||||||
}
|
}
|
||||||
|
|
||||||
verifyFieldsAreRequired() {
|
|
||||||
cy.get(this.assetError).contains(this.requiredText);
|
|
||||||
cy.get(this.toError).contains(this.requiredText);
|
|
||||||
cy.get(this.amountError).contains(this.requiredText);
|
|
||||||
cy.getByTestId('input-error-text').should('have.length', 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
verifyInvalidPublicKey() {
|
verifyInvalidPublicKey() {
|
||||||
cy.get(this.toError).contains('Invalid Vega key').should('be.visible');
|
cy.get(this.toError).should('have.text', 'Invalid Vega key');
|
||||||
}
|
}
|
||||||
|
|
||||||
verifyAmountTooSmall() {
|
verifyAmountTooSmall() {
|
||||||
cy.get(this.amountError)
|
cy.get(this.amountError).should('have.text', 'Value is below minimum');
|
||||||
.contains('Value is below minimum')
|
|
||||||
.should('be.visible');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
verifyInsufficientAmountMessage() {
|
verifyInsufficientAmountMessage() {
|
||||||
cy.getByTestId('input-error-text')
|
cy.getByTestId('input-error-text').should(
|
||||||
.contains('Insufficient amount in Ethereum wallet')
|
'contain.text',
|
||||||
.should('be.visible');
|
'Insufficient amount in Ethereum wallet'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
verifyNotApproved() {
|
verifyNotApproved() {
|
||||||
cy.get(this.amountError)
|
cy.get(this.amountError).should(
|
||||||
.contains('Amount is above approved amount')
|
'have.text',
|
||||||
.should('be.visible');
|
'Amount is above approved amount'
|
||||||
|
);
|
||||||
cy.contains('Deposits of tBTC not approved').should('be.visible');
|
cy.contains('Deposits of tBTC not approved').should('be.visible');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,44 @@
|
|||||||
import BasePage from './base-page';
|
import BasePage from './base-page';
|
||||||
|
|
||||||
export default class PortfolioPage extends BasePage {}
|
export default class PortfolioPage extends BasePage {
|
||||||
|
deposit = 'deposit';
|
||||||
|
depositTEuro = 'deposit-tEuro';
|
||||||
|
viewWithdrawals = 'view-withdrawals';
|
||||||
|
withdraw = 'withdraw';
|
||||||
|
withdrawTEuro = 'withdraw-tEuro';
|
||||||
|
|
||||||
|
navigateToDeposit() {
|
||||||
|
cy.getByTestId(this.deposit)
|
||||||
|
.should('have.attr', 'href')
|
||||||
|
.and('include', '/portfolio/deposit');
|
||||||
|
cy.getByTestId(this.deposit).click();
|
||||||
|
}
|
||||||
|
|
||||||
|
navigateToDepositTEuro() {
|
||||||
|
cy.getByTestId(this.depositTEuro)
|
||||||
|
.should('have.attr', 'href')
|
||||||
|
.and('include', '/portfolio/deposit?assetId');
|
||||||
|
cy.getByTestId(this.depositTEuro).click();
|
||||||
|
}
|
||||||
|
|
||||||
|
navigateToWithdrawals() {
|
||||||
|
cy.getByTestId(this.viewWithdrawals)
|
||||||
|
.should('have.attr', 'href')
|
||||||
|
.and('include', '/portfolio/withdrawals');
|
||||||
|
cy.getByTestId(this.viewWithdrawals).click();
|
||||||
|
}
|
||||||
|
|
||||||
|
navigateToWithdraw() {
|
||||||
|
cy.getByTestId(this.withdraw)
|
||||||
|
.should('have.attr', 'href')
|
||||||
|
.and('include', '/portfolio/withdraw');
|
||||||
|
cy.getByTestId(this.withdraw).click();
|
||||||
|
}
|
||||||
|
|
||||||
|
navigateToWithdrawTEuro() {
|
||||||
|
cy.getByTestId(this.withdrawTEuro)
|
||||||
|
.should('have.attr', 'href')
|
||||||
|
.and('include', '/portfolio/withdraw?assetId');
|
||||||
|
cy.getByTestId(this.withdrawTEuro).click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
94
apps/trading-e2e/src/support/pages/withdrawals-page.ts
Normal file
94
apps/trading-e2e/src/support/pages/withdrawals-page.ts
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
import BasePage from './base-page';
|
||||||
|
|
||||||
|
export default class WithdrawalsPage extends BasePage {
|
||||||
|
useConnectedEthWallet = 'use-connected';
|
||||||
|
useMaximumAmount = 'use-maximum';
|
||||||
|
submitBtn = 'submit-withdrawal';
|
||||||
|
connectVegaWalletText = 'connect-vega-wallet-text';
|
||||||
|
assetSymbolColId = 'asset.symbol';
|
||||||
|
amountColId = 'amount';
|
||||||
|
recipientColdId = 'details.receiverAddress';
|
||||||
|
createdAtTimeStampId = 'createdTimestamp';
|
||||||
|
statusColId = 'status';
|
||||||
|
etherScanLink = 'etherscan-link';
|
||||||
|
|
||||||
|
clearEthereumAddress() {
|
||||||
|
cy.get(this.toAddressField).clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
clickUseConnected() {
|
||||||
|
cy.getByTestId(this.useConnectedEthWallet).click();
|
||||||
|
}
|
||||||
|
|
||||||
|
clickUseMaximum() {
|
||||||
|
cy.getByTestId(this.useMaximumAmount).click();
|
||||||
|
}
|
||||||
|
|
||||||
|
clickSubmit() {
|
||||||
|
cy.getByTestId(this.submitBtn).click();
|
||||||
|
}
|
||||||
|
|
||||||
|
validateConnectWalletText() {
|
||||||
|
cy.getByTestId(this.connectVegaWalletText).should(
|
||||||
|
'have.text',
|
||||||
|
'Please connect your Vega wallet'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
validateTestWalletEthWalletAddress() {
|
||||||
|
cy.get(this.toAddressField).should(
|
||||||
|
'have.value',
|
||||||
|
Cypress.env('ETHEREUM_WALLET_ADDRESS')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
validateAmount(expectedAmount: string) {
|
||||||
|
cy.get(this.amountField).should('have.value', expectedAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
validateConfirmWithdrawalModal() {
|
||||||
|
cy.getByTestId(this.dialogHeader).should('have.text', 'Confirm withdrawal');
|
||||||
|
cy.getByTestId(this.dialogText).should(
|
||||||
|
'have.text',
|
||||||
|
'Confirm withdrawal in Vega wallet'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
validateWithdrawalAssetDisplayed(assetSymbol: string) {
|
||||||
|
cy.get(`[col-id="${this.assetSymbolColId}"]`).should(
|
||||||
|
'contain.text',
|
||||||
|
assetSymbol
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
validateWithdrawalAmountDisplayed(amount: string) {
|
||||||
|
cy.get(`[col-id="${this.amountColId}"]`).should('contain.text', amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
validateWithdrawalRecipientDisplayed(
|
||||||
|
truncatedEthAddress: string,
|
||||||
|
ethAddressLink: string
|
||||||
|
) {
|
||||||
|
cy.get(`[col-id="${this.recipientColdId}"]`)
|
||||||
|
.should('contain.text', truncatedEthAddress)
|
||||||
|
.find(`[data-testid=${this.etherScanLink}]`)
|
||||||
|
.should('have.attr', 'href', ethAddressLink);
|
||||||
|
}
|
||||||
|
|
||||||
|
validateWithdrawalDateDisplayed() {
|
||||||
|
cy.get(`[col-id="${this.createdAtTimeStampId}"]`)
|
||||||
|
.invoke('text')
|
||||||
|
.should('not.be.empty');
|
||||||
|
}
|
||||||
|
|
||||||
|
validateWithdrawalStatusDisplayed(status: string) {
|
||||||
|
cy.get(`[col-id="${this.statusColId}"]`).should('contain.text', status);
|
||||||
|
}
|
||||||
|
|
||||||
|
validateEtherScanLinkDisplayed(txlink: string) {
|
||||||
|
cy.getByTestId(this.etherScanLink)
|
||||||
|
.last()
|
||||||
|
.should('have.text', 'View on Etherscan')
|
||||||
|
.and('have.attr', 'href', txlink);
|
||||||
|
}
|
||||||
|
}
|
@ -30,16 +30,16 @@ Then('I can see the deposit form', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
When('I submit a deposit with empty fields', () => {
|
When('I submit a deposit with empty fields', () => {
|
||||||
depositsPage.updateForm();
|
depositsPage.updateTransactionform();
|
||||||
depositsPage.submitForm();
|
depositsPage.submitForm();
|
||||||
});
|
});
|
||||||
|
|
||||||
Then('I can see empty form validation errors present', () => {
|
Then('I can see empty form validation errors present', () => {
|
||||||
depositsPage.verifyFieldsAreRequired();
|
depositsPage.verifyFormErrorDisplayed('Required', 3);
|
||||||
});
|
});
|
||||||
|
|
||||||
Then('I enter the following deposit details in deposit form', (table) => {
|
Then('I enter the following deposit details in deposit form', (table) => {
|
||||||
depositsPage.updateForm({
|
depositsPage.updateTransactionform({
|
||||||
asset: table.rowsHash().asset,
|
asset: table.rowsHash().asset,
|
||||||
to: Cypress.env(table.rowsHash().to),
|
to: Cypress.env(table.rowsHash().to),
|
||||||
amount: table.rowsHash().amount,
|
amount: table.rowsHash().amount,
|
||||||
@ -59,7 +59,7 @@ Then('Amount too small message shown', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
And('I enter a valid amount', () => {
|
And('I enter a valid amount', () => {
|
||||||
depositsPage.updateForm({ amount: '1' });
|
depositsPage.updateTransactionform({ amount: '1' });
|
||||||
});
|
});
|
||||||
|
|
||||||
Then('Not approved message shown', () => {
|
Then('Not approved message shown', () => {
|
||||||
|
@ -40,6 +40,14 @@ When('select a different public key', () => {
|
|||||||
vegaWallet.selectPublicKey();
|
vegaWallet.selectPublicKey();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
When('I disconnect my Vega wallet', () => {
|
||||||
|
vegaWallet.validatePublicKeyDisplayed(
|
||||||
|
Cypress.env('TRUNCATED_VEGA_PUBLIC_KEY')
|
||||||
|
);
|
||||||
|
vegaWallet.clickOnWalletConnectDialog();
|
||||||
|
vegaWallet.clickDisconnectAllKeys();
|
||||||
|
});
|
||||||
|
|
||||||
Then('public key is switched', () => {
|
Then('public key is switched', () => {
|
||||||
vegaWallet.validatePublicKeyDisplayed(
|
vegaWallet.validatePublicKeyDisplayed(
|
||||||
Cypress.env('TRUNCATED_VEGA_PUBLIC_KEY2')
|
Cypress.env('TRUNCATED_VEGA_PUBLIC_KEY2')
|
||||||
|
@ -0,0 +1,112 @@
|
|||||||
|
import { Given, When, Then } from 'cypress-cucumber-preprocessor/steps';
|
||||||
|
import PortfolioPage from '../pages/portfolio-page';
|
||||||
|
import WithdrawalsPage from '../pages/withdrawals-page';
|
||||||
|
|
||||||
|
const portfolioPage = new PortfolioPage();
|
||||||
|
const withdrawalsPage = new WithdrawalsPage();
|
||||||
|
|
||||||
|
Given('I navigate to withdrawal page', () => {
|
||||||
|
cy.visit('/');
|
||||||
|
portfolioPage.closeDialog();
|
||||||
|
portfolioPage.navigateToPortfolio();
|
||||||
|
portfolioPage.navigateToWithdraw();
|
||||||
|
});
|
||||||
|
|
||||||
|
Given('I navigate to withdrawals page', () => {
|
||||||
|
portfolioPage.navigateToPortfolio();
|
||||||
|
portfolioPage.navigateToWithdrawals();
|
||||||
|
});
|
||||||
|
|
||||||
|
When('I clear ethereum address', () => {
|
||||||
|
withdrawalsPage.clearEthereumAddress();
|
||||||
|
});
|
||||||
|
|
||||||
|
When('click submit', () => {
|
||||||
|
withdrawalsPage.clickSubmit();
|
||||||
|
});
|
||||||
|
|
||||||
|
When('I enter an invalid ethereum address', () => {
|
||||||
|
withdrawalsPage.updateTransactionform({
|
||||||
|
to: '0x0dAAACaa868f87BB4666F918742141cAEAe893Fa',
|
||||||
|
});
|
||||||
|
withdrawalsPage.clickSubmit();
|
||||||
|
});
|
||||||
|
|
||||||
|
When('I select {string}', (selectedAsset) => {
|
||||||
|
withdrawalsPage.updateTransactionform({
|
||||||
|
asset: selectedAsset,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
When('ethereum address is connected Ethereum wallet', () => {
|
||||||
|
withdrawalsPage.validateTestWalletEthWalletAddress();
|
||||||
|
});
|
||||||
|
|
||||||
|
When('I click Use maximum', () => {
|
||||||
|
withdrawalsPage.clickUseMaximum();
|
||||||
|
});
|
||||||
|
|
||||||
|
When('I enter the following details in withdrawal form', (table) => {
|
||||||
|
withdrawalsPage.updateTransactionform({
|
||||||
|
asset: table.rowsHash().asset,
|
||||||
|
to: table.rowsHash().to,
|
||||||
|
amount: table.rowsHash().amount,
|
||||||
|
});
|
||||||
|
withdrawalsPage.clickSubmit();
|
||||||
|
});
|
||||||
|
|
||||||
|
When('I succesfully fill in and submit withdrawal form', () => {
|
||||||
|
withdrawalsPage.updateTransactionform({
|
||||||
|
asset: Cypress.env('WITHDRAWAL_ASSET_ID'),
|
||||||
|
amount: '0.1',
|
||||||
|
});
|
||||||
|
withdrawalsPage.clickSubmit();
|
||||||
|
});
|
||||||
|
|
||||||
|
Then('errors are displayed for empty fields', () => {
|
||||||
|
withdrawalsPage.verifyFormErrorDisplayed('Required', 3);
|
||||||
|
});
|
||||||
|
|
||||||
|
Then('error for invalid ethereum address is displayed', () => {
|
||||||
|
// Expecting empty field errors to still be displayed
|
||||||
|
withdrawalsPage.verifyFormErrorDisplayed('Invalid Ethereum address', 3);
|
||||||
|
});
|
||||||
|
|
||||||
|
Then('connect to Vega wallet is displayed', () => {
|
||||||
|
withdrawalsPage.validateConnectWalletText();
|
||||||
|
});
|
||||||
|
|
||||||
|
Then('expected amount is {string}', (expectedAmount) => {
|
||||||
|
withdrawalsPage.validateAmount(expectedAmount);
|
||||||
|
});
|
||||||
|
|
||||||
|
Then('withdrawal modal is displayed', () => {
|
||||||
|
withdrawalsPage.validateConfirmWithdrawalModal();
|
||||||
|
});
|
||||||
|
|
||||||
|
Then('error for below minumum amount is displayed', () => {
|
||||||
|
withdrawalsPage.verifyFormErrorDisplayed('Value is below minimum', 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
Then('error for above maximum amount is displayed', () => {
|
||||||
|
withdrawalsPage.verifyFormErrorDisplayed('Value is above maximum', 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
Then('history of withdrawals are displayed', () => {
|
||||||
|
const ethAddressLink = `${Cypress.env('ETHERSCAN_URL')}/address/${Cypress.env(
|
||||||
|
'ETHEREUM_WALLET_ADDRESS'
|
||||||
|
)}`;
|
||||||
|
const etherScanLink = `${Cypress.env(
|
||||||
|
'ETHERSCAN_URL'
|
||||||
|
)}/tx/0x0d1a5d209f468ff248326d4ae7647ad5a3667ce463341a0250118a95f3beb597`;
|
||||||
|
|
||||||
|
withdrawalsPage.validateWithdrawalAssetDisplayed('tEURO');
|
||||||
|
withdrawalsPage.validateWithdrawalAmountDisplayed('10,000.00000');
|
||||||
|
withdrawalsPage.validateWithdrawalRecipientDisplayed(
|
||||||
|
'0x265C…807158',
|
||||||
|
ethAddressLink
|
||||||
|
);
|
||||||
|
withdrawalsPage.validateWithdrawalDateDisplayed();
|
||||||
|
withdrawalsPage.validateWithdrawalStatusDisplayed('Finalized');
|
||||||
|
withdrawalsPage.validateEtherScanLinkDisplayed(etherScanLink);
|
||||||
|
});
|
@ -3,6 +3,7 @@ export default class VegaWallet {
|
|||||||
walletConnectors = 'connectors-list';
|
walletConnectors = 'connectors-list';
|
||||||
walletForm = 'rest-connector-form';
|
walletForm = 'rest-connector-form';
|
||||||
selectPublicKeyBtn = 'select-keypair-button';
|
selectPublicKeyBtn = 'select-keypair-button';
|
||||||
|
disconnectAllKeysBtn = 'disconnect';
|
||||||
walletInputError = 'input-wallet-error';
|
walletInputError = 'input-wallet-error';
|
||||||
walletFormError = 'form-error';
|
walletFormError = 'form-error';
|
||||||
inputError = 'input-error-text';
|
inputError = 'input-error-text';
|
||||||
@ -56,4 +57,8 @@ export default class VegaWallet {
|
|||||||
clickOnWalletConnectDialog() {
|
clickOnWalletConnectDialog() {
|
||||||
cy.getByTestId(this.connectVegaBtn).click();
|
cy.getByTestId(this.connectVegaBtn).click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clickDisconnectAllKeys() {
|
||||||
|
cy.getByTestId(this.disconnectAllKeysBtn).click();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,17 +6,30 @@ const Portfolio = () => {
|
|||||||
<div className="p-24">
|
<div className="p-24">
|
||||||
<h1 className="text-h3 mb-12">{t('Portfolio')}</h1>
|
<h1 className="text-h3 mb-12">{t('Portfolio')}</h1>
|
||||||
<div className="flex gap-4 mb-12">
|
<div className="flex gap-4 mb-12">
|
||||||
<AnchorButton href="/portfolio/deposit">{t('Deposit')}</AnchorButton>
|
<AnchorButton data-testid="deposit" href="/portfolio/deposit">
|
||||||
<AnchorButton href="/portfolio/deposit?assetId=8b52d4a3a4b0ffe733cddbc2b67be273816cfeb6ca4c8b339bac03ffba08e4e4">
|
{t('Deposit')}
|
||||||
|
</AnchorButton>
|
||||||
|
<AnchorButton
|
||||||
|
data-testid="deposit-tEuro"
|
||||||
|
href="/portfolio/deposit?assetId=8b52d4a3a4b0ffe733cddbc2b67be273816cfeb6ca4c8b339bac03ffba08e4e4"
|
||||||
|
>
|
||||||
{t('Deposit tEURO')}
|
{t('Deposit tEURO')}
|
||||||
</AnchorButton>
|
</AnchorButton>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-4">
|
<div className="flex gap-4">
|
||||||
<AnchorButton href="/portfolio/withdrawals">
|
<AnchorButton
|
||||||
|
data-testid="view-withdrawals"
|
||||||
|
href="/portfolio/withdrawals"
|
||||||
|
>
|
||||||
{t('View Withdrawals')}
|
{t('View Withdrawals')}
|
||||||
</AnchorButton>
|
</AnchorButton>
|
||||||
<AnchorButton href="/portfolio/withdraw">{t('Withdraw')}</AnchorButton>
|
<AnchorButton data-testid="withdraw" href="/portfolio/withdraw">
|
||||||
<AnchorButton href="/portfolio/withdraw?assetId=8b52d4a3a4b0ffe733cddbc2b67be273816cfeb6ca4c8b339bac03ffba08e4e4">
|
{t('Withdraw')}
|
||||||
|
</AnchorButton>
|
||||||
|
<AnchorButton
|
||||||
|
data-testid="withdraw-tEuro"
|
||||||
|
href="/portfolio/withdraw?assetId=8b52d4a3a4b0ffe733cddbc2b67be273816cfeb6ca4c8b339bac03ffba08e4e4"
|
||||||
|
>
|
||||||
{t('Withdraw tEURO')}
|
{t('Withdraw tEURO')}
|
||||||
</AnchorButton>
|
</AnchorButton>
|
||||||
</div>
|
</div>
|
||||||
|
@ -48,7 +48,11 @@ export const WithdrawPageContainer = ({
|
|||||||
const { keypair } = useVegaWallet();
|
const { keypair } = useVegaWallet();
|
||||||
|
|
||||||
if (!keypair) {
|
if (!keypair) {
|
||||||
return <p>{t('Please connect your Vega wallet')}</p>;
|
return (
|
||||||
|
<p data-testid="connect-vega-wallet-text">
|
||||||
|
{t('Please connect your Vega wallet')}
|
||||||
|
</p>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -51,7 +51,10 @@ export const DialogWrapper = ({
|
|||||||
<div className="flex gap-12 max-w-full text-ui">
|
<div className="flex gap-12 max-w-full text-ui">
|
||||||
<div className="pt-8 fill-current">{icon}</div>
|
<div className="pt-8 fill-current">{icon}</div>
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<h1 className="text-h4 text-black dark:text-white capitalize mb-12">
|
<h1
|
||||||
|
data-testid="dialog-title"
|
||||||
|
className="text-h4 text-black dark:text-white capitalize mb-12"
|
||||||
|
>
|
||||||
{title}
|
{title}
|
||||||
</h1>
|
</h1>
|
||||||
{children}
|
{children}
|
||||||
@ -65,7 +68,11 @@ interface StepProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Step = ({ children }: StepProps) => {
|
const Step = ({ children }: StepProps) => {
|
||||||
return <p className="flex justify-between">{children}</p>;
|
return (
|
||||||
|
<p data-testid="dialog-text" className="flex justify-between">
|
||||||
|
{children}
|
||||||
|
</p>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
interface DialogProps {
|
interface DialogProps {
|
||||||
|
@ -14,7 +14,7 @@ import {
|
|||||||
Select,
|
Select,
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import type BigNumber from 'bignumber.js';
|
import type BigNumber from 'bignumber.js';
|
||||||
import type { ReactNode } from 'react';
|
import type { ButtonHTMLAttributes, ReactNode } from 'react';
|
||||||
import { useForm, Controller } from 'react-hook-form';
|
import { useForm, Controller } from 'react-hook-form';
|
||||||
import type { WithdrawalFields } from './use-withdraw';
|
import type { WithdrawalFields } from './use-withdraw';
|
||||||
import type { Asset } from './types';
|
import type { Asset } from './types';
|
||||||
@ -124,6 +124,7 @@ export const WithdrawForm = ({
|
|||||||
)}
|
)}
|
||||||
{ethereumAccount && (
|
{ethereumAccount && (
|
||||||
<UseButton
|
<UseButton
|
||||||
|
data-testid="use-connected"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setValue('to', ethereumAccount);
|
setValue('to', ethereumAccount);
|
||||||
clearErrors('to');
|
clearErrors('to');
|
||||||
@ -154,6 +155,7 @@ export const WithdrawForm = ({
|
|||||||
)}
|
)}
|
||||||
{selectedAsset && (
|
{selectedAsset && (
|
||||||
<UseButton
|
<UseButton
|
||||||
|
data-testid="use-maximum"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setValue('amount', max.toFixed(selectedAsset.decimals));
|
setValue('amount', max.toFixed(selectedAsset.decimals));
|
||||||
clearErrors('amount');
|
clearErrors('amount');
|
||||||
@ -163,22 +165,23 @@ export const WithdrawForm = ({
|
|||||||
</UseButton>
|
</UseButton>
|
||||||
)}
|
)}
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<Button type="submit">Submit</Button>
|
<Button data-testid="submit-withdrawal" type="submit">
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
interface UseButtonProps {
|
interface UseButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
onClick: () => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const UseButton = ({ children, onClick }: UseButtonProps) => {
|
const UseButton = ({ children, ...rest }: UseButtonProps) => {
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
|
{...rest}
|
||||||
type="button"
|
type="button"
|
||||||
className="ml-auto text-ui absolute top-0 right-0 underline"
|
className="ml-auto text-ui absolute top-0 right-0 underline"
|
||||||
onClick={onClick}
|
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</button>
|
</button>
|
||||||
|
Loading…
Reference in New Issue
Block a user