Task/229 Stub api in trading e2e (#211)
* add fixture for markets query * stub graphql requests * re-add assertion for tx hash, stub command/sync requests * refactor to get tests to run with trading page mocked queries * add test wallet credentials * split up markets page from trading page * add portfolio page feature, add market page scenarios * move hasOperationName helper to support/index * fix home-page.feature * fix missing feature step * Minor changes to BDD steps * Use in object syntax to get better type safety on hasOperationName helper function * remove bypass placing orders env var and usage in tests * use UI_Trading_Test wallet publick key in command/sync mock * move public key to cypress env * replace fixtures with generator functions * colocate query generators with queries * add custom commands, add index files * fix dodgy merge, remove duplicate market page feature * make tsconfig for cypress lib match * update tsconfig for explorer e2e so commands using merge work * revert trading step to js Co-authored-by: Joe <joe@vega.xyz>
This commit is contained in:
parent
3db9546266
commit
04872522d6
@ -3,8 +3,16 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"sourceMap": false,
|
"sourceMap": false,
|
||||||
"outDir": "../../dist/out-tsc",
|
"outDir": "../../dist/out-tsc",
|
||||||
|
"types": ["cypress", "node"],
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"types": ["cypress", "node"]
|
"esModuleInterop": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"strict": true,
|
||||||
|
"noImplicitOverride": true,
|
||||||
|
"noPropertyAccessFromIndexSignature": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noFallthroughCasesInSwitch": true
|
||||||
},
|
},
|
||||||
"include": ["src/**/*.ts", "src/**/*.js"]
|
"include": ["src/**/*.ts", "src/**/*.js"]
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
"chromeWebSecurity": false,
|
"chromeWebSecurity": false,
|
||||||
"projectId": "et4snf",
|
"projectId": "et4snf",
|
||||||
"env": {
|
"env": {
|
||||||
"bypassPlacingOrders": true,
|
"vegaPublicKey": "47836c253520d2661bf5bed6339c0de08fd02cf5d4db0efee3b4373f20c7d278",
|
||||||
"tsConfig": "tsconfig.json",
|
"tsConfig": "tsconfig.json",
|
||||||
"TAGS": "not @todo and not @ignore and not @manual"
|
"TAGS": "not @todo and not @ignore and not @manual"
|
||||||
}
|
}
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Using fixtures to represent data",
|
|
||||||
"email": "hello@cypress.io"
|
|
||||||
}
|
|
@ -1,11 +1,8 @@
|
|||||||
Feature: Market orders
|
Feature: Deal ticket
|
||||||
|
|
||||||
Scenario Outline: Successfull market buy orders
|
Scenario Outline: Successfull market buy orders
|
||||||
Given I am on the homepage
|
Given I am on the trading page for an active market
|
||||||
And I navigate to markets page
|
|
||||||
When I click on active market
|
|
||||||
And I connect to Vega Wallet
|
And I connect to Vega Wallet
|
||||||
And place a buy '<marketOrderType>' market order
|
When I place a buy '<marketOrderType>' market order
|
||||||
Then order request is sent
|
Then order request is sent
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
@ -14,11 +11,9 @@ Feature: Market orders
|
|||||||
| IOC |
|
| IOC |
|
||||||
|
|
||||||
Scenario Outline: Successfull Limit buy orders
|
Scenario Outline: Successfull Limit buy orders
|
||||||
Given I am on the homepage
|
Given I am on the trading page for an active market
|
||||||
And I navigate to markets page
|
|
||||||
When I click on active market
|
|
||||||
And I connect to Vega Wallet
|
And I connect to Vega Wallet
|
||||||
And place a buy '<limitOrderType>' limit order
|
When I place a buy '<limitOrderType>' limit order
|
||||||
Then order request is sent
|
Then order request is sent
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
@ -30,11 +25,9 @@ Feature: Market orders
|
|||||||
| GFN |
|
| GFN |
|
||||||
|
|
||||||
Scenario Outline: Successfull market sell order
|
Scenario Outline: Successfull market sell order
|
||||||
Given I am on the homepage
|
Given I am on the trading page for an active market
|
||||||
And I navigate to markets page
|
|
||||||
When I click on active market
|
|
||||||
And I connect to Vega Wallet
|
And I connect to Vega Wallet
|
||||||
And place a sell '<marketOrderType>' market order
|
When I place a sell '<marketOrderType>' market order
|
||||||
Then order request is sent
|
Then order request is sent
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
@ -43,11 +36,10 @@ Feature: Market orders
|
|||||||
| IOC |
|
| IOC |
|
||||||
|
|
||||||
Scenario Outline: Successfull limit sell order
|
Scenario Outline: Successfull limit sell order
|
||||||
Given I am on the homepage
|
Given I am on the trading page for an active market
|
||||||
And I navigate to markets page
|
|
||||||
When I click on active market
|
|
||||||
And I connect to Vega Wallet
|
And I connect to Vega Wallet
|
||||||
And place a sell '<limitOrderType>' limit order
|
When I place a sell '<limitOrderType>' limit order
|
||||||
|
Then order request is sent
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
| limitOrderType |
|
| limitOrderType |
|
||||||
@ -66,27 +58,20 @@ Feature: Market orders
|
|||||||
And place a buy 'FOK' market order
|
And place a buy 'FOK' market order
|
||||||
Then error message for insufficient funds is displayed
|
Then error message for insufficient funds is displayed
|
||||||
|
|
||||||
@ignore
|
|
||||||
Scenario: Unable to order because market is suspended
|
Scenario: Unable to order because market is suspended
|
||||||
Given I am on the homepage
|
Given I am on the trading page for a suspended market
|
||||||
And I navigate to markets page
|
|
||||||
When I click on suspended market
|
|
||||||
And I connect to Vega Wallet
|
And I connect to Vega Wallet
|
||||||
Then place order button is disabled
|
Then place order button is disabled
|
||||||
And "Market is currently suspended" error is shown
|
And "Market is currently suspended" error is shown
|
||||||
|
|
||||||
Scenario: Unable to order because wallet is not connected
|
Scenario: Unable to order because wallet is not connected
|
||||||
Given I am on the homepage
|
Given I am on the trading page for an active market
|
||||||
And I navigate to markets page
|
|
||||||
When I click on active market
|
|
||||||
Then place order button is disabled
|
Then place order button is disabled
|
||||||
And "No public key selected" error is shown
|
And "No public key selected" error is shown
|
||||||
|
|
||||||
@ignore
|
@ignore
|
||||||
Scenario: Unsuccessfull because quantity is 0
|
Scenario: Unsuccessfull because quantity is 0
|
||||||
Given I am on the homepage
|
Given I am on the trading page for an active market
|
||||||
And I navigate to markets page
|
|
||||||
When I click on active market
|
|
||||||
And I connect to Vega Wallet
|
And I connect to Vega Wallet
|
||||||
And place a buy 'FOK' market order with amount of 0
|
And place a buy 'FOK' market order with amount of 0
|
||||||
Then Order rejected by wallet error shown containing text "must be positive"
|
Then Order rejected by wallet error shown containing text "must be positive"
|
@ -7,6 +7,10 @@ Feature: Home page
|
|||||||
Given I am on the homepage
|
Given I am on the homepage
|
||||||
And I navigate to portfolio page
|
And I navigate to portfolio page
|
||||||
|
|
||||||
|
Scenario: Visit Markets page
|
||||||
|
Given I am on the homepage
|
||||||
|
And I navigate to markets page
|
||||||
|
|
||||||
Scenario: Unable to connect Vega wallet with incorrect credentials
|
Scenario: Unable to connect Vega wallet with incorrect credentials
|
||||||
Given I am on the homepage
|
Given I am on the homepage
|
||||||
When I try to connect Vega wallet with incorrect details
|
When I try to connect Vega wallet with incorrect details
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
Feature: Market Page
|
|
||||||
|
|
||||||
Scenario: Market table displayed on market page
|
|
||||||
Given I am on the homepage
|
|
||||||
And I navigate to markets page
|
|
||||||
Then the market table is displayed
|
|
17
apps/trading-e2e/src/integration/markets-page.feature
Normal file
17
apps/trading-e2e/src/integration/markets-page.feature
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
Feature: Markets page
|
||||||
|
|
||||||
|
Scenario: Navigation
|
||||||
|
Given I am on the homepage
|
||||||
|
When I navigate to markets page
|
||||||
|
Then I can view markets
|
||||||
|
And the market table is displayed
|
||||||
|
|
||||||
|
Scenario: Select active market
|
||||||
|
Given I am on the markets page
|
||||||
|
When I click on an active market
|
||||||
|
Then I am on the trading page for an active market
|
||||||
|
|
||||||
|
Scenario: Select suspended market
|
||||||
|
Given I am on the markets page
|
||||||
|
When I click on a suspended market
|
||||||
|
Then I am on the trading page for a suspended market
|
5
apps/trading-e2e/src/integration/portfolio-page.feature
Normal file
5
apps/trading-e2e/src/integration/portfolio-page.feature
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
Feature: Portfolio page
|
||||||
|
Scenario: Navigation
|
||||||
|
Given I am on the homepage
|
||||||
|
Then I navigate to portfolio page
|
@ -1 +0,0 @@
|
|||||||
export const getGreeting = () => cy.get('h1');
|
|
@ -1,17 +1,11 @@
|
|||||||
// ***********************************************************
|
|
||||||
// This example support/index.js is processed and
|
|
||||||
// loaded automatically before your test files.
|
|
||||||
//
|
|
||||||
// This is a great place to put global configuration and
|
|
||||||
// behavior that modifies Cypress.
|
|
||||||
//
|
|
||||||
// You can change the location of this file or turn off
|
|
||||||
// automatically serving support files with the
|
|
||||||
// 'supportFile' configuration option.
|
|
||||||
//
|
|
||||||
// You can read more here:
|
|
||||||
// https://on.cypress.io/configuration
|
|
||||||
// ***********************************************************
|
|
||||||
|
|
||||||
// Import commands.js using ES2015 syntax:
|
|
||||||
import '@vegaprotocol/cypress';
|
import '@vegaprotocol/cypress';
|
||||||
|
import type { CyHttpMessages } from 'cypress/types/net-stubbing';
|
||||||
|
|
||||||
|
// Utility to match GraphQL mutation based on the operation name
|
||||||
|
export const hasOperationName = (
|
||||||
|
req: CyHttpMessages.IncomingHttpRequest,
|
||||||
|
operationName: string
|
||||||
|
) => {
|
||||||
|
const { body } = req;
|
||||||
|
return 'operationName' in body && body.operationName === operationName;
|
||||||
|
};
|
||||||
|
@ -1,56 +1,16 @@
|
|||||||
export default class BasePage {
|
export default class BasePage {
|
||||||
porfolioUrl = '/portfolio';
|
porfolioUrl = '/portfolio';
|
||||||
marketsUrl = '/markets';
|
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() {
|
navigateToPortfolio() {
|
||||||
cy.get(`a[href='${this.porfolioUrl}']`).click();
|
cy.get(`a[href='${this.porfolioUrl}']`).should('be.visible').click();
|
||||||
|
cy.url().should('include', '/portfolio');
|
||||||
|
cy.getByTestId('portfolio');
|
||||||
}
|
}
|
||||||
|
|
||||||
navigateToMarkets() {
|
navigateToMarkets() {
|
||||||
cy.get(`a[href='${this.marketsUrl}']`)
|
cy.get(`a[href='${this.marketsUrl}']`).should('be.visible').click();
|
||||||
.should('be.visible')
|
|
||||||
.click({ force: true });
|
|
||||||
cy.url().should('include', '/markets');
|
cy.url().should('include', '/markets');
|
||||||
}
|
cy.getByTestId('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');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,15 +7,10 @@ export default class MarketPage extends BasePage {
|
|||||||
'tradableInstrument.instrument.product.settlementAsset.symbol';
|
'tradableInstrument.instrument.product.settlementAsset.symbol';
|
||||||
marketRowPrices = 'flash-cell';
|
marketRowPrices = 'flash-cell';
|
||||||
marketRowDescription = 'name';
|
marketRowDescription = 'name';
|
||||||
chartTab = 'chart';
|
|
||||||
ticketTab = 'ticket';
|
validateMarketsAreDisplayed() {
|
||||||
orderbookTab = 'orderbook';
|
cy.get('.ag-root-wrapper').should('be.visible');
|
||||||
ordersTab = 'orders';
|
}
|
||||||
positionsTab = 'positions';
|
|
||||||
collateralTab = 'collateral';
|
|
||||||
tradesTab = 'trades';
|
|
||||||
completedTrades = 'market-trades';
|
|
||||||
orderBookTab = 'orderbook';
|
|
||||||
|
|
||||||
validateMarketTableDisplayed() {
|
validateMarketTableDisplayed() {
|
||||||
const expectedMarketHeaders = [
|
const expectedMarketHeaders = [
|
||||||
@ -58,39 +53,7 @@ export default class MarketPage extends BasePage {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
validateCompletedTradesDisplayed() {
|
clickOnMarket(text) {
|
||||||
cy.getByTestId(this.completedTrades).should('not.be.empty');
|
cy.contains(text).click();
|
||||||
}
|
|
||||||
|
|
||||||
clickOnMarket(marketText) {
|
|
||||||
cy.contains(marketText).click();
|
|
||||||
}
|
|
||||||
|
|
||||||
clickOnActiveMarket() {
|
|
||||||
cy.contains('Active', { timeout: 8000 }).click({ force: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
clickOnTopMarketRow() {
|
|
||||||
cy.get('[col-id="data"]').eq(1).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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
3
apps/trading-e2e/src/support/pages/portfolio-page.js
Normal file
3
apps/trading-e2e/src/support/pages/portfolio-page.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import BasePage from './base-page';
|
||||||
|
|
||||||
|
export default class PortfolioPage extends BasePage {}
|
33
apps/trading-e2e/src/support/pages/trading-page.js
Normal file
33
apps/trading-e2e/src/support/pages/trading-page.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import BasePage from './base-page';
|
||||||
|
|
||||||
|
export default class TradingPage extends BasePage {
|
||||||
|
chartTab = 'chart';
|
||||||
|
ticketTab = 'ticket';
|
||||||
|
orderbookTab = 'orderbook';
|
||||||
|
ordersTab = 'orders';
|
||||||
|
positionsTab = 'positions';
|
||||||
|
collateralTab = 'collateral';
|
||||||
|
tradesTab = 'trades';
|
||||||
|
completedTrades = 'market-trades';
|
||||||
|
orderBookTab = 'orderbook';
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
@ -1,27 +0,0 @@
|
|||||||
import { Given, 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,5 @@
|
|||||||
|
import { Given } from 'cypress-cucumber-preprocessor/steps';
|
||||||
|
|
||||||
|
Given('I am on the homepage', () => {
|
||||||
|
cy.visit('/');
|
||||||
|
});
|
@ -0,0 +1,52 @@
|
|||||||
|
import { Then, When } from 'cypress-cucumber-preprocessor/steps';
|
||||||
|
import DealTicket from '../trading-windows/deal-ticket';
|
||||||
|
|
||||||
|
const dealTicket = new DealTicket();
|
||||||
|
|
||||||
|
When('I place a buy {string} market order', (orderType) => {
|
||||||
|
dealTicket.placeMarketOrder(true, 100, orderType);
|
||||||
|
dealTicket.clickPlaceOrder();
|
||||||
|
});
|
||||||
|
|
||||||
|
When('I place a sell {string} market order', (orderType) => {
|
||||||
|
dealTicket.placeMarketOrder(false, 100, orderType);
|
||||||
|
dealTicket.clickPlaceOrder();
|
||||||
|
});
|
||||||
|
|
||||||
|
When('I place a buy {string} limit order', (limitOrderType) => {
|
||||||
|
dealTicket.placeLimitOrder(true, 100, 2000, limitOrderType);
|
||||||
|
dealTicket.clickPlaceOrder();
|
||||||
|
});
|
||||||
|
|
||||||
|
When('I place a sell {string} limit order', (limitOrderType) => {
|
||||||
|
dealTicket.placeLimitOrder(false, 100, 2000, limitOrderType);
|
||||||
|
dealTicket.clickPlaceOrder();
|
||||||
|
});
|
||||||
|
|
||||||
|
When('I place a buy {string} market order with amount of 0', (orderType) => {
|
||||||
|
dealTicket.placeMarketOrder(true, 0, orderType);
|
||||||
|
dealTicket.clickPlaceOrder();
|
||||||
|
});
|
||||||
|
|
||||||
|
Then('order request is sent', () => {
|
||||||
|
dealTicket.verifyOrderRequestSent();
|
||||||
|
});
|
||||||
|
|
||||||
|
Then('error message for insufficient funds is displayed', () => {
|
||||||
|
dealTicket.verifyOrderFailedInsufficientFunds();
|
||||||
|
});
|
||||||
|
|
||||||
|
Then('place order button is disabled', () => {
|
||||||
|
dealTicket.verifyPlaceOrderBtnDisabled();
|
||||||
|
});
|
||||||
|
|
||||||
|
Then('{string} error is shown', (errorMsg) => {
|
||||||
|
dealTicket.verifySubmitBtnErrorText(errorMsg);
|
||||||
|
});
|
||||||
|
|
||||||
|
Then(
|
||||||
|
'Order rejected by wallet error shown containing text {string}',
|
||||||
|
(expectedError) => {
|
||||||
|
dealTicket.verifyOrderRejected(expectedError);
|
||||||
|
}
|
||||||
|
);
|
@ -1,22 +1,23 @@
|
|||||||
import { Then, When } from 'cypress-cucumber-preprocessor/steps';
|
import { Then, When } from 'cypress-cucumber-preprocessor/steps';
|
||||||
import MarketsPage from '../pages/markets-page';
|
import VegaWallet from '../vega-wallet';
|
||||||
const marketsPage = new MarketsPage();
|
|
||||||
|
const vegaWallet = new VegaWallet();
|
||||||
|
|
||||||
When('I try to connect Vega wallet with incorrect details', () => {
|
When('I try to connect Vega wallet with incorrect details', () => {
|
||||||
marketsPage.navigateToConnectVegaWallet();
|
vegaWallet.openVegaWalletConnectDialog();
|
||||||
marketsPage.fillInWalletForm('name', 'wrong passphrase');
|
vegaWallet.fillInWalletForm('name', 'wrong passphrase');
|
||||||
marketsPage.clickConnectVegaWallet();
|
vegaWallet.clickConnectVegaWallet();
|
||||||
});
|
});
|
||||||
|
|
||||||
When('I try to connect Vega wallet with blank fields', () => {
|
When('I try to connect Vega wallet with blank fields', () => {
|
||||||
marketsPage.navigateToConnectVegaWallet();
|
vegaWallet.openVegaWalletConnectDialog();
|
||||||
marketsPage.clickConnectVegaWallet();
|
vegaWallet.clickConnectVegaWallet();
|
||||||
});
|
});
|
||||||
|
|
||||||
Then('wallet not running error message is displayed', () => {
|
Then('wallet not running error message is displayed', () => {
|
||||||
marketsPage.validateWalletNotRunningError();
|
vegaWallet.validateWalletNotRunningError();
|
||||||
});
|
});
|
||||||
|
|
||||||
Then('wallet field validation errors are shown', () => {
|
Then('wallet field validation errors are shown', () => {
|
||||||
marketsPage.validateWalletErrorFieldsDisplayed();
|
vegaWallet.validateWalletErrorFieldsDisplayed();
|
||||||
});
|
});
|
||||||
|
@ -1,54 +0,0 @@
|
|||||||
import { Then, When } from 'cypress-cucumber-preprocessor/steps';
|
|
||||||
|
|
||||||
import DealTicketPage from '../pages/deal-ticket-page';
|
|
||||||
const dealTicketPage = new DealTicketPage();
|
|
||||||
|
|
||||||
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();
|
|
||||||
});
|
|
||||||
|
|
||||||
Then('order request is sent', () => {
|
|
||||||
if (Cypress.env('bypassPlacingOrders' != true)) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,23 +1,47 @@
|
|||||||
import { When, Then } from 'cypress-cucumber-preprocessor/steps';
|
import { And, Given, Then, When } from 'cypress-cucumber-preprocessor/steps';
|
||||||
|
import { hasOperationName } from '..';
|
||||||
import MarketsPage from '../pages/markets-page';
|
import MarketsPage from '../pages/markets-page';
|
||||||
|
// eslint-disable-next-line @nrwl/nx/enforce-module-boundaries
|
||||||
|
import { generateMarkets } from '../../../../../libs/market-list/src/__tests__/generate-markets';
|
||||||
|
|
||||||
const marketsPage = new MarketsPage();
|
const marketsPage = new MarketsPage();
|
||||||
|
|
||||||
When('I click on market for {string}', (marketText) => {
|
const mockMarkets = () => {
|
||||||
marketsPage.clickOnMarket(marketText);
|
cy.mockGQL('Markets', (req) => {
|
||||||
});
|
if (hasOperationName(req, 'Markets')) {
|
||||||
|
req.reply({
|
||||||
When('I click on active market', () => {
|
body: { data: generateMarkets() },
|
||||||
if (Cypress.env('bypassPlacingOrders' != true)) {
|
});
|
||||||
marketsPage.clickOnMarket('Active');
|
|
||||||
} else {
|
|
||||||
marketsPage.clickOnTopMarketRow();
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
mockMarkets();
|
||||||
});
|
});
|
||||||
|
|
||||||
When('I click on suspended market', () => {
|
Then('I navigate to markets page', () => {
|
||||||
marketsPage.clickOnMarket('Suspended');
|
marketsPage.navigateToMarkets();
|
||||||
});
|
});
|
||||||
|
|
||||||
Then('the market table is displayed', () => {
|
Given('I am on the markets page', () => {
|
||||||
|
cy.visit('/markets');
|
||||||
|
cy.wait('@Markets');
|
||||||
|
});
|
||||||
|
|
||||||
|
Then('I can view markets', () => {
|
||||||
|
cy.wait('@Markets');
|
||||||
|
marketsPage.validateMarketsAreDisplayed();
|
||||||
|
});
|
||||||
|
|
||||||
|
And('the market table is displayed', () => {
|
||||||
marketsPage.validateMarketTableDisplayed();
|
marketsPage.validateMarketTableDisplayed();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
When('I click on an active market', () => {
|
||||||
|
marketsPage.clickOnMarket('Active');
|
||||||
|
});
|
||||||
|
|
||||||
|
When('I click on a suspended market', () => {
|
||||||
|
marketsPage.clickOnMarket('Suspended');
|
||||||
|
});
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
import { Then } from 'cypress-cucumber-preprocessor/steps';
|
||||||
|
import PortfolioPage from '../pages/portfolio-page';
|
||||||
|
|
||||||
|
const portfolioPage = new PortfolioPage();
|
||||||
|
|
||||||
|
Then('I navigate to portfolio page', () => {
|
||||||
|
portfolioPage.navigateToPortfolio();
|
||||||
|
});
|
@ -0,0 +1,68 @@
|
|||||||
|
import { Given } from 'cypress-cucumber-preprocessor/steps';
|
||||||
|
import { hasOperationName } from '..';
|
||||||
|
import { MarketState } from '@vegaprotocol/types';
|
||||||
|
/* eslint-disable @nrwl/nx/enforce-module-boundaries */
|
||||||
|
import { generateTrades } from '../../../../../libs/trades/src/__tests__';
|
||||||
|
import {
|
||||||
|
generateChart,
|
||||||
|
generateCandles,
|
||||||
|
} from '../../../../../libs/chart/src/__tests__';
|
||||||
|
import { generateDealTicketQuery } from '../../../../../libs/deal-ticket/src/__tests__';
|
||||||
|
import { generateMarket } from '../../../../trading/pages/markets/__tests__';
|
||||||
|
/* eslint-enable @nrwl/nx/enforce-module-boundaries */
|
||||||
|
|
||||||
|
const mockMarket = (state) => {
|
||||||
|
cy.mockGQL('Market', (req) => {
|
||||||
|
if (hasOperationName(req, 'Market')) {
|
||||||
|
req.reply({
|
||||||
|
body: {
|
||||||
|
data: generateMarket({
|
||||||
|
market: {
|
||||||
|
name: `${state.toUpperCase()} MARKET`,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasOperationName(req, 'DealTicketQuery')) {
|
||||||
|
req.reply({
|
||||||
|
body: { data: generateDealTicketQuery({ market: { state } }) },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasOperationName(req, 'Trades')) {
|
||||||
|
req.reply({
|
||||||
|
body: { data: generateTrades() },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasOperationName(req, 'Chart')) {
|
||||||
|
req.reply({
|
||||||
|
body: { data: generateChart() },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasOperationName(req, 'Candles')) {
|
||||||
|
req.reply({
|
||||||
|
body: { data: generateCandles() },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Given('I am on the trading page for an active market', () => {
|
||||||
|
mockMarket(MarketState.Active);
|
||||||
|
|
||||||
|
cy.visit('/markets/market-id');
|
||||||
|
cy.wait('@Market');
|
||||||
|
cy.contains('Market: ACTIVE MARKET');
|
||||||
|
});
|
||||||
|
|
||||||
|
Given('I am on the trading page for a suspended market', () => {
|
||||||
|
mockMarket(MarketState.Suspended);
|
||||||
|
|
||||||
|
cy.visit('/markets/market-id');
|
||||||
|
cy.wait('@Market');
|
||||||
|
cy.contains('Market: SUSPENDED MARKET');
|
||||||
|
});
|
@ -0,0 +1,30 @@
|
|||||||
|
import { When } from 'cypress-cucumber-preprocessor/steps';
|
||||||
|
import VegaWallet from '../vega-wallet';
|
||||||
|
|
||||||
|
const vegaWallet = new VegaWallet();
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
// The two important values here are the signature.value and the From.Pubkey.
|
||||||
|
// From.PubKey is the first public key in the UI_Trading_Test wallet. We assert that the returned pubkey matches
|
||||||
|
// what is used to sign the transaction
|
||||||
|
// The tx.signature.value isn't currently used in any tests but the value returned is used to create IDs objects such
|
||||||
|
// as orders, if its invalid an erro will be thrown
|
||||||
|
cy.mockVegaCommandSync({
|
||||||
|
txHash: 'test-tx-hash',
|
||||||
|
tx: {
|
||||||
|
signature: {
|
||||||
|
value:
|
||||||
|
'd86138bba739bbc1069b3dc975d20b3a1517c2b9bdd401c70eeb1a0ecbc502ec268cf3129824841178b8b506b0b7d650c76644dbd96f524a6cb2158fb7121800',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
When('I connect to Vega Wallet', () => {
|
||||||
|
vegaWallet.openVegaWalletConnectDialog();
|
||||||
|
vegaWallet.fillInWalletForm(
|
||||||
|
'UI_Trading_Test',
|
||||||
|
Cypress.env('tradingWalletPassphrase')
|
||||||
|
);
|
||||||
|
vegaWallet.clickConnectVegaWallet();
|
||||||
|
});
|
@ -1,5 +1,4 @@
|
|||||||
import BasePage from './base-page';
|
export default class DealTicket {
|
||||||
export default class DealTicketPage extends BasePage {
|
|
||||||
marketOrderType = 'order-type-TYPE_MARKET';
|
marketOrderType = 'order-type-TYPE_MARKET';
|
||||||
limitOrderType = 'order-type-TYPE_LIMIT';
|
limitOrderType = 'order-type-TYPE_LIMIT';
|
||||||
buyOrder = 'order-side-SIDE_BUY';
|
buyOrder = 'order-side-SIDE_BUY';
|
||||||
@ -53,8 +52,7 @@ export default class DealTicketPage extends BasePage {
|
|||||||
);
|
);
|
||||||
cy.getByTestId(this.orderTransactionHash)
|
cy.getByTestId(this.orderTransactionHash)
|
||||||
.invoke('text')
|
.invoke('text')
|
||||||
.should('contain', 'Tx hash: ')
|
.should('contain', 'Tx hash: test-tx-hash');
|
||||||
.and('have.length.above', 64);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
verifyOrderFailedInsufficientFunds() {
|
verifyOrderFailedInsufficientFunds() {
|
||||||
@ -65,9 +63,8 @@ export default class DealTicketPage extends BasePage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clickPlaceOrder() {
|
clickPlaceOrder() {
|
||||||
if (Cypress.env('bypassPlacingOrders' != true)) {
|
|
||||||
cy.getByTestId(this.placeOrderBtn).click();
|
cy.getByTestId(this.placeOrderBtn).click();
|
||||||
}
|
cy.contains('Awaiting network confirmation');
|
||||||
}
|
}
|
||||||
|
|
||||||
verifyPlaceOrderBtnDisabled() {
|
verifyPlaceOrderBtnDisabled() {
|
||||||
@ -75,7 +72,10 @@ export default class DealTicketPage extends BasePage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
verifySubmitBtnErrorText(expectedText) {
|
verifySubmitBtnErrorText(expectedText) {
|
||||||
cy.getByTestId(this.inputError).should('have.text', expectedText);
|
cy.getByTestId('dealticket-error-message').should(
|
||||||
|
'have.text',
|
||||||
|
expectedText
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
verifyOrderRejected(errorMsg) {
|
verifyOrderRejected(errorMsg) {
|
43
apps/trading-e2e/src/support/vega-wallet/index.js
Normal file
43
apps/trading-e2e/src/support/vega-wallet/index.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
export default class VegaWallet {
|
||||||
|
connectVegaBtn = 'connect-vega-wallet';
|
||||||
|
walletConnectors = 'connectors-list';
|
||||||
|
walletForm = 'rest-connector-form';
|
||||||
|
walletInputError = 'input-wallet-error';
|
||||||
|
walletFormError = 'form-error';
|
||||||
|
inputError = 'input-error-text';
|
||||||
|
|
||||||
|
openVegaWalletConnectDialog() {
|
||||||
|
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');
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,15 @@
|
|||||||
"sourceMap": false,
|
"sourceMap": false,
|
||||||
"outDir": "../../dist/out-tsc",
|
"outDir": "../../dist/out-tsc",
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"types": ["cypress", "node"]
|
"types": ["cypress", "node"],
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"strict": true,
|
||||||
|
"noImplicitOverride": true,
|
||||||
|
"noPropertyAccessFromIndexSignature": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noFallthroughCasesInSwitch": true
|
||||||
},
|
},
|
||||||
"include": ["src/**/*.ts", "src/**/*.js"]
|
"include": ["src/**/*.ts", "src/**/*.js"]
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ function VegaTradingApp({ Component, pageProps }: AppProps) {
|
|||||||
<ThemeSwitcher onToggle={toggleTheme} className="-my-4" />
|
<ThemeSwitcher onToggle={toggleTheme} className="-my-4" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<main>
|
<main data-testid={pageProps.page}>
|
||||||
<Component {...pageProps} />
|
<Component {...pageProps} />
|
||||||
</main>
|
</main>
|
||||||
<VegaConnectDialog
|
<VegaConnectDialog
|
||||||
|
@ -22,4 +22,8 @@ export function Index() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Index.getInitialProps = () => ({
|
||||||
|
page: 'home',
|
||||||
|
});
|
||||||
|
|
||||||
export default Index;
|
export default Index;
|
||||||
|
@ -60,6 +60,10 @@ const MarketPage = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
MarketPage.getInitialProps = () => ({
|
||||||
|
page: 'market',
|
||||||
|
});
|
||||||
|
|
||||||
export default MarketPage;
|
export default MarketPage;
|
||||||
|
|
||||||
const useWindowSize = () => {
|
const useWindowSize = () => {
|
||||||
|
15
apps/trading/pages/markets/__tests__/generate-market.ts
Normal file
15
apps/trading/pages/markets/__tests__/generate-market.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import merge from 'lodash/merge';
|
||||||
|
import type { PartialDeep } from 'type-fest';
|
||||||
|
import type { Market } from '../__generated__/Market';
|
||||||
|
|
||||||
|
export const generateMarket = (override?: PartialDeep<Market>): Market => {
|
||||||
|
const defaultResult = {
|
||||||
|
market: {
|
||||||
|
id: 'market-id',
|
||||||
|
name: 'MARKET NAME',
|
||||||
|
__typename: 'Market',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return merge(defaultResult, override);
|
||||||
|
};
|
1
apps/trading/pages/markets/__tests__/index.ts
Normal file
1
apps/trading/pages/markets/__tests__/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './generate-market';
|
@ -4,4 +4,8 @@ const Markets = () => {
|
|||||||
return <MarketsContainer />;
|
return <MarketsContainer />;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Markets.getInitialProps = () => ({
|
||||||
|
page: 'markets',
|
||||||
|
});
|
||||||
|
|
||||||
export default Markets;
|
export default Markets;
|
||||||
|
@ -31,4 +31,8 @@ const Deposit = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Deposit.getInitialProps = () => ({
|
||||||
|
page: 'deposit',
|
||||||
|
});
|
||||||
|
|
||||||
export default Deposit;
|
export default Deposit;
|
||||||
|
@ -5,8 +5,8 @@ import { useVegaWallet } from '@vegaprotocol/wallet';
|
|||||||
const Portfolio = () => {
|
const Portfolio = () => {
|
||||||
const { keypair } = useVegaWallet();
|
const { keypair } = useVegaWallet();
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className="p-24">
|
||||||
<h1>{t('Portfolio')}</h1>
|
<h1 className="text-h3 mb-12">{t('Portfolio')}</h1>
|
||||||
{keypair && <p>{t(`Keypair: ${keypair.name} ${keypair.pub}`)}</p>}
|
{keypair && <p>{t(`Keypair: ${keypair.name} ${keypair.pub}`)}</p>}
|
||||||
<div className="flex gap-4">
|
<div className="flex gap-4">
|
||||||
<AnchorButton href="/portfolio/deposit">{t('Deposit')}</AnchorButton>
|
<AnchorButton href="/portfolio/deposit">{t('Deposit')}</AnchorButton>
|
||||||
@ -18,4 +18,8 @@ const Portfolio = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Portfolio.getInitialProps = () => ({
|
||||||
|
page: 'portfolio',
|
||||||
|
});
|
||||||
|
|
||||||
export default Portfolio;
|
export default Portfolio;
|
||||||
|
56
libs/chart/src/__tests__/generate-candles.ts
Normal file
56
libs/chart/src/__tests__/generate-candles.ts
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import merge from 'lodash/merge';
|
||||||
|
import type { PartialDeep } from 'type-fest';
|
||||||
|
import type {
|
||||||
|
Candles,
|
||||||
|
Candles_market_candles,
|
||||||
|
} from '../lib/__generated__/Candles';
|
||||||
|
|
||||||
|
export const generateCandles = (override?: PartialDeep<Candles>): Candles => {
|
||||||
|
const candles: Candles_market_candles[] = [
|
||||||
|
{
|
||||||
|
datetime: '2022-04-06T09:15:00Z',
|
||||||
|
high: '17481092',
|
||||||
|
low: '17403651',
|
||||||
|
open: '17458833',
|
||||||
|
close: '17446470',
|
||||||
|
volume: '82721',
|
||||||
|
__typename: 'Candle',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
datetime: '2022-04-06T09:30:00Z',
|
||||||
|
high: '17491202',
|
||||||
|
low: '17361138',
|
||||||
|
open: '17446470',
|
||||||
|
close: '17367174',
|
||||||
|
volume: '62637',
|
||||||
|
__typename: 'Candle',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
datetime: '2022-04-06T09:45:00Z',
|
||||||
|
high: '17424522',
|
||||||
|
low: '17337719',
|
||||||
|
open: '17367174',
|
||||||
|
close: '17376455',
|
||||||
|
volume: '60259',
|
||||||
|
__typename: 'Candle',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const defaultResult = {
|
||||||
|
market: {
|
||||||
|
id: 'market-id',
|
||||||
|
decimalPlaces: 5,
|
||||||
|
tradableInstrument: {
|
||||||
|
instrument: {
|
||||||
|
id: '',
|
||||||
|
name: 'Apple Monthly (30 Jun 2022)',
|
||||||
|
code: 'AAPL.MF21',
|
||||||
|
__typename: 'Instrument',
|
||||||
|
},
|
||||||
|
__typename: 'TradableInstrument',
|
||||||
|
},
|
||||||
|
candles,
|
||||||
|
__typename: 'Market',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return merge(defaultResult, override);
|
||||||
|
};
|
27
libs/chart/src/__tests__/generate-chart.ts
Normal file
27
libs/chart/src/__tests__/generate-chart.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import merge from 'lodash/merge';
|
||||||
|
import type { PartialDeep } from 'type-fest';
|
||||||
|
import type {
|
||||||
|
Chart,
|
||||||
|
Chart_market_data_priceMonitoringBounds,
|
||||||
|
} from '../lib/__generated__/Chart';
|
||||||
|
|
||||||
|
export const generateChart = (override?: PartialDeep<Chart>): Chart => {
|
||||||
|
const priceMonitoringBound: Chart_market_data_priceMonitoringBounds = {
|
||||||
|
minValidPrice: '16256291',
|
||||||
|
maxValidPrice: '18296869',
|
||||||
|
referencePrice: '17247489',
|
||||||
|
__typename: 'PriceMonitoringBounds',
|
||||||
|
};
|
||||||
|
const defaultResult = {
|
||||||
|
market: {
|
||||||
|
decimalPlaces: 5,
|
||||||
|
data: {
|
||||||
|
priceMonitoringBounds: [priceMonitoringBound],
|
||||||
|
__typename: 'MarketData',
|
||||||
|
},
|
||||||
|
__typename: 'Market',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return merge(defaultResult, override);
|
||||||
|
};
|
2
libs/chart/src/__tests__/index.ts
Normal file
2
libs/chart/src/__tests__/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './generate-candles';
|
||||||
|
export * from './generate-chart';
|
@ -1,5 +1,9 @@
|
|||||||
import { addGetTestIdcommand } from './lib/commands/get-by-test-id';
|
import { addGetTestIdcommand } from './lib/commands/get-by-test-id';
|
||||||
|
import { addMockGQLCommand } from './lib/commands/mock-gql';
|
||||||
|
import { addMockVegaWalletCommands } from './lib/commands/mock-vega-wallet';
|
||||||
import { addSlackCommand } from './lib/commands/slack';
|
import { addSlackCommand } from './lib/commands/slack';
|
||||||
|
|
||||||
addGetTestIdcommand();
|
addGetTestIdcommand();
|
||||||
addSlackCommand();
|
addSlackCommand();
|
||||||
|
addMockGQLCommand();
|
||||||
|
addMockVegaWalletCommands();
|
||||||
|
21
libs/cypress/src/lib/commands/mock-gql.ts
Normal file
21
libs/cypress/src/lib/commands/mock-gql.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import type { RouteHandler } from 'cypress/types/net-stubbing';
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||||
|
declare namespace Cypress {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
interface Chainable<Subject> {
|
||||||
|
mockGQL(alias: string, handler: RouteHandler): void;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addMockGQLCommand() {
|
||||||
|
Cypress.Commands.add(
|
||||||
|
// @ts-ignore - ignoring Cypress type error which gets resolved when Cypress uses the command
|
||||||
|
'mockGQL',
|
||||||
|
(alias: string, handler: RouteHandler) => {
|
||||||
|
cy.intercept('POST', 'https://lb.testnet.vega.xyz/query', handler).as(
|
||||||
|
alias
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
45
libs/cypress/src/lib/commands/mock-vega-wallet.ts
Normal file
45
libs/cypress/src/lib/commands/mock-vega-wallet.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import merge from 'lodash/merge';
|
||||||
|
import type { TransactionResponse } from '@vegaprotocol/vegawallet-service-api-client';
|
||||||
|
import type { PartialDeep } from 'type-fest';
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||||
|
declare namespace Cypress {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
interface Chainable<Subject> {
|
||||||
|
mockVegaCommandSync(txHash: string, signature: string): void;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addMockVegaWalletCommands() {
|
||||||
|
Cypress.Commands.add(
|
||||||
|
// @ts-ignore - ignoring Cypress type error which gets resolved when Cypress uses the command
|
||||||
|
'mockVegaCommandSync',
|
||||||
|
(override?: PartialDeep<TransactionResponse>) => {
|
||||||
|
const defaultTransactionResponse = {
|
||||||
|
txHash: 'tx-hash',
|
||||||
|
tx: {
|
||||||
|
input_data:
|
||||||
|
'CPe6vpiqsPqxDBDC1w7KPkoKQGE4Y2M0NjUwMjhiMGY4OTM4YTYzZTEzNDViYzM2ODc3ZWRmODg4MjNmOWU0ZmI4ZDRlN2VkMmFlMzAwNzA3ZTMYASABKAM4Ag==',
|
||||||
|
signature: {
|
||||||
|
// sig value needs to be 'real' so sigToId function doesn't error out
|
||||||
|
value: 'signature',
|
||||||
|
algo: 'vega/ed25519',
|
||||||
|
version: 1,
|
||||||
|
},
|
||||||
|
From: {
|
||||||
|
PubKey: Cypress.env('vegaPublicKey'),
|
||||||
|
},
|
||||||
|
version: 2,
|
||||||
|
pow: {
|
||||||
|
tid: '0CEEC2FDFDB5D68BC0C1E2640440E4AA11E49986CB2929E0F3572E16CB7DC59C',
|
||||||
|
nonce: 23525,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
cy.intercept('POST', 'http://localhost:1789/api/v1/command/sync', {
|
||||||
|
body: merge(defaultTransactionResponse, override),
|
||||||
|
}).as('VegaCommandSync');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
@ -11,8 +11,13 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"allowJs": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
|
"noImplicitOverride": true,
|
||||||
|
"noPropertyAccessFromIndexSignature": true,
|
||||||
"noImplicitReturns": true,
|
"noImplicitReturns": true,
|
||||||
"noFallthroughCasesInSwitch": true
|
"noFallthroughCasesInSwitch": true
|
||||||
}
|
}
|
||||||
|
37
libs/deal-ticket/src/__tests__/generate-deal-ticket-query.ts
Normal file
37
libs/deal-ticket/src/__tests__/generate-deal-ticket-query.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { MarketState, MarketTradingMode } from '@vegaprotocol/types';
|
||||||
|
import merge from 'lodash/merge';
|
||||||
|
import type { PartialDeep } from 'type-fest';
|
||||||
|
import type { DealTicketQuery } from '../__generated__/DealTicketQuery';
|
||||||
|
|
||||||
|
export const generateDealTicketQuery = (
|
||||||
|
override?: PartialDeep<DealTicketQuery>
|
||||||
|
): DealTicketQuery => {
|
||||||
|
const defaultResult: DealTicketQuery = {
|
||||||
|
market: {
|
||||||
|
id: 'market-id',
|
||||||
|
decimalPlaces: 2,
|
||||||
|
state: MarketState.Active,
|
||||||
|
tradingMode: MarketTradingMode.Continuous,
|
||||||
|
tradableInstrument: {
|
||||||
|
instrument: {
|
||||||
|
product: {
|
||||||
|
quoteName: 'BTC',
|
||||||
|
__typename: 'Future',
|
||||||
|
},
|
||||||
|
__typename: 'Instrument',
|
||||||
|
},
|
||||||
|
__typename: 'TradableInstrument',
|
||||||
|
},
|
||||||
|
depth: {
|
||||||
|
__typename: 'MarketDepth',
|
||||||
|
lastTrade: {
|
||||||
|
__typename: 'Trade',
|
||||||
|
price: '100',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
__typename: 'Market',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return merge(defaultResult, override);
|
||||||
|
};
|
1
libs/deal-ticket/src/__tests__/index.ts
Normal file
1
libs/deal-ticket/src/__tests__/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './generate-deal-ticket-query';
|
@ -79,7 +79,11 @@ export const SubmitButton = ({
|
|||||||
>
|
>
|
||||||
{transactionStatus === 'pending' ? t('Pending...') : t('Place order')}
|
{transactionStatus === 'pending' ? t('Pending...') : t('Place order')}
|
||||||
</Button>
|
</Button>
|
||||||
{invalidText && <InputError className="mb-8">{invalidText}</InputError>}
|
{invalidText && (
|
||||||
|
<InputError className="mb-8" data-testid="dealticket-error-message">
|
||||||
|
{invalidText}
|
||||||
|
</InputError>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
78
libs/market-list/src/__tests__/generate-markets.ts
Normal file
78
libs/market-list/src/__tests__/generate-markets.ts
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import merge from 'lodash/merge';
|
||||||
|
import { MarketState, MarketTradingMode } from '@vegaprotocol/types';
|
||||||
|
import type { PartialDeep } from 'type-fest';
|
||||||
|
import type { Markets, Markets_markets } from '../lib/__generated__/Markets';
|
||||||
|
|
||||||
|
export const generateMarkets = (override?: PartialDeep<Markets>): Markets => {
|
||||||
|
const markets: Markets_markets[] = [
|
||||||
|
{
|
||||||
|
id: 'market-id',
|
||||||
|
name: 'ACTIVE MARKET',
|
||||||
|
decimalPlaces: 5,
|
||||||
|
data: {
|
||||||
|
market: {
|
||||||
|
id: '10cd0a793ad2887b340940337fa6d97a212e0e517fe8e9eab2b5ef3a38633f35',
|
||||||
|
state: MarketState.Active,
|
||||||
|
tradingMode: MarketTradingMode.Continuous,
|
||||||
|
__typename: 'Market',
|
||||||
|
},
|
||||||
|
bestBidPrice: '0',
|
||||||
|
bestOfferPrice: '0',
|
||||||
|
markPrice: '4612690058',
|
||||||
|
__typename: 'MarketData',
|
||||||
|
},
|
||||||
|
tradableInstrument: {
|
||||||
|
instrument: {
|
||||||
|
code: 'BTCUSD.MF21',
|
||||||
|
product: {
|
||||||
|
settlementAsset: {
|
||||||
|
symbol: 'tDAI',
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'Future',
|
||||||
|
},
|
||||||
|
__typename: 'Instrument',
|
||||||
|
},
|
||||||
|
__typename: 'TradableInstrument',
|
||||||
|
},
|
||||||
|
__typename: 'Market',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'test-market-suspended',
|
||||||
|
name: 'SUSPENDED MARKET',
|
||||||
|
decimalPlaces: 2,
|
||||||
|
data: {
|
||||||
|
market: {
|
||||||
|
id: '34d95e10faa00c21d19d382d6d7e6fc9722a96985369f0caec041b0f44b775ed',
|
||||||
|
state: MarketState.Suspended,
|
||||||
|
tradingMode: MarketTradingMode.Continuous,
|
||||||
|
__typename: 'Market',
|
||||||
|
},
|
||||||
|
bestBidPrice: '0',
|
||||||
|
bestOfferPrice: '0',
|
||||||
|
markPrice: '8441',
|
||||||
|
__typename: 'MarketData',
|
||||||
|
},
|
||||||
|
tradableInstrument: {
|
||||||
|
instrument: {
|
||||||
|
code: 'SOLUSD',
|
||||||
|
product: {
|
||||||
|
settlementAsset: {
|
||||||
|
symbol: 'XYZalpha',
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'Future',
|
||||||
|
},
|
||||||
|
__typename: 'Instrument',
|
||||||
|
},
|
||||||
|
__typename: 'TradableInstrument',
|
||||||
|
},
|
||||||
|
__typename: 'Market',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const defaultResult = {
|
||||||
|
markets,
|
||||||
|
};
|
||||||
|
|
||||||
|
return merge(defaultResult, override);
|
||||||
|
};
|
53
libs/trades/src/__tests__/generate-trades.ts
Normal file
53
libs/trades/src/__tests__/generate-trades.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import merge from 'lodash/merge';
|
||||||
|
import type { PartialDeep } from 'type-fest';
|
||||||
|
import type { Trades, Trades_market_trades } from '../lib/__generated__/Trades';
|
||||||
|
|
||||||
|
export const generateTrades = (override?: PartialDeep<Trades>): Trades => {
|
||||||
|
const trades: Trades_market_trades[] = [
|
||||||
|
{
|
||||||
|
id: 'FFFFBC80005C517A10ACF481F7E6893769471098E696D0CC407F18134044CB16',
|
||||||
|
price: '17116898',
|
||||||
|
size: '24',
|
||||||
|
createdAt: '2022-04-06T16:19:42.692598951Z',
|
||||||
|
market: {
|
||||||
|
id: '0c3c1490db767f926d24fb674b4235a9aa339614915a4ab96cbfc0e1ad83c0ff',
|
||||||
|
decimalPlaces: 5,
|
||||||
|
__typename: 'Market',
|
||||||
|
},
|
||||||
|
__typename: 'Trade',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'FFFFB91453AC8F26EDAC223E2FB6C4A61461B1837946B51D943D675FB94FDF72',
|
||||||
|
price: '17209102',
|
||||||
|
size: '7',
|
||||||
|
createdAt: '2022-04-07T06:59:44.835686754Z',
|
||||||
|
market: {
|
||||||
|
id: '0c3c1490db767f926d24fb674b4235a9aa339614915a4ab96cbfc0e1ad83c0ff',
|
||||||
|
decimalPlaces: 5,
|
||||||
|
__typename: 'Market',
|
||||||
|
},
|
||||||
|
__typename: 'Trade',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'FFFFAD1BF47AA2853E5C375B6B3A62375F62D5B10807583D32EF3119CC455CD1',
|
||||||
|
price: '17106734',
|
||||||
|
size: '18',
|
||||||
|
createdAt: '2022-04-07T17:56:47.997938583Z',
|
||||||
|
market: {
|
||||||
|
id: '0c3c1490db767f926d24fb674b4235a9aa339614915a4ab96cbfc0e1ad83c0ff',
|
||||||
|
decimalPlaces: 5,
|
||||||
|
__typename: 'Market',
|
||||||
|
},
|
||||||
|
__typename: 'Trade',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const defaultResult = {
|
||||||
|
market: {
|
||||||
|
id: 'market-id',
|
||||||
|
trades,
|
||||||
|
__typename: 'Market',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return merge(defaultResult, override);
|
||||||
|
};
|
1
libs/trades/src/__tests__/index.ts
Normal file
1
libs/trades/src/__tests__/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './generate-trades';
|
@ -124,6 +124,7 @@
|
|||||||
"sass": "1.43.2",
|
"sass": "1.43.2",
|
||||||
"storybook-addon-themes": "^6.1.0",
|
"storybook-addon-themes": "^6.1.0",
|
||||||
"ts-jest": "27.0.5",
|
"ts-jest": "27.0.5",
|
||||||
|
"type-fest": "^2.12.2",
|
||||||
"typescript": "~4.5.2",
|
"typescript": "~4.5.2",
|
||||||
"url-loader": "^3.0.0"
|
"url-loader": "^3.0.0"
|
||||||
},
|
},
|
||||||
|
@ -20171,6 +20171,11 @@ type-fest@^0.8.1:
|
|||||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
|
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
|
||||||
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
|
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
|
||||||
|
|
||||||
|
type-fest@^2.12.2:
|
||||||
|
version "2.12.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.12.2.tgz#80a53614e6b9b475eb9077472fb7498dc7aa51d0"
|
||||||
|
integrity sha512-qt6ylCGpLjZ7AaODxbpyBZSs9fCI9SkL3Z9q2oxMBQhs/uyY+VD8jHA8ULCGmWQJlBgqvO3EJeAngOHD8zQCrQ==
|
||||||
|
|
||||||
type-is@~1.6.18:
|
type-is@~1.6.18:
|
||||||
version "1.6.18"
|
version "1.6.18"
|
||||||
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
|
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
|
||||||
|
Loading…
Reference in New Issue
Block a user