From a8cd7f157fe8981b9ff1a023ac30c3b04432a550 Mon Sep 17 00:00:00 2001 From: Ben Date: Thu, 30 Nov 2023 09:42:57 +0000 Subject: [PATCH] chore(trading): migrate cypress tests to python (#5367) --- .../src/integration/market-summary.cy.ts | 182 ------------------ .../src/integration/vega-wallet-prompt.cy.ts | 103 ---------- .../src/integration/wallet-eth.cy.ts | 12 -- .../src/integration/wallet-vega.cy.ts | 91 --------- .../market_lifecycle/test_market_lifecycle.py | 25 ++- apps/trading/e2e/tests/wallet/test_wallet.py | 116 +++++++++++ 6 files changed, 140 insertions(+), 389 deletions(-) delete mode 100644 apps/trading-e2e/src/integration/market-summary.cy.ts delete mode 100644 apps/trading-e2e/src/integration/vega-wallet-prompt.cy.ts delete mode 100644 apps/trading-e2e/src/integration/wallet-vega.cy.ts create mode 100644 apps/trading/e2e/tests/wallet/test_wallet.py diff --git a/apps/trading-e2e/src/integration/market-summary.cy.ts b/apps/trading-e2e/src/integration/market-summary.cy.ts deleted file mode 100644 index 8339182b3..000000000 --- a/apps/trading-e2e/src/integration/market-summary.cy.ts +++ /dev/null @@ -1,182 +0,0 @@ -import * as Schema from '@vegaprotocol/types'; - -const expirtyTooltip = 'expiry-tooltip'; -const externalLink = 'external-link'; -const itemHeader = 'item-header'; -const itemValue = 'item-value'; -const link = 'link'; -const liquidityLink = 'view-liquidity-link'; -const liquiditySupplied = 'liquidity-supplied'; -const liquiditySuppliedTooltip = 'liquidity-supplied-tooltip'; -const marketChange = 'market-change'; -const marketExpiry = 'market-expiry'; -const marketMode = 'market-trading-mode'; -const marketName = 'header-title'; -const marketPrice = 'market-price'; -const marketSettlement = 'market-settlement-asset'; -const marketSummaryBlock = 'header-summary'; -const marketVolume = 'market-volume'; -const percentageValue = 'price-change-percentage'; -const priceChangeValue = 'price-change'; -const tradingModeTooltip = 'trading-mode-tooltip'; - -describe('Market trading page', () => { - before(() => { - cy.clearAllLocalStorage(); - cy.mockTradingPage( - Schema.MarketState.STATE_ACTIVE, - Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION, - Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET - ); - cy.mockSubscription(); - cy.setOnBoardingViewed(); - cy.visit('/#/markets/market-0'); - cy.wait('@MarketData'); - cy.getByTestId(marketSummaryBlock).should('be.visible'); - }); - - describe('Market summary', { tags: '@smoke' }, () => { - // 7002-SORD-001 - // 7002-SORD-002 - it('must display market name', () => { - // 6002-MDET-001 - cy.getByTestId(marketName).should('not.be.empty'); - }); - - it('must see market expiry', () => { - // 6002-MDET-002 - cy.getByTestId(marketSummaryBlock).within(() => { - cy.getByTestId(marketExpiry).within(() => { - cy.getByTestId(itemHeader).should('have.text', 'Expiry'); - cy.getByTestId(itemValue).should('not.be.empty'); - }); - }); - }); - - it('must see market price', () => { - // 6002-MDET-003 - cy.getByTestId(marketSummaryBlock).within(() => { - cy.getByTestId(marketPrice).within(() => { - cy.getByTestId(itemHeader).should('have.text', 'Mark Price'); - cy.getByTestId(itemValue).should('not.be.empty'); - }); - }); - }); - - it('must see market change', () => { - // 6002-MDET-004 - cy.getByTestId(marketSummaryBlock).within(() => { - cy.getByTestId(marketChange).within(() => { - cy.getByTestId(itemHeader).should('have.text', 'Change (24h)'); - cy.getByTestId(percentageValue).should('not.be.empty'); - cy.getByTestId(priceChangeValue).should('not.be.empty'); - }); - }); - }); - - it('must see market volume', () => { - // 6002-MDET-005 - cy.getByTestId(marketSummaryBlock).within(() => { - cy.getByTestId(marketVolume).within(() => { - cy.getByTestId(itemHeader).should('have.text', 'Volume (24h)'); - cy.getByTestId(itemValue).should('not.be.empty'); - }); - }); - }); - - it('must see market settlement', () => { - // 6002-MDET-008 - cy.getByTestId(marketSummaryBlock).within(() => { - cy.getByTestId(marketSettlement).within(() => { - cy.getByTestId(itemHeader).should('have.text', 'Settlement asset'); - cy.getByTestId(itemValue).should('not.be.empty'); - }); - }); - }); - }); - - describe('Market tooltips', { tags: '@smoke' }, () => { - it('should see expiry tooltip', () => { - cy.getByTestId(marketSummaryBlock).within(() => { - cy.getByTestId(marketExpiry).within(() => { - cy.getByTestId(itemValue) - .should('have.text', 'Not time-based') - .realHover(); - }); - }); - cy.getByTestId(expirtyTooltip) - .eq(0) - .should( - 'contain.text', - 'This market expires when triggered by its oracle, not on a set date.' - ) - .within(() => { - cy.getByTestId(link) - .should('have.attr', 'href') - .and('include', Cypress.env('EXPLORER_URL')); - }); - }); - - it('should see trading conditions tooltip', () => { - const toolTipLabel = 'tooltip-label'; - const toolTipValue = 'tooltip-value'; - const auctionToolTipLabels = [ - 'Auction start', - 'Est. auction end', - 'Target liquidity', - 'Current liquidity', - 'Est. uncrossing price', - 'Est. uncrossing vol', - ]; - - cy.getByTestId(marketSummaryBlock).within(() => { - cy.getByTestId(marketMode).within(() => { - cy.getByTestId(itemValue) - .should('contain.text', 'Monitoring auction') - .and('contain.text', 'liquidity') - .realHover(); - }); - }); - cy.getByTestId(tradingModeTooltip) - .should( - 'contain.text', - 'This market is in auction until it reaches sufficient liquidity.' - ) - .eq(0) - .within(() => { - cy.getByTestId(externalLink) - .should('have.attr', 'href') - .and('include', Cypress.env('TRADING_MODE_LINK')); - - for (let i = 0; i < 6; i++) { - cy.getByTestId(toolTipLabel) - .eq(i) - .should('have.text', auctionToolTipLabels[i]); - cy.getByTestId(toolTipValue).eq(i).should('not.be.empty'); - } - }); - }); - - it('should see liquidity supplied tooltip', () => { - cy.getByTestId(marketSummaryBlock).within(() => { - cy.getByTestId(liquiditySupplied).within(() => { - cy.getByTestId(itemValue).realHover(); - }); - }); - cy.getByTestId(liquiditySuppliedTooltip) - .should('contain.text', 'Supplied stake') - .and('contain.text', 'Target stake') - .first() - .within(() => { - cy.getByTestId(liquidityLink).should( - 'have.text', - 'View liquidity provision table' - ); - cy.getByTestId(externalLink).should( - 'have.text', - 'Learn about providing liquidity' - ); - }); - }); - }); -}); diff --git a/apps/trading-e2e/src/integration/vega-wallet-prompt.cy.ts b/apps/trading-e2e/src/integration/vega-wallet-prompt.cy.ts deleted file mode 100644 index 444f12e3a..000000000 --- a/apps/trading-e2e/src/integration/vega-wallet-prompt.cy.ts +++ /dev/null @@ -1,103 +0,0 @@ -import * as Schema from '@vegaprotocol/types'; -import type { OrderSubmission } from '@vegaprotocol/wallet'; -import { createOrder } from '../support/create-order'; - -describe( - 'vega wallet - prompt', - { tags: '@regression', testIsolation: true }, - () => { - describe('must submit order', { tags: '@smoke' }, () => { - // 7002-SORD-039 - beforeEach(() => { - cy.setVegaWallet(); - cy.mockTradingPage(); - cy.mockSubscription(); - cy.visit('/#/markets/market-0'); - cy.wait('@Markets'); - }); - - it('must see a prompt to check connected vega wallet to approve transaction', () => { - // 0003-WTXN-002 - cy.mockVegaWalletTransaction(1000); - const order: OrderSubmission = { - marketId: 'market-0', - type: Schema.OrderType.TYPE_MARKET, - side: Schema.Side.SIDE_BUY, - timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_FOK, - size: '100', - }; - createOrder(order); - cy.getByTestId('toast-content').should( - 'contain.text', - 'Please go to your Vega wallet application and approve or reject the transaction.' - ); - }); - - it('must show error returned by wallet ', () => { - // 0003-WTXN-009 - // 0003-WTXN-011 - // 0002-WCON-016 - // 0003-WTXN-008 - - //trigger error from the wallet - cy.intercept('POST', 'http://localhost:1789/api/v2/requests', (req) => { - req.on('response', (res) => { - res.send({ - jsonrpc: '2.0', - id: '1', - }); - }); - }); - - const order: OrderSubmission = { - marketId: 'market-0', - type: Schema.OrderType.TYPE_MARKET, - side: Schema.Side.SIDE_BUY, - timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_FOK, - size: '100', - }; - createOrder(order); - cy.getByTestId('toast-content').should( - 'contain.text', - 'The connection to your Vega Wallet has been lost.' - ); - cy.getByTestId('connect-vega-wallet').click(); - cy.getByTestId('dialog-content').should('be.visible'); - }); - - it('must see that the order was rejected by the connected wallet', () => { - // 0003-WTXN-007 - - //trigger rejection error from the wallet - cy.intercept('POST', 'http://localhost:1789/api/v2/requests', (req) => { - req.alias = 'client.send_transaction'; - req.reply({ - statusCode: 400, - body: { - jsonrpc: '2.0', - error: { - code: 3001, - data: 'the user rejected the wallet connection', - message: 'User error', - }, - id: '0', - }, - }); - }); - - const order: OrderSubmission = { - marketId: 'market-0', - type: Schema.OrderType.TYPE_MARKET, - side: Schema.Side.SIDE_BUY, - timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_FOK, - size: '100', - }; - createOrder(order); - cy.getByTestId('toast-content').should( - 'contain.text', - 'Error occurredthe user rejected the wallet connection' - ); - }); - }); - } -); diff --git a/apps/trading-e2e/src/integration/wallet-eth.cy.ts b/apps/trading-e2e/src/integration/wallet-eth.cy.ts index 13dd34186..9f10ce504 100644 --- a/apps/trading-e2e/src/integration/wallet-eth.cy.ts +++ b/apps/trading-e2e/src/integration/wallet-eth.cy.ts @@ -26,18 +26,6 @@ describe('ethereum wallet', { tags: '@smoke', testIsolation: true }, () => { cy.getByTestId('tab-deposits').should('not.be.empty'); }); - it.skip('should see QR code modal for WalletConnect', () => { - // 0004-EWAL-003 - - cy.getByTestId('Deposits').click(); - cy.getByTestId('deposit-button').click(); - cy.getByTestId('connect-eth-wallet-btn').click(); - cy.getByTestId('web3-connector-list').should('exist'); - cy.getByTestId('web3-connector-WalletConnect').click(); - // testing if exists rather than visible because of the long loading time - cy.get('#w3m-modal').should('exist'); - }); - it('able to disconnect eth wallet', () => { // 0004-EWAL-004 // 0004-EWAL-005 diff --git a/apps/trading-e2e/src/integration/wallet-vega.cy.ts b/apps/trading-e2e/src/integration/wallet-vega.cy.ts deleted file mode 100644 index f0b5c19eb..000000000 --- a/apps/trading-e2e/src/integration/wallet-vega.cy.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { - mockConnectWallet, - mockConnectWalletWithUserError, -} from '@vegaprotocol/cypress'; - -const connectVegaBtn = 'connect-vega-wallet'; -const manageVegaBtn = 'manage-vega-wallet'; -const dialogContent = 'dialog-content'; - -describe('connect vega wallet', { tags: '@smoke', testIsolation: true }, () => { - beforeEach(() => { - // Using portfolio page as it requires vega wallet connection - cy.mockTradingPage(); - cy.mockSubscription(); - cy.setOnBoardingViewed(); - cy.visit('/#/portfolio'); - cy.get('[data-testid="pathname-/portfolio"]').should('exist'); - }); - - it('can connect', () => { - // 0002-WCON-002 - // 0002-WCON-005 - // 0002-WCON-007 - // 0002-WCON-009 - - mockConnectWallet(); - cy.getByTestId(connectVegaBtn).click(); - cy.getByTestId('connectors-list') - .find('[data-testid="connector-jsonRpc"]') - .click(); - cy.wait('@walletReq'); - cy.getByTestId(dialogContent).should( - 'contain.text', - 'Approve the connection from your Vega wallet app.' - ); - cy.getByTestId(dialogContent).should('not.exist'); - cy.getByTestId(manageVegaBtn).should('exist'); - }); - - it('can not connect', () => { - // 0002-WCON-002 - // 0002-WCON-005 - // 0002-WCON-007 - // 0002-WCON-015 - - mockConnectWalletWithUserError(); - cy.getByTestId(connectVegaBtn).click(); - cy.getByTestId('connectors-list') - .find('[data-testid="connector-jsonRpc"]') - .click(); - cy.getByTestId('dialog-content') - .should('contain.text', 'User error') - .and('contain.text', 'the user rejected the wallet connection'); - }); - - it('can change selected public key and disconnect', () => { - // 0002-WCON-022 - // 0002-WCON-023 - // 0002-WCON-025 - // 0002-WCON-026 - // 0002-WCON-021 - // 0002-WCON-027 - // 0002-WCON-030 - // 0002-WCON-029 - // 0002-WCON-008 - // 0002-WCON-035 - // 0002-WCON-014 - // 0002-WCON-010 - // 0003-WTXN-004 - - mockConnectWallet(); - const key2 = Cypress.env('VEGA_PUBLIC_KEY2'); - const truncatedKey2 = Cypress.env('TRUNCATED_VEGA_PUBLIC_KEY2'); - cy.connectVegaWallet(); - cy.getByTestId('manage-vega-wallet').click(); - cy.getByTestId('keypair-list').should('exist'); - cy.getByTestId(`key-${key2}`).should('contain.text', truncatedKey2); - cy.getByTestId(`key-${key2}`) - .find('[data-testid="copy-vega-public-key"]') - .should('be.visible'); - cy.get(`[data-testid="key-${key2}"] > .mr-2`).click(); - cy.getByTestId('keypair-list') - .find('[data-state="checked"]') - .should('be.visible'); - cy.getByTestId('disconnect').click(); - cy.getByTestId('connect-vega-wallet').should('exist'); - cy.getByTestId('manage-vega-wallet').should('not.exist'); - cy.getByTestId('connect-vega-wallet').click(); - cy.contains('Enter a custom wallet location'); - }); -}); diff --git a/apps/trading/e2e/tests/market_lifecycle/test_market_lifecycle.py b/apps/trading/e2e/tests/market_lifecycle/test_market_lifecycle.py index 7d7b740a2..4449f9abd 100644 --- a/apps/trading/e2e/tests/market_lifecycle/test_market_lifecycle.py +++ b/apps/trading/e2e/tests/market_lifecycle/test_market_lifecycle.py @@ -1,4 +1,5 @@ import pytest +import re import vega_sim.api.governance as governance from playwright.sync_api import Page, expect from vega_sim.service import VegaService, PeggedOrder @@ -10,6 +11,8 @@ from wallet_config import MM_WALLET, MM_WALLET2, GOVERNANCE_WALLET @pytest.mark.usefixtures("vega", "page", "proposed_market", "risk_accepted") def test_market_lifecycle(proposed_market, vega: VegaService, page: Page): + # 7002-SORD-001 + # 7002-SORD-002 trading_mode = page.get_by_test_id("market-trading-mode").get_by_test_id( "item-value" ) @@ -18,12 +21,32 @@ def test_market_lifecycle(proposed_market, vega: VegaService, page: Page): # setup market in proposed step, without liquidity provided market_id = proposed_market page.goto(f"/#/markets/{market_id}") - + # 6002-MDET-001 + expect(page.get_by_test_id("header-title")).to_have_text("BTC:DAI_2023Futr") + # 6002-MDET-002 + expect(page.get_by_test_id("market-expiry")).to_have_text("ExpiryNot time-based") + page.get_by_test_id("market-expiry").hover() + expect(page.get_by_test_id("expiry-tooltip").first).to_have_text("This market expires when triggered by its oracle, not on a set date.View oracle specification") + expect(page.get_by_test_id("expiry-tooltip").first.get_by_test_id("link")).to_have_attribute("href", re.compile('.*')) + # 6002-MDET-003 + expect(page.get_by_test_id("market-price")).to_have_text("Mark Price0.00") + # 6002-MDET-004 + expect(page.get_by_test_id("market-change")).to_have_text("Change (24h)0.00%0.00") + # 6002-MDET-005 + expect(page.get_by_test_id("market-volume")).to_have_text("Volume (24h)-") + # 6002-MDET-008 + expect(page.get_by_test_id("market-settlement-asset")).to_have_text("Settlement assettDAI") + expect(page.get_by_test_id("liquidity-supplied")).to_have_text("Liquidity supplied 0.00 (0.00%)") + page.get_by_test_id("liquidity-supplied").hover() + expect(page.get_by_test_id("liquidity-supplied-tooltip").first).to_have_text("Supplied stake0.00Target stake0.00View liquidity provision tableLearn about providing liquidity") + expect(page.get_by_test_id("liquidity-supplied-tooltip").first.get_by_test_id("link").first).to_have_text("View liquidity provision table") # check that market is in proposed state # 6002-MDET-006 # 6002-MDET-007 # 7002-SORD-061 expect(trading_mode).to_have_text("No trading") + trading_mode.hover() + expect(page.get_by_test_id("trading-mode-tooltip").first).to_have_text("No trading enabled for this market.") expect(market_state).to_have_text("Proposed") # approve market diff --git a/apps/trading/e2e/tests/wallet/test_wallet.py b/apps/trading/e2e/tests/wallet/test_wallet.py new file mode 100644 index 000000000..2f33742f7 --- /dev/null +++ b/apps/trading/e2e/tests/wallet/test_wallet.py @@ -0,0 +1,116 @@ +import pytest +import re +import json +from playwright.sync_api import Page, expect, Route +from vega_sim.service import VegaService +from conftest import init_vega +from fixtures.market import setup_continuous_market + +order_size = "order-size" +order_price = "order-price" +place_order = "place-order" +order_side_sell = "order-side-SIDE_SELL" +market_order = "order-type-Market" +tif = "order-tif" +expire = "expire" +api_request_match = r"http://localhost:\d+/api/v2/requests" + +@pytest.fixture(scope="module") +def vega(request): + with init_vega(request) as vega: + yield vega + + +@pytest.fixture(scope="module") +def continuous_market(vega): + return setup_continuous_market(vega) + +def handle_route_connection_lost(route: Route, request): + if request.method == "POST" and re.match(api_request_match, request.url): + route.fulfill( + status=200, + headers={"Content-Type": "application/json"}, + body='{"jsonrpc": "2.0", "id": "1"}' + ) + else: + route.continue_() + +def handle_route_connection_rejected(route: Route, request): + if request.method == "POST" and re.match(api_request_match, request.url): + custom_response = { + "jsonrpc": "2.0", + "error": { + "code": 3001, + "data": "the user rejected the wallet connection", + "message": "User error" + }, + "id": "0" + } + route.fulfill( + status=400, + headers={"Content-Type": "application/json"}, + body=json.dumps(custom_response) + ) + else: + route.continue_() + +def assert_connection_approve(route: Route, request, page:Page): + if request.method == "POST" and re.match(api_request_match, request.url): + expect(page.get_by_test_id("toast-content")).to_have_text("Please go to your Vega wallet application and approve or reject the transaction.") + else: + route.continue_() + +@pytest.mark.usefixtures("page", "auth", "risk_accepted") +def test_wallet_connection_error(continuous_market, page: Page): + page.goto(f"/#/markets/{continuous_market}") + page.route("**/*", handle_route_connection_lost) + page.get_by_test_id("connect-vega-wallet").click() + page.get_by_test_id("connector-jsonRpc").click() + expect(page.get_by_test_id("wallet-dialog-title")).to_have_text("Something went wrong") + +@pytest.mark.usefixtures("page", "risk_accepted") +def test_wallet_connection_rejected(continuous_market, page: Page): + # 0002-WCON-002 + # 0002-WCON-005 + # 0002-WCON-007 + # 0002-WCON-015 + page.goto(f"/#/markets/{continuous_market}") + page.route("**/*", handle_route_connection_rejected) + page.get_by_test_id("connect-vega-wallet").click() + page.get_by_test_id("connector-jsonRpc").click() + expect(page.get_by_test_id("dialog-content").nth(1)).to_have_text("User errorthe user rejected the wallet connectionTry againAbout the Vega wallet | Supported browsers ") + + +@pytest.mark.usefixtures("page", "auth", "risk_accepted") +def test_wallet_connection_error_transaction(continuous_market, vega: VegaService, page: Page): + # 0003-WTXN-009 + # 0003-WTXN-011 + # 0002-WCON-016 + # 0003-WTXN-008 + page.goto(f"/#/markets/{continuous_market}") + page.get_by_test_id(order_size).fill("10") + page.get_by_test_id(order_price).fill("120") + page.route("**/*", handle_route_connection_lost) + page.get_by_test_id(place_order).click() + expect(page.get_by_test_id("toast-content")).to_have_text("Wallet disconnectedThe connection to your Vega Wallet has been lost.Connect vega wallet") + +@pytest.mark.usefixtures("page", "auth", "risk_accepted") +def test_wallet_transaction_rejected(continuous_market, vega: VegaService, page: Page): + # 0003-WTXN-007 + page.goto(f"/#/markets/{continuous_market}") + page.get_by_test_id(order_size).fill("10") + page.get_by_test_id(order_price).fill("120") + page.route("**/*", handle_route_connection_rejected) + page.get_by_test_id(place_order).click() + expect(page.get_by_test_id("toast-content")).to_have_text("Error occurredthe user rejected the wallet connection") + +@pytest.mark.usefixtures("page", "auth", "risk_accepted") +def test_wallet_connection_approve(continuous_market, vega: VegaService, page: Page): + # 0002-WCON-005 + # 0002-WCON-007 + # 0002-WCON-009 + page.goto(f"/#/markets/{continuous_market}") + page.get_by_test_id(order_size).fill("10") + page.get_by_test_id(order_price).fill("120") + page.route("**/*", assert_connection_approve) + page.get_by_test_id(place_order).click() \ No newline at end of file