Chore/Improve trading app mock queries (#582)

* fix: remove supreflous intercepts and use one intercept for all gql queries

* fix: mock vega tx per test, beforeEach not working

* fix: wait for both queries

* fix: move MarketList wait back

* fix: dont wait for MarketList query

* fix: move assertion to actual test body so other tests can run

* fix: ensure page rendered before checking url after redirect
This commit is contained in:
Matthew Russell 2022-06-20 08:16:47 -07:00 committed by GitHub
parent 40868bb98a
commit a11efacba1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 141 additions and 173 deletions

View File

@ -1,15 +1,11 @@
import { hasOperationName } from '../support';
import { aliasQuery } from '@vegaprotocol/cypress';
import { generateDepositPage } from '../support/mocks/generate-deposit-page';
describe('deposit form validation', () => {
beforeEach(() => {
cy.mockWeb3Provider();
cy.mockGQL('DepositPage', (req) => {
if (hasOperationName(req, 'DepositPage')) {
req.reply({
body: { data: generateDepositPage() },
});
}
cy.mockGQL((req) => {
aliasQuery(req, 'DepositPage', generateDepositPage());
});
cy.visit('/portfolio/deposit');

View File

@ -1,6 +1,6 @@
import { aliasQuery } from '@vegaprotocol/cypress';
import type { MarketList, MarketList_markets } from '@vegaprotocol/market-list';
import { MarketState } from '@vegaprotocol/types';
import { hasOperationName } from '../support';
import { generateMarketList } from '../support/mocks/generate-market-list';
import { generateMarkets } from '../support/mocks/generate-markets';
import type { MarketsLanding } from '../support/mocks/generate-markets-landing';
@ -23,30 +23,19 @@ describe('home', () => {
);
// Mock markets query that is triggered by home page to find default market
cy.mockGQL('MarketsLanding', (req) => {
if (hasOperationName(req, 'MarketsLanding')) {
req.reply({
body: { data: marketsLanding },
});
}
});
cy.mockGQL((req) => {
aliasQuery(req, 'MarketsLanding', marketsLanding);
aliasQuery(req, 'MarketList', marketList);
// Market market list for the dialog that opens on a trading page
cy.mockGQL('MarketList', (req) => {
if (hasOperationName(req, 'MarketList')) {
req.reply({
body: { data: marketList },
});
}
// Mock all market page queries
mockTradingPage(req, MarketState.Active);
});
// Mock market page
mockTradingPage(MarketState.Active);
cy.visit('/');
cy.wait('@MarketsLanding');
cy.wait('@GQL');
cy.get('main[data-testid="market"]').should('exist'); // Wait for page to be rendered to before checking url
cy.url().should('include', `/markets/${oldestMarket.id}`); // Should redirect to oldest market
cy.wait('@MarketList');
});
it('redirects to a default market with the landing dialog open', () => {
@ -115,40 +104,31 @@ describe('home', () => {
describe('no default found', () => {
it('redirects to a the market list page if no sensible default is found', () => {
// Mock markets query that is triggered by home page to find default market
cy.mockGQL('MarketsLanding', (req) => {
if (hasOperationName(req, 'MarketsLanding')) {
req.reply({
body: {
// Remove open timestamps so we can't calculate a sensible default market
data: generateMarketsLanding({
markets: [
{
marketTimestamps: {
__typename: 'MarketTimestamps',
open: '',
},
},
{
marketTimestamps: {
__typename: 'MarketTimestamps',
open: '',
},
},
],
}),
},
});
}
});
cy.mockGQL((req) => {
aliasQuery(
req,
'MarketsLanding',
generateMarketsLanding({
markets: [
{
marketTimestamps: {
__typename: 'MarketTimestamps',
open: '',
},
},
{
marketTimestamps: {
__typename: 'MarketTimestamps',
open: '',
},
},
],
})
);
aliasQuery(req, 'Markets', generateMarkets());
cy.mockGQL('Markets', (req) => {
if (hasOperationName(req, 'Markets')) {
req.reply({
body: {
data: generateMarkets(),
},
});
}
// Mock all market page queries
mockTradingPage(req, MarketState.Active);
});
cy.visit('/');

View File

@ -1,16 +1,12 @@
import { aliasQuery } from '@vegaprotocol/cypress';
import { MarketState } from '@vegaprotocol/types';
import { hasOperationName } from '../support';
import { generateMarkets } from '../support/mocks/generate-markets';
import { mockTradingPage } from '../support/trading';
describe('markets table', () => {
beforeEach(() => {
cy.mockGQL('Markets', (req) => {
if (hasOperationName(req, 'Markets')) {
req.reply({
body: { data: generateMarkets() },
});
}
cy.mockGQL((req) => {
aliasQuery(req, 'Markets', generateMarkets());
});
cy.visit('/markets');
});
@ -64,7 +60,9 @@ describe('markets table', () => {
cy.wait('@Markets');
cy.get('.ag-root-wrapper').should('be.visible');
mockTradingPage(MarketState.Active);
cy.mockGQL((req) => {
mockTradingPage(req, MarketState.Active);
});
// click on active market
cy.get('[role="gridcell"][col-id=data]').should('be.visible');
@ -79,7 +77,9 @@ describe('markets table', () => {
cy.wait('@Markets');
cy.get('.ag-root-wrapper').should('be.visible');
mockTradingPage(MarketState.Suspended);
cy.mockGQL((req) => {
mockTradingPage(req, MarketState.Suspended);
});
// click on active market
cy.get('[role="gridcell"][col-id=data]').should('be.visible');

View File

@ -3,7 +3,9 @@ import { mockTradingPage } from '../support/trading';
import { connectVegaWallet } from '../support/vega-wallet';
beforeEach(() => {
mockTradingPage(MarketState.Active);
cy.mockGQL((req) => {
mockTradingPage(req, MarketState.Active);
});
cy.visit('/markets/market-0');
});

View File

@ -17,6 +17,16 @@ interface Order {
expiresAt?: string;
}
const mockTx = {
txHash: 'test-tx-hash',
tx: {
signature: {
value:
'd86138bba739bbc1069b3dc975d20b3a1517c2b9bdd401c70eeb1a0ecbc502ec268cf3129824841178b8b506b0b7d650c76644dbd96f524a6cb2158fb7121800',
},
},
};
describe('deal ticket orders', () => {
const orderSizeField = 'order-size';
const orderPriceField = 'order-price';
@ -26,24 +36,15 @@ describe('deal ticket orders', () => {
const orderTransactionHash = 'tx-hash';
before(() => {
mockTradingPage(MarketState.Active);
cy.mockGQL((req) => {
mockTradingPage(req, MarketState.Active);
});
cy.visit('/markets/market-0');
connectVegaWallet();
});
beforeEach(() => {
cy.mockVegaCommandSync({
txHash: 'test-tx-hash',
tx: {
signature: {
value:
'd86138bba739bbc1069b3dc975d20b3a1517c2b9bdd401c70eeb1a0ecbc502ec268cf3129824841178b8b506b0b7d650c76644dbd96f524a6cb2158fb7121800',
},
},
});
});
it('successfully places market buy order', () => {
cy.mockVegaCommandSync(mockTx);
const order: Order = {
type: 'TYPE_MARKET',
side: 'SIDE_BUY',
@ -54,6 +55,7 @@ describe('deal ticket orders', () => {
});
it('successfully places market sell order', () => {
cy.mockVegaCommandSync(mockTx);
const order: Order = {
type: 'TYPE_MARKET',
side: 'SIDE_SELL',
@ -64,6 +66,7 @@ describe('deal ticket orders', () => {
});
it('successfully places limit buy order', () => {
cy.mockVegaCommandSync(mockTx);
const order: Order = {
type: 'TYPE_LIMIT',
side: 'SIDE_BUY',
@ -75,6 +78,7 @@ describe('deal ticket orders', () => {
});
it('successfully places limit sell order', () => {
cy.mockVegaCommandSync(mockTx);
const order: Order = {
type: 'TYPE_LIMIT',
side: 'SIDE_SELL',
@ -86,6 +90,7 @@ describe('deal ticket orders', () => {
});
it('successfully places GTT limit buy order', () => {
cy.mockVegaCommandSync(mockTx);
const order: Order = {
type: 'TYPE_LIMIT',
side: 'SIDE_SELL',
@ -152,7 +157,9 @@ describe('deal ticket orders', () => {
describe('deal ticket validation', () => {
before(() => {
mockTradingPage(MarketState.Active);
cy.mockGQL((req) => {
mockTradingPage(req, MarketState.Active);
});
cy.visit('/markets/market-0');
});

View File

@ -3,7 +3,9 @@ import { mockTradingPage } from '../support/trading';
import { connectVegaWallet } from '../support/vega-wallet';
beforeEach(() => {
mockTradingPage(MarketState.Active);
cy.mockGQL((req) => {
mockTradingPage(req, MarketState.Active);
});
cy.visit('/markets/market-0');
});

View File

@ -3,7 +3,9 @@ import { mockTradingPage } from '../support/trading';
import { connectVegaWallet } from '../support/vega-wallet';
beforeEach(() => {
mockTradingPage(MarketState.Active);
cy.mockGQL((req) => {
mockTradingPage(req, MarketState.Active);
});
cy.visit('/markets/market-0');
});

View File

@ -2,7 +2,9 @@ import { MarketState } from '@vegaprotocol/types';
import { mockTradingPage } from '../support/trading';
beforeEach(() => {
mockTradingPage(MarketState.Active);
cy.mockGQL((req) => {
mockTradingPage(req, MarketState.Active);
});
cy.visit('/markets/market-0');
});

View File

@ -1,4 +1,4 @@
import { hasOperationName } from '../support';
import { aliasQuery } from '@vegaprotocol/cypress';
import { connectEthereumWallet } from '../support/ethereum-wallet';
import { generateWithdrawPageQuery } from '../support/mocks/generate-withdraw-page-query';
import { connectVegaWallet } from '../support/vega-wallet';
@ -13,12 +13,8 @@ describe('withdraw', () => {
beforeEach(() => {
cy.mockWeb3Provider();
cy.mockGQL('WithdrawPageQuery', (req) => {
if (hasOperationName(req, 'WithdrawPageQuery')) {
req.reply({
body: { data: generateWithdrawPageQuery() },
});
}
cy.mockGQL((req) => {
aliasQuery(req, 'WithdrawPageQuery', generateWithdrawPageQuery());
});
cy.visit('/portfolio/withdraw');

View File

@ -1,4 +1,4 @@
import { hasOperationName } from '../support';
import { aliasQuery } from '@vegaprotocol/cypress';
import { connectEthereumWallet } from '../support/ethereum-wallet';
import { generateWithdrawals } from '../support/mocks/generate-withdrawals';
import { connectVegaWallet } from '../support/vega-wallet';
@ -6,12 +6,8 @@ import { connectVegaWallet } from '../support/vega-wallet';
describe('withdrawals', () => {
beforeEach(() => {
cy.mockWeb3Provider();
cy.mockGQL('Withdrawals', (req) => {
if (hasOperationName(req, 'Withdrawals')) {
req.reply({
body: { data: generateWithdrawals() },
});
}
cy.mockGQL((req) => {
aliasQuery(req, 'Withdrawals', generateWithdrawals());
});
cy.visit('/portfolio/withdrawals');

View File

@ -1,11 +1 @@
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;
};

View File

@ -1,5 +1,6 @@
import { aliasQuery } from '@vegaprotocol/cypress';
import type { MarketState } from '@vegaprotocol/types';
import { hasOperationName } from '.';
import type { CyHttpMessages } from 'cypress/types/net-stubbing';
import { generateAccounts } from './mocks/generate-accounts';
import { generateCandles } from './mocks/generate-candles';
import { generateChart } from './mocks/generate-chart';
@ -9,62 +10,28 @@ import { generateOrders } from './mocks/generate-orders';
import { generatePositions } from './mocks/generate-positions';
import { generateTrades } from './mocks/generate-trades';
export const mockTradingPage = (state: MarketState) => {
cy.mockGQL('Market', (req) => {
if (hasOperationName(req, 'Market')) {
req.reply({
body: {
data: generateMarket({
market: {
name: `${state.toUpperCase()} MARKET`,
},
}),
},
});
}
if (hasOperationName(req, 'Orders')) {
req.reply({
body: { data: generateOrders() },
});
}
if (hasOperationName(req, 'Accounts')) {
req.reply({
body: {
data: generateAccounts(),
},
});
}
if (hasOperationName(req, 'Positions')) {
req.reply({
body: { data: generatePositions() },
});
}
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() },
});
}
});
export const mockTradingPage = (
req: CyHttpMessages.IncomingHttpRequest,
state: MarketState
) => {
aliasQuery(
req,
'Market',
generateMarket({
market: {
name: `${state.toUpperCase()} MARKET`,
},
})
);
aliasQuery(req, 'Orders', generateOrders());
aliasQuery(req, 'Accounts', generateAccounts());
aliasQuery(req, 'Positions', generatePositions());
aliasQuery(
req,
'DealTicketQuery',
generateDealTicketQuery({ market: { state } })
);
aliasQuery(req, 'Trades', generateTrades());
aliasQuery(req, 'Chart', generateChart());
aliasQuery(req, 'Candles', generateCandles());
};

View File

@ -9,3 +9,5 @@ addSlackCommand();
addMockGQLCommand();
addMockVegaWalletCommands();
addMockWeb3ProviderCommand();
export * from './lib/graphql-test-utils';

View File

@ -5,15 +5,15 @@ declare global {
namespace Cypress {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface Chainable<Subject> {
mockGQL(alias: string, handler: RouteHandler): void;
mockGQL(handler: RouteHandler): void;
}
}
}
export function addMockGQLCommand() {
Cypress.Commands.add('mockGQL', (alias: string, handler: RouteHandler) => {
Cypress.Commands.add('mockGQL', (handler: RouteHandler) => {
cy.intercept('POST', 'https://lb.testnet.vega.xyz/query', handler).as(
alias
'GQL'
);
});
}

View File

@ -0,0 +1,26 @@
import type { CyHttpMessages } from 'cypress/types/net-stubbing';
export const hasOperationName = (
req: CyHttpMessages.IncomingHttpRequest,
operationName: string
) => {
const { body } = req;
return 'operationName' in body && body.operationName === operationName;
};
// Alias query if operationName matches
export const aliasQuery = (
req: CyHttpMessages.IncomingHttpRequest,
operationName: string,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
data?: any
) => {
if (hasOperationName(req, operationName)) {
req.alias = operationName;
if (data !== undefined) {
req.reply((res) => {
res.body.data = data;
});
}
}
};