Test/deal ticket tests (#161)
* scaffold dealticket package, remove trading views from react-helpers * add deal ticket component, add intent utils, expand dialog and form group styles * add splash component, show market not found message if market doesnt exist * tidy up error handling * add handleError method for vega tx hook * add better testname for provider test, flesh out tests a bit more for deal ticket * Add unit tests for useVegaTransaction and useOrderSubmit hooks * add wrapper component for order dialog styles * add vega styled loader to ui toolkit and use in order dialog * add title prop to order dialog * split limit and market tickets into own files * add button radio component * revert dialog styles * move splash component to ui-toolkit, add story * convert intent to enum * Make button always type=button unless type prop is passed * inline filter logic for tif selector * add date-fns, add datetime to helpers * add order types to wallet package, make price undefined if order type is market * use enums in deal ticket logic * tidy up order state by moving submit and transaction hooks out of deal ticket * add comment for dialog styles * remove decimal from price input * add types package, delete old generated types from trading project * rename types package to graphql * update generate command to point to correct locations * fix use order submit test * BDD and navigation tests passing * Remove commented steps * Steps up to placing order * Date picker and date-fns update * Vega connector wallet tests * Passing up to request sent, updated date picker * Tests for sell orders and errors * Update market feature * Fix failing tests * Update wallet login * Readded tx hash assertion and remaining tests * Add CI wallet import * Update .github/workflows/cypress.yml Co-authored-by: Dexter Edwards <dexter.edwards93@gmail.com> * Resolved PR comments * Fix yaml error * Attempt to fix failing tests in CI * Run Cypress in Chrome * Add reload if public key error displayed * Fix wallet name * Add force click and waits * Increase timeout for deal ticket page * Removed network list from yaml and using input error id * Increase timeout to 8 seconds * Re add deleted test id Co-authored-by: Matthew Russell <mattrussell36@gmail.com> Co-authored-by: Dexter Edwards <dexter.edwards93@gmail.com>
This commit is contained in:
parent
8fd1d00474
commit
205f4124f1
51
.github/workflows/cypress.yml
vendored
51
.github/workflows/cypress.yml
vendored
@ -11,7 +11,13 @@ jobs:
|
||||
master:
|
||||
name: Run end-to-end tests - main
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
vegawallet-version:
|
||||
- '0.13.2'
|
||||
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
@ -28,11 +34,34 @@ jobs:
|
||||
node-version: 16.14.0
|
||||
- name: Install root dependencies
|
||||
run: yarn install
|
||||
|
||||
- name: Download and unzip wallet
|
||||
run: curl -L https://github.com/vegaprotocol/vegawallet/releases/download/v${{ matrix.vegawallet-version }}/vegawallet-linux-amd64.zip -O
|
||||
- name: Unzip wallet
|
||||
run: unzip ./vegawallet-linux-amd64.zip
|
||||
- name: Create passphrase
|
||||
run: echo "${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}" > ./passphrase
|
||||
- name: Create recovery
|
||||
run: echo "${{ secrets.TRADING_TEST_VEGA_WALLET_RECOVERY }}" > ./recovery
|
||||
|
||||
- name: Initialize wallet
|
||||
run: ./vegawallet init -f
|
||||
- name: Import wallet
|
||||
run: ./vegawallet import -w UI_Trading_Test --recovery-phrase-file ./recovery -p ./passphrase
|
||||
- name: Import config
|
||||
run: ./vegawallet network import --from-url https://raw.githubusercontent.com/vegaprotocol/networks/master/fairground/fairground.toml
|
||||
- name: Start service
|
||||
run: ./vegawallet service run --network fairground &
|
||||
|
||||
- name: Run Cypress tests
|
||||
run: npx nx affected:e2e --parallel=5 --record --key ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||
run: npx nx affected:e2e --parallel=5 --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --env.tradingWalletPassphrase=${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }} --browser chrome
|
||||
pr:
|
||||
name: Run end-to-end tests - PR
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
vegawallet-version:
|
||||
- '0.13.2'
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
@ -51,5 +80,23 @@ jobs:
|
||||
node-version: 16.14.0
|
||||
- name: Install root dependencies
|
||||
run: yarn install
|
||||
- name: Download and unzip wallet
|
||||
run: curl -L https://github.com/vegaprotocol/vegawallet/releases/download/v${{ matrix.vegawallet-version }}/vegawallet-linux-amd64.zip -O
|
||||
- name: Unzip wallet
|
||||
run: unzip ./vegawallet-linux-amd64.zip
|
||||
- name: Create passphrase
|
||||
run: echo "${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}" > ./passphrase
|
||||
- name: Create recovery
|
||||
run: echo "${{ secrets.TRADING_TEST_VEGA_WALLET_RECOVERY }}" > ./recovery
|
||||
|
||||
- name: Initialize wallet
|
||||
run: ./vegawallet init -f
|
||||
- name: Import wallet
|
||||
run: ./vegawallet import -w UI_Trading_Test --recovery-phrase-file ./recovery -p ./passphrase
|
||||
- name: Import config
|
||||
run: ./vegawallet network import --from-url https://raw.githubusercontent.com/vegaprotocol/networks/master/fairground/fairground.toml
|
||||
- name: Start service
|
||||
run: ./vegawallet service run --network fairground &
|
||||
|
||||
- name: Run Cypress tests
|
||||
run: npx nx affected:e2e --parallel=5 --record --key ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||
run: npx nx affected:e2e --parallel=5 --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --env.tradingWalletPassphrase=${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }} --browser chrome
|
||||
|
@ -14,6 +14,7 @@
|
||||
"screenshotsFolder": "../../dist/cypress/apps/explorer-e2e/screenshots",
|
||||
"chromeWebSecurity": false,
|
||||
"env": {
|
||||
"tsConfig": "tsconfig.json"
|
||||
"tsConfig": "tsconfig.json",
|
||||
"TAGS": "not @todo and not @ignore and not @manual"
|
||||
}
|
||||
}
|
||||
|
3
apps/trading-e2e/.cypress-cucumber-preprocessorrc
Normal file
3
apps/trading-e2e/.cypress-cucumber-preprocessorrc
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"stepDefinitions": "src/support/step_definitions"
|
||||
}
|
@ -1,13 +1,20 @@
|
||||
{
|
||||
"baseUrl": "http://localhost:4200",
|
||||
"fileServerFolder": ".",
|
||||
"fixturesFolder": "./src/fixtures",
|
||||
"fixturesFolder": false,
|
||||
"pluginsFile": "./src/plugins/index.js",
|
||||
"testFiles": "*.{ts,feature,features}",
|
||||
"ignoreTestFiles": "**/*.js",
|
||||
"integrationFolder": "./src/integration",
|
||||
"modifyObstructiveCode": false,
|
||||
"supportFile": "./src/support/index.ts",
|
||||
"pluginsFile": false,
|
||||
"video": true,
|
||||
"videosFolder": "../../dist/cypress/apps/trading-e2e/videos",
|
||||
"screenshotsFolder": "../../dist/cypress/apps/trading-e2e/screenshots",
|
||||
"chromeWebSecurity": false,
|
||||
"projectId": "et4snf"
|
||||
"projectId": "et4snf",
|
||||
"env": {
|
||||
"tsConfig": "tsconfig.json",
|
||||
"TAGS": "not @todo and not @ignore and not @manual"
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +0,0 @@
|
||||
import { getGreeting } from '../support/app.po';
|
||||
|
||||
describe('trading', () => {
|
||||
beforeEach(() => cy.visit('/'));
|
||||
|
||||
it('should display welcome message', () => {
|
||||
// Custom command example, see `../support/commands.ts` file
|
||||
cy.login('my-email@something.com', 'myPassword');
|
||||
|
||||
// Function helper example, see `../support/app.po.ts` file
|
||||
getGreeting().contains('Welcome to Vega Trading App');
|
||||
});
|
||||
});
|
18
apps/trading-e2e/src/integration/home-page.feature
Normal file
18
apps/trading-e2e/src/integration/home-page.feature
Normal file
@ -0,0 +1,18 @@
|
||||
Feature: Home page
|
||||
|
||||
Scenario: Visit Home page
|
||||
Given I am on the homepage
|
||||
|
||||
Scenario: Visit Portfolio page
|
||||
Given I am on the homepage
|
||||
And I navigate to portfolio page
|
||||
|
||||
Scenario: Unable to connect Vega wallet with incorrect credentials
|
||||
Given I am on the homepage
|
||||
When I try to connect Vega wallet with incorrect details
|
||||
Then wallet not running error message is displayed
|
||||
|
||||
Scenario: Unable to connect Vega wallet with blank fields
|
||||
Given I am on the homepage
|
||||
When I try to connect Vega wallet with blank fields
|
||||
Then wallet field validation errors are shown
|
98
apps/trading-e2e/src/integration/market-order.feature
Normal file
98
apps/trading-e2e/src/integration/market-order.feature
Normal file
@ -0,0 +1,98 @@
|
||||
Feature: Market orders
|
||||
|
||||
Scenario Outline: Successfull market buy orders
|
||||
Given I am on the homepage
|
||||
And I navigate to markets page
|
||||
When I click on active market
|
||||
And I connect to Vega Wallet
|
||||
And place a buy '<marketOrderType>' market order
|
||||
Then order request is sent
|
||||
|
||||
Examples:
|
||||
| marketOrderType |
|
||||
| FOK |
|
||||
| IOC |
|
||||
|
||||
Scenario Outline: Successfull Limit buy orders
|
||||
Given I am on the homepage
|
||||
And I navigate to markets page
|
||||
When I click on active market
|
||||
And I connect to Vega Wallet
|
||||
And place a buy '<limitOrderType>' limit order
|
||||
Then order request is sent
|
||||
|
||||
Examples:
|
||||
| limitOrderType |
|
||||
| IOC |
|
||||
| FOK |
|
||||
| GTT |
|
||||
# | GFA | Requires market to be in auction
|
||||
| GFN |
|
||||
|
||||
Scenario Outline: Successfull market sell order
|
||||
Given I am on the homepage
|
||||
And I navigate to markets page
|
||||
When I click on active market
|
||||
And I connect to Vega Wallet
|
||||
And place a sell '<marketOrderType>' market order
|
||||
Then order request is sent
|
||||
|
||||
Examples:
|
||||
| marketOrderType |
|
||||
| FOK |
|
||||
| IOC |
|
||||
|
||||
Scenario Outline: Successfull limit sell order
|
||||
Given I am on the homepage
|
||||
And I navigate to markets page
|
||||
When I click on active market
|
||||
And I connect to Vega Wallet
|
||||
And place a sell '<limitOrderType>' limit order
|
||||
|
||||
Examples:
|
||||
| limitOrderType |
|
||||
| IOC |
|
||||
| FOK |
|
||||
| GTT |
|
||||
# | GFA | Requires market to be in auction
|
||||
| GFN |
|
||||
|
||||
Scenario: Unsuccessfull order because lack of funds
|
||||
Given I am on the homepage
|
||||
And I navigate to markets page
|
||||
When I click on active market
|
||||
And I connect to Vega Wallet
|
||||
And place a buy 'FOK' market order
|
||||
Then error message for insufficient funds is displayed
|
||||
|
||||
Scenario: Unable to order because market is suspended
|
||||
Given I am on the homepage
|
||||
And I navigate to markets page
|
||||
When I click on suspended market
|
||||
And I connect to Vega Wallet
|
||||
Then place order button is disabled
|
||||
And "Market is currently suspended" error is shown
|
||||
|
||||
Scenario: Unable to order because wallet is not connected
|
||||
Given I am on the homepage
|
||||
And I navigate to markets page
|
||||
When I click on active market
|
||||
Then place order button is disabled
|
||||
And "No public key selected" error is shown
|
||||
|
||||
Scenario: Unsuccessfull because quantity is 0
|
||||
Given I am on the homepage
|
||||
And I navigate to markets page
|
||||
When I click on active market
|
||||
And I connect to Vega Wallet
|
||||
And place a buy 'FOK' market order with amount of 0
|
||||
Then Order rejected by wallet error shown containing text "must be positive"
|
||||
|
||||
@manual
|
||||
Scenario: GTT order failed because invalid date
|
||||
|
||||
@manual
|
||||
Scenario: GTT order failed because date in the past
|
||||
|
||||
@manual
|
||||
Scenario: GTT order failed because date over allowed period
|
75
apps/trading-e2e/src/plugins/index.js
Normal file
75
apps/trading-e2e/src/plugins/index.js
Normal file
@ -0,0 +1,75 @@
|
||||
/// <reference types="cypress" />
|
||||
|
||||
const webpackPreprocessor = require('@cypress/webpack-preprocessor');
|
||||
const webpack = require('webpack');
|
||||
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
|
||||
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
|
||||
const nodeExternals = require('webpack-node-externals');
|
||||
|
||||
/**
|
||||
* @type {Cypress.PluginConfig}
|
||||
*/
|
||||
module.exports = (on, config) => {
|
||||
on(
|
||||
'file:preprocessor',
|
||||
webpackPreprocessor({
|
||||
webpackOptions: {
|
||||
resolve: {
|
||||
extensions: ['.ts', '.tsx', '.mjs', '.js', '.jsx'],
|
||||
plugins: [
|
||||
new TsconfigPathsPlugin({
|
||||
configFile: config.env.tsConfig,
|
||||
extensions: ['.ts', '.tsx', '.mjs', '.js', '.jsx'],
|
||||
}),
|
||||
],
|
||||
fallback: {
|
||||
path: require.resolve('path-browserify'),
|
||||
},
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.([jt])sx?$/,
|
||||
loader: 'ts-loader',
|
||||
exclude: [/node_modules/],
|
||||
options: {
|
||||
configFile: config.env.tsConfig,
|
||||
// https://github.com/TypeStrong/ts-loader/pull/685
|
||||
experimentalWatchApi: true,
|
||||
transpileOnly: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.feature$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'cypress-cucumber-preprocessor/loader',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.features$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'cypress-cucumber-preprocessor/lib/featuresLoader',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new ForkTsCheckerWebpackPlugin({
|
||||
typescript: {
|
||||
enabled: true,
|
||||
configFile: config.env.tsConfig,
|
||||
},
|
||||
}),
|
||||
new webpack.ProvidePlugin({
|
||||
process: 'process/browser',
|
||||
}),
|
||||
],
|
||||
externals: [nodeExternals()],
|
||||
},
|
||||
})
|
||||
);
|
||||
};
|
@ -13,6 +13,7 @@ declare namespace Cypress {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
interface Chainable<Subject> {
|
||||
login(email: string, password: string): void;
|
||||
getByTestId(selector: string): Chainable<JQuery<HTMLElement>>;
|
||||
}
|
||||
}
|
||||
//
|
||||
@ -31,3 +32,6 @@ Cypress.Commands.add('login', (email, password) => {
|
||||
//
|
||||
// -- This will overwrite an existing command --
|
||||
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
|
||||
Cypress.Commands.add('getByTestId', (selector, ...args) => {
|
||||
return cy.get(`[data-testid=${selector}]`, ...args);
|
||||
});
|
||||
|
56
apps/trading-e2e/src/support/pages/base-page.js
Normal file
56
apps/trading-e2e/src/support/pages/base-page.js
Normal file
@ -0,0 +1,56 @@
|
||||
export default class BasePage {
|
||||
porfolioUrl = '/portfolio';
|
||||
marketsUrl = '/markets';
|
||||
connectVegaBtn = 'connect-vega-wallet';
|
||||
walletConnectors = 'connectors-list';
|
||||
walletForm = 'rest-connector-form';
|
||||
walletInputError = 'input-wallet-error';
|
||||
walletFormError = 'form-error';
|
||||
inputError = 'input-error-text';
|
||||
|
||||
navigateToPortfolio() {
|
||||
cy.get(`a[href='${this.porfolioUrl}']`).click();
|
||||
}
|
||||
|
||||
navigateToMarkets() {
|
||||
cy.get(`a[href='${this.marketsUrl}']`)
|
||||
.should('be.visible')
|
||||
.click({ force: true });
|
||||
cy.url().should('include', '/markets');
|
||||
}
|
||||
|
||||
navigateToConnectVegaWallet() {
|
||||
cy.getByTestId(this.connectVegaBtn).click();
|
||||
cy.contains('Connects using REST to a running Vega wallet service');
|
||||
cy.getByTestId(this.walletConnectors).find('button').click();
|
||||
}
|
||||
|
||||
fillInWalletForm(walletName, walletPassphrase) {
|
||||
cy.getByTestId(this.walletForm)
|
||||
.find('#wallet')
|
||||
.click({ force: true })
|
||||
.type(walletName);
|
||||
cy.getByTestId(this.walletForm)
|
||||
.find('#passphrase')
|
||||
.click({ force: true })
|
||||
.type(walletPassphrase);
|
||||
}
|
||||
|
||||
clickConnectVegaWallet() {
|
||||
cy.getByTestId(this.walletForm)
|
||||
.find('button[type=submit]')
|
||||
.click({ force: true });
|
||||
}
|
||||
|
||||
validateWalletNotRunningError() {
|
||||
cy.getByTestId(this.walletFormError).should(
|
||||
'have.text',
|
||||
'Authentication failed'
|
||||
);
|
||||
}
|
||||
|
||||
validateWalletErrorFieldsDisplayed() {
|
||||
cy.getByTestId(this.walletInputError).should('have.text', 'Required');
|
||||
cy.getByTestId(this.inputError).should('have.text', 'Required');
|
||||
}
|
||||
}
|
114
apps/trading-e2e/src/support/pages/deal-ticket-page.js
Normal file
114
apps/trading-e2e/src/support/pages/deal-ticket-page.js
Normal file
@ -0,0 +1,114 @@
|
||||
import BasePage from './base-page';
|
||||
export default class DealTicketPage extends BasePage {
|
||||
marketOrderType = 'order-type-TYPE_MARKET';
|
||||
limitOrderType = 'order-type-TYPE_LIMIT';
|
||||
buyOrder = 'order-side-SIDE_BUY';
|
||||
sellOrder = 'order-side-SIDE_SELL';
|
||||
orderSizeField = 'order-size';
|
||||
orderPriceField = 'order-price';
|
||||
orderTypeDropDown = 'order-tif';
|
||||
datePickerField = 'date-picker-field';
|
||||
placeOrderBtn = 'place-order';
|
||||
orderDialog = 'order-wrapper';
|
||||
orderStatusHeader = 'order-status-header';
|
||||
orderTransactionHash = 'tx-hash';
|
||||
orderErrorTxt = 'error-reason';
|
||||
|
||||
placeMarketOrder(isBuy, orderSize, orderType) {
|
||||
cy.get(`[data-testid=${this.placeOrderBtn}]`, { timeout: 8000 }).should(
|
||||
'be.visible'
|
||||
);
|
||||
|
||||
if (isBuy == false) {
|
||||
cy.getByTestId(this.sellOrder).click();
|
||||
}
|
||||
|
||||
cy.getByTestId(this.orderSizeField).clear().type(orderSize);
|
||||
cy.getByTestId(this.orderTypeDropDown).select(orderType);
|
||||
}
|
||||
|
||||
placeLimitOrder(isBuy, orderSize, orderPrice, orderType) {
|
||||
cy.getByTestId(this.limitOrderType).click();
|
||||
|
||||
if (isBuy == false) {
|
||||
cy.getByTestId(this.sellOrder).click();
|
||||
}
|
||||
|
||||
cy.getByTestId(this.orderSizeField).clear().type(orderSize);
|
||||
cy.getByTestId(this.orderPriceField).clear().type(orderPrice);
|
||||
cy.getByTestId(this.orderTypeDropDown).select(orderType);
|
||||
|
||||
if (orderType == 'GTT') {
|
||||
const today = new Date(new Date().setSeconds(0));
|
||||
const futureDate = new Date(today.setMonth(today.getMonth() + 1)); // set expiry to one month from now
|
||||
const formattedDate = this.formatDate(futureDate);
|
||||
cy.getByTestId(this.datePickerField).click().type(formattedDate);
|
||||
}
|
||||
}
|
||||
|
||||
verifyOrderRequestSent() {
|
||||
cy.getByTestId(this.orderStatusHeader).should(
|
||||
'have.text',
|
||||
'Awaiting network confirmation'
|
||||
);
|
||||
cy.getByTestId(this.orderTransactionHash)
|
||||
.invoke('text')
|
||||
.should('contain', 'Tx hash: ')
|
||||
.and('have.length.above', 64);
|
||||
}
|
||||
|
||||
verifyOrderFailedInsufficientFunds() {
|
||||
cy.get(`[data-testid=${this.orderErrorTxt}]`, { timeout: 8000 }).should(
|
||||
'have.text',
|
||||
'Reason: InsufficientAssetBalance'
|
||||
);
|
||||
}
|
||||
|
||||
clickPlaceOrder() {
|
||||
cy.getByTestId(this.placeOrderBtn).click();
|
||||
}
|
||||
|
||||
verifyPlaceOrderBtnDisabled() {
|
||||
cy.getByTestId(this.placeOrderBtn).should('be.disabled');
|
||||
}
|
||||
|
||||
verifySubmitBtnErrorText(expectedText) {
|
||||
cy.getByTestId(this.inputError).should('have.text', expectedText);
|
||||
}
|
||||
|
||||
verifyOrderRejected(errorMsg) {
|
||||
cy.getByTestId(this.orderStatusHeader).should(
|
||||
'have.text',
|
||||
'Order rejected by wallet'
|
||||
);
|
||||
cy.getByTestId(this.orderDialog)
|
||||
.find('pre')
|
||||
.should('contain.text', errorMsg);
|
||||
}
|
||||
|
||||
reloadPageIfPublicKeyErrorDisplayed() {
|
||||
cy.get('body').then(($body) => {
|
||||
if ($body.find(`[data-testid=${this.inputError}]`).length) {
|
||||
cy.getByTestId(this.inputError)
|
||||
.invoke('text')
|
||||
.then(($errorText) => {
|
||||
if ($errorText == 'No public key selected') {
|
||||
cy.reload;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
formatDate(date) {
|
||||
const padZero = (num) => num.toString().padStart(2, '0');
|
||||
|
||||
const year = date.getFullYear();
|
||||
const month = padZero(date.getMonth() + 1);
|
||||
const day = padZero(date.getDate());
|
||||
const hours = padZero(date.getHours());
|
||||
const minutes = padZero(date.getMinutes());
|
||||
|
||||
return `${year}-${month}-${day}T${hours}:${minutes}`;
|
||||
}
|
||||
}
|
54
apps/trading-e2e/src/support/pages/markets-page.js
Normal file
54
apps/trading-e2e/src/support/pages/markets-page.js
Normal file
@ -0,0 +1,54 @@
|
||||
import BasePage from './base-page';
|
||||
|
||||
export default class MarketPage extends BasePage {
|
||||
marketRow = 'market-row';
|
||||
chartTab = 'chart';
|
||||
ticketTab = 'ticket';
|
||||
orderbookTab = 'orderbook';
|
||||
ordersTab = 'orders';
|
||||
positionsTab = 'positions';
|
||||
collateralTab = 'collateral';
|
||||
tradesTab = 'trades';
|
||||
completedTrades = 'market-trades';
|
||||
orderBookTab = 'orderbook';
|
||||
|
||||
validateMarketsAreDisplayed() {
|
||||
cy.getByTestId(this.marketRow).should('have.length.above', 0);
|
||||
}
|
||||
|
||||
validateCompletedTradesDisplayed() {
|
||||
cy.getByTestId(this.completedTrades).should('not.be.empty');
|
||||
}
|
||||
|
||||
clickOnMarket(marketText) {
|
||||
cy.contains(marketText).click();
|
||||
}
|
||||
|
||||
clickOnActiveMarket() {
|
||||
cy.contains('Active', { timeout: 8000 }).click({ force: true });
|
||||
}
|
||||
|
||||
clickOnTopMarketRow() {
|
||||
cy.getByTestId(this.marketRow).first().click();
|
||||
}
|
||||
|
||||
clickOnOrdersTab() {
|
||||
cy.getByTestId(this.ordersTab).click();
|
||||
}
|
||||
|
||||
clickOnTicketTab() {
|
||||
cy.getByTestId(this.ticketTab).click();
|
||||
}
|
||||
|
||||
clickOnCollateralTab() {
|
||||
cy.getByTestId(this.collateralTab).click();
|
||||
}
|
||||
|
||||
clickOnTradesTab() {
|
||||
cy.getByTestId(this.tradesTab).click();
|
||||
}
|
||||
|
||||
clickOrderBookTab() {
|
||||
cy.getByTestId(this.orderBookTab).click();
|
||||
}
|
||||
}
|
27
apps/trading-e2e/src/support/step_definitions/common-step.js
Normal file
27
apps/trading-e2e/src/support/step_definitions/common-step.js
Normal file
@ -0,0 +1,27 @@
|
||||
import { Given, Then, When } from 'cypress-cucumber-preprocessor/steps';
|
||||
import MarketsPage from '../pages/markets-page';
|
||||
import DealTicketPage from '../pages/deal-ticket-page';
|
||||
const marketsPage = new MarketsPage();
|
||||
const dealTicketPage = new DealTicketPage();
|
||||
|
||||
Given('I am on the homepage', () => {
|
||||
cy.visit('/');
|
||||
});
|
||||
|
||||
Given('I navigate to markets page', () => {
|
||||
marketsPage.navigateToMarkets();
|
||||
});
|
||||
|
||||
Given('I navigate to portfolio page', () => {
|
||||
marketsPage.navigateToPortfolio();
|
||||
});
|
||||
|
||||
When('I connect to Vega Wallet', () => {
|
||||
marketsPage.navigateToConnectVegaWallet();
|
||||
marketsPage.fillInWalletForm(
|
||||
'UI_Trading_Test',
|
||||
Cypress.env('tradingWalletPassphrase')
|
||||
);
|
||||
marketsPage.clickConnectVegaWallet();
|
||||
dealTicketPage.reloadPageIfPublicKeyErrorDisplayed();
|
||||
});
|
@ -0,0 +1,22 @@
|
||||
import { Given, Then, When } from 'cypress-cucumber-preprocessor/steps';
|
||||
import MarketsPage from '../pages/markets-page';
|
||||
const marketsPage = new MarketsPage();
|
||||
|
||||
When('I try to connect Vega wallet with incorrect details', () => {
|
||||
marketsPage.navigateToConnectVegaWallet();
|
||||
marketsPage.fillInWalletForm('name', 'wrong passphrase');
|
||||
marketsPage.clickConnectVegaWallet();
|
||||
});
|
||||
|
||||
When('I try to connect Vega wallet with blank fields', () => {
|
||||
marketsPage.navigateToConnectVegaWallet();
|
||||
marketsPage.clickConnectVegaWallet();
|
||||
});
|
||||
|
||||
Then('wallet not running error message is displayed', () => {
|
||||
marketsPage.validateWalletNotRunningError();
|
||||
});
|
||||
|
||||
Then('wallet field validation errors are shown', () => {
|
||||
marketsPage.validateWalletErrorFieldsDisplayed();
|
||||
});
|
@ -0,0 +1,65 @@
|
||||
import { Given, Then, When } from 'cypress-cucumber-preprocessor/steps';
|
||||
import MarketsPage from '../pages/markets-page';
|
||||
import DealTicketPage from '../pages/deal-ticket-page';
|
||||
const marketsPage = new MarketsPage();
|
||||
const dealTicketPage = new DealTicketPage();
|
||||
|
||||
When('I click on market for {string}', (marketText) => {
|
||||
marketsPage.clickOnMarket(marketText);
|
||||
});
|
||||
|
||||
When('I click on active market', () => {
|
||||
marketsPage.clickOnMarket('Active');
|
||||
});
|
||||
|
||||
When('place a buy {string} market order', (orderType) => {
|
||||
dealTicketPage.placeMarketOrder(true, 100, orderType);
|
||||
dealTicketPage.clickPlaceOrder();
|
||||
});
|
||||
|
||||
When('place a sell {string} market order', (orderType) => {
|
||||
dealTicketPage.placeMarketOrder(false, 100, orderType);
|
||||
dealTicketPage.clickPlaceOrder();
|
||||
});
|
||||
|
||||
When('place a buy {string} limit order', (limitOrderType) => {
|
||||
dealTicketPage.placeLimitOrder(true, 100, 2000, limitOrderType);
|
||||
dealTicketPage.clickPlaceOrder();
|
||||
});
|
||||
|
||||
When('place a sell {string} limit order', (limitOrderType) => {
|
||||
dealTicketPage.placeLimitOrder(false, 100, 2000, limitOrderType);
|
||||
dealTicketPage.clickPlaceOrder();
|
||||
});
|
||||
|
||||
When('place a buy {string} market order with amount of 0', (orderType) => {
|
||||
dealTicketPage.placeMarketOrder(true, 0, orderType);
|
||||
dealTicketPage.clickPlaceOrder();
|
||||
});
|
||||
|
||||
When('I click on suspended market', () => {
|
||||
marketsPage.clickOnMarket('Suspended');
|
||||
});
|
||||
|
||||
Then('order request is sent', () => {
|
||||
dealTicketPage.verifyOrderRequestSent();
|
||||
});
|
||||
|
||||
Then('error message for insufficient funds is displayed', () => {
|
||||
dealTicketPage.verifyOrderFailedInsufficientFunds();
|
||||
});
|
||||
|
||||
Then('place order button is disabled', () => {
|
||||
dealTicketPage.verifyPlaceOrderBtnDisabled();
|
||||
});
|
||||
|
||||
Then('{string} error is shown', (errorMsg) => {
|
||||
dealTicketPage.verifySubmitBtnErrorText(errorMsg);
|
||||
});
|
||||
|
||||
Then(
|
||||
'Order rejected by wallet error shown containing text {string}',
|
||||
(expectedError) => {
|
||||
dealTicketPage.verifyOrderRejected(expectedError);
|
||||
}
|
||||
);
|
@ -27,6 +27,7 @@ export const VegaWalletConnectButton = ({
|
||||
<span className="text-ui-small font-mono mr-2">Vega key:</span>
|
||||
)}
|
||||
<button
|
||||
data-testid="connect-vega-wallet"
|
||||
onClick={handleClick}
|
||||
className="ml-auto inline-block text-ui-small font-mono hover:underline"
|
||||
>
|
||||
|
@ -53,7 +53,11 @@ export const GridTabs = ({ children, group }: GridTabsProps) => {
|
||||
'bg-black-10 dark:bg-white-10': !isActive,
|
||||
});
|
||||
return (
|
||||
<Tabs.Trigger value={child.props.id} className={triggerClass}>
|
||||
<Tabs.Trigger
|
||||
data-testid={child.props.name}
|
||||
value={child.props.id}
|
||||
className={triggerClass}
|
||||
>
|
||||
{child.props.name}
|
||||
</Tabs.Trigger>
|
||||
);
|
||||
|
@ -156,6 +156,7 @@ export const TradePanels = ({ market }: TradePanelsProps) => {
|
||||
});
|
||||
return (
|
||||
<button
|
||||
data-testid={key}
|
||||
onClick={() => setView(key as TradingView)}
|
||||
className={className}
|
||||
key={key}
|
||||
|
@ -14,6 +14,7 @@ export const ExpirySelector = ({ order, onSelect }: ExpirySelectorProps) => {
|
||||
return (
|
||||
<FormGroup label="Expiry time/date" labelFor="expiration">
|
||||
<Input
|
||||
data-testid="date-picker-field"
|
||||
id="expiration"
|
||||
name="expiration"
|
||||
type="datetime-local"
|
||||
|
@ -40,7 +40,9 @@ export const OrderDialog = ({
|
||||
icon={<Loader />}
|
||||
>
|
||||
{transaction.hash && (
|
||||
<p className="break-all">{t(`Tx hash: ${transaction.hash}`)}</p>
|
||||
<p data-testid="tx-hash" className="break-all">
|
||||
{t(`Tx hash: ${transaction.hash}`)}
|
||||
</p>
|
||||
)}
|
||||
</OrderDialogWrapper>
|
||||
);
|
||||
@ -53,7 +55,9 @@ export const OrderDialog = ({
|
||||
title="Order failed"
|
||||
icon={<Icon name="warning-sign" size={20} />}
|
||||
>
|
||||
<p>{t(`Reason: ${finalizedOrder.rejectionReason}`)}</p>
|
||||
<p data-testid="error-reason">
|
||||
{t(`Reason: ${finalizedOrder.rejectionReason}`)}
|
||||
</p>
|
||||
</OrderDialogWrapper>
|
||||
);
|
||||
}
|
||||
@ -97,8 +101,10 @@ const OrderDialogWrapper = ({
|
||||
return (
|
||||
<div className="flex gap-12 max-w-full">
|
||||
<div className="pt-8 fill-current">{icon}</div>
|
||||
<div className="flex-1">
|
||||
<h1 className="text-h4">{title}</h1>
|
||||
<div data-testid="order-wrapper" className="flex-1">
|
||||
<h1 data-testid="order-status-header" className="text-h4">
|
||||
{title}
|
||||
</h1>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -75,6 +75,7 @@ export const SubmitButton = ({
|
||||
variant="primary"
|
||||
type="submit"
|
||||
disabled={disabled}
|
||||
data-testid="place-order"
|
||||
>
|
||||
{transactionStatus === 'pending' ? t('Pending...') : t('Place order')}
|
||||
</Button>
|
||||
|
@ -35,7 +35,11 @@ export const InputError = ({
|
||||
'fill-intent-warning': intent === 'warning',
|
||||
});
|
||||
return (
|
||||
<div className={effectiveClassName} {...props}>
|
||||
<div
|
||||
data-testid="input-error-text"
|
||||
className={effectiveClassName}
|
||||
{...props}
|
||||
>
|
||||
<Icon name="warning-sign" className={iconClassName} />
|
||||
{children}
|
||||
</div>
|
||||
|
@ -60,7 +60,11 @@ export function RestConnectorForm({
|
||||
autoFocus={true}
|
||||
/>
|
||||
{errors.wallet?.message && (
|
||||
<InputError intent="danger" className="mt-4">
|
||||
<InputError
|
||||
data-testid="input-wallet-error"
|
||||
intent="danger"
|
||||
className="mt-4"
|
||||
>
|
||||
{errors.wallet.message}
|
||||
</InputError>
|
||||
)}
|
||||
|
Loading…
Reference in New Issue
Block a user