Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f5991de20a |
@@ -125,7 +125,7 @@ jobs:
|
||||
#----------------------------------------------
|
||||
- name: Run tests
|
||||
working-directory: ./console-test
|
||||
run: poetry run pytest -v -s --numprocesses auto --dist loadfile --durations=20
|
||||
run: poetry run pytest -s --numprocesses auto
|
||||
- name: Check files
|
||||
run: |
|
||||
ls -al .
|
||||
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
project: ${{ fromJSON(inputs.projects) }}
|
||||
name: ${{ matrix.project }}
|
||||
runs-on: self-hosted-runner
|
||||
timeout-minutes: 120
|
||||
timeout-minutes: 100
|
||||
steps:
|
||||
# Checks if skip cache was requested
|
||||
- name: Set skip-nx-cache flag
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
{
|
||||
"proposalSubmission": {
|
||||
"rationale": {
|
||||
"title": "Test new asset proposal",
|
||||
"description": "E2E test for proposals"
|
||||
},
|
||||
"terms": {
|
||||
"newAsset": {
|
||||
"changes": {
|
||||
"name": "USDT Coin",
|
||||
"symbol": "USDT",
|
||||
"decimals": "18",
|
||||
"quantum": "1",
|
||||
"erc20": {
|
||||
"contractAddress": "0xb404c51bbc10dcbe948077f18a4b8e553d160084",
|
||||
"withdrawThreshold": "10",
|
||||
"lifetimeLimit": "10"
|
||||
}
|
||||
}
|
||||
},
|
||||
"closingTimestamp": 1724339572,
|
||||
"enactmentTimestamp": 1724339572,
|
||||
"validationTimestamp": 1692799617
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
import { getNewAssetTxBody } from '../support/governance.functions';
|
||||
|
||||
context('Proposal page', { tags: '@smoke' }, function () {
|
||||
describe('Verify elements on page', function () {
|
||||
const proposalHeading = 'proposals-heading';
|
||||
const dateTimeRegex =
|
||||
/(\d{1,2})\/(\d{1,2})\/(\d{4}), (\d{1,2}):(\d{1,2}):(\d{1,2})/gm;
|
||||
const proposalTitle = 'Add Lorem Ipsum market';
|
||||
|
||||
before('Create market proposal', function () {
|
||||
cy.visit('/');
|
||||
@@ -12,8 +11,6 @@ context('Proposal page', { tags: '@smoke' }, function () {
|
||||
});
|
||||
|
||||
it('Able to view proposal', function () {
|
||||
const proposalTitle = 'Add Lorem Ipsum market';
|
||||
|
||||
cy.navigate_to('governanceProposals');
|
||||
cy.getByTestId(proposalHeading).should('be.visible');
|
||||
cy.contains(proposalTitle)
|
||||
@@ -25,9 +22,6 @@ context('Proposal page', { tags: '@smoke' }, function () {
|
||||
cy.get_element_by_col_id('type').should('have.text', 'NewMarket');
|
||||
cy.get_element_by_col_id('state').should('have.text', 'Enacted');
|
||||
cy.getByTestId('vote-progress').should('be.visible');
|
||||
cy.getByTestId('vote-progress-bar-for')
|
||||
.invoke('attr', 'style')
|
||||
.should('eq', 'width: 100%;');
|
||||
cy.get('[col-id="cDate"]')
|
||||
.invoke('text')
|
||||
.should('match', dateTimeRegex);
|
||||
@@ -41,12 +35,9 @@ context('Proposal page', { tags: '@smoke' }, function () {
|
||||
});
|
||||
cy.getByTestId('dialog-title').should('have.text', proposalTitle);
|
||||
cy.get('.language-json').should('exist');
|
||||
cy.getByTestId('icon-cross').click();
|
||||
});
|
||||
|
||||
it.skip('Proposal page displayed on mobile', function () {
|
||||
const proposalTitle = 'Add Lorem Ipsum market';
|
||||
|
||||
cy.common_switch_to_mobile_and_click_toggle();
|
||||
cy.navigate_to('governanceProposals', true);
|
||||
cy.getByTestId(proposalHeading).should('be.visible');
|
||||
@@ -54,40 +45,5 @@ context('Proposal page', { tags: '@smoke' }, function () {
|
||||
cy.get_element_by_col_id('title').should('have.text', proposalTitle);
|
||||
});
|
||||
});
|
||||
|
||||
it('Able to view new asset proposal', function () {
|
||||
const proposalTitle = 'Test new asset proposal';
|
||||
const newAssetProposalBody = getNewAssetTxBody();
|
||||
cy.VegaWalletSubmitProposal(newAssetProposalBody);
|
||||
|
||||
cy.visit('/');
|
||||
cy.navigate_to('governanceProposals');
|
||||
cy.contains(proposalTitle)
|
||||
.parent()
|
||||
.parent()
|
||||
.parent()
|
||||
.within(() => {
|
||||
cy.get_element_by_col_id('title').should('have.text', proposalTitle);
|
||||
cy.get_element_by_col_id('type').should('have.text', 'NewAsset');
|
||||
cy.get_element_by_col_id('state').should(
|
||||
'have.text',
|
||||
'Waiting for Node Vote'
|
||||
);
|
||||
cy.getByTestId('vote-progress').should('be.visible');
|
||||
cy.getByTestId('vote-progress-bar-against')
|
||||
.invoke('attr', 'style')
|
||||
.should('eq', 'width: 100%;');
|
||||
cy.get('[col-id="cDate"]')
|
||||
.invoke('text')
|
||||
.should('match', dateTimeRegex);
|
||||
cy.get('[col-id="eDate"]')
|
||||
.invoke('text')
|
||||
.should('match', dateTimeRegex);
|
||||
cy.getByTestId('external-link')
|
||||
.should('have.attr', 'href')
|
||||
.and('contains', 'https://governance.fairground.wtf/proposals/');
|
||||
cy.contains('View terms').should('exist').click();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,18 +1,8 @@
|
||||
import { addSeconds, millisecondsToSeconds } from 'date-fns';
|
||||
|
||||
export function createSuccessorMarketProposal(parentMarketId) {
|
||||
cy.VegaWalletSubmitProposal(getSuccessorTxBody(parentMarketId));
|
||||
}
|
||||
|
||||
function getSuccessorTxBody(parentMarketId) {
|
||||
const MIN_CLOSE_SEC = 500;
|
||||
const MIN_ENACT_SEC = 700;
|
||||
|
||||
const closingDate = addSeconds(new Date(), MIN_CLOSE_SEC);
|
||||
const enactmentDate = addSeconds(closingDate, MIN_ENACT_SEC);
|
||||
const closingTimestamp = millisecondsToSeconds(closingDate.getTime());
|
||||
const enactmentTimestamp = millisecondsToSeconds(enactmentDate.getTime());
|
||||
|
||||
return {
|
||||
proposalSubmission: {
|
||||
rationale: {
|
||||
@@ -132,49 +122,8 @@ function getSuccessorTxBody(parentMarketId) {
|
||||
},
|
||||
},
|
||||
},
|
||||
closingTimestamp,
|
||||
enactmentTimestamp,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function getNewAssetTxBody() {
|
||||
const MIN_CLOSE_SEC = 500;
|
||||
const MIN_ENACT_SEC = 700;
|
||||
const MIN_VALID_SEC = 60;
|
||||
|
||||
const closingDate = addSeconds(new Date(), MIN_CLOSE_SEC);
|
||||
const enactmentDate = addSeconds(closingDate, MIN_ENACT_SEC);
|
||||
const validationDate = addSeconds(new Date(), MIN_VALID_SEC);
|
||||
|
||||
const closingTimestamp = millisecondsToSeconds(closingDate.getTime());
|
||||
const enactmentTimestamp = millisecondsToSeconds(enactmentDate.getTime());
|
||||
const validationTimestamp = millisecondsToSeconds(validationDate.getTime());
|
||||
|
||||
return {
|
||||
proposalSubmission: {
|
||||
rationale: {
|
||||
title: 'Test new asset proposal',
|
||||
description: 'E2E test for proposals',
|
||||
},
|
||||
terms: {
|
||||
newAsset: {
|
||||
changes: {
|
||||
name: 'USDT Coin',
|
||||
symbol: 'USDT',
|
||||
decimals: '18',
|
||||
quantum: '1',
|
||||
erc20: {
|
||||
contractAddress: '0xb404c51bbc10dcbe948077f18a4b8e553d160084',
|
||||
withdrawThreshold: '10',
|
||||
lifetimeLimit: '10',
|
||||
},
|
||||
},
|
||||
},
|
||||
closingTimestamp,
|
||||
enactmentTimestamp,
|
||||
validationTimestamp,
|
||||
closingTimestamp: 1695666618,
|
||||
enactmentTimestamp: 1695666618,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
# App configuration variables
|
||||
NX_TENDERMINT_URL=http://localhost:26617
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
|
||||
NX_VEGA_ENV=CUSTOM
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
|
||||
@@ -6,6 +8,3 @@ NX_VEGA_EXPLORER_URL=/
|
||||
|
||||
# App flags
|
||||
NX_EXPLORER_TXS_LIST=0
|
||||
|
||||
NX_TENDERMINT_URL=http://localhost:26617
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
# App configuration variables
|
||||
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket
|
||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
|
||||
NX_VEGA_ENV=DEVNET
|
||||
NX_BLOCK_EXPLORER=https://be.devnet1.vega.xyz/rest
|
||||
@@ -8,6 +10,3 @@ NX_VEGA_URL=https://api.devnet1.vega.xyz/graphql
|
||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
NX_VEGA_EXPLORER_URL=/
|
||||
|
||||
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
# App configuration variables
|
||||
NX_TENDERMINT_URL=https://be.vega.community
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
|
||||
NX_SENTRY_DSN=https://b3a56b03eda842faad731f3ea9dfd1bc@o286262.ingest.sentry.io/6242427
|
||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/master/mainnet1/mainnet1.toml
|
||||
NX_VEGA_URL=https://api.vega.community/graphql
|
||||
@@ -9,6 +11,3 @@ NX_VEGA_GOVERNANCE_URL=https://governance.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||
NX_VEGA_EXPLORER_URL=https://explorer.vega.xyz/
|
||||
NX_VEGA_CONSOLE_URL=https://console.vega.xyz
|
||||
|
||||
NX_TENDERMINT_URL=https://be.vega.community
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
# App configuration variables
|
||||
NX_TENDERMINT_URL=https://be.mainnet-mirror.vega.rocks
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket
|
||||
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
|
||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/mainnet-mirror/vegawallet-mainnet-mirror.toml
|
||||
NX_VEGA_URL=https://api.mainnet-mirror.vega.rocks/graphql
|
||||
@@ -8,7 +10,4 @@ NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_VEGA_GOVERNANCE_URL=https://governance.mainnet-mirror.vega.rocks
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||
NX_VEGA_EXPLORER_URL=https://explorer.mainnet-mirror.vega.rocks/
|
||||
NX_VEGA_CONSOLE_URL=https://console.mainnet-mirror.vega.rocks
|
||||
|
||||
NX_TENDERMINT_URL=https://be.mainnet-mirror.vega.rocks
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket
|
||||
NX_VEGA_CONSOLE_URL=https://console.mainnet-mirror.vega.rocks
|
||||
@@ -1,5 +1,7 @@
|
||||
# App configuration variables
|
||||
NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz
|
||||
NX_BLOCK_EXPLORER=https://be.testnet.vega.xyz/rest
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket
|
||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/fairground/vegawallet-fairground.toml
|
||||
NX_VEGA_ENV=TESTNET
|
||||
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
|
||||
@@ -9,6 +11,3 @@ NX_VEGA_GOVERNANCE_URL=https://governance.fairground.wtf
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
|
||||
NX_VEGA_CONSOLE_URL=https://console.fairground.wtf
|
||||
|
||||
NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket
|
||||
|
||||
@@ -7,10 +7,9 @@ NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
|
||||
NX_TENDERMINT_URL=https://tm.be.validators-testnet.vega.rocks
|
||||
NX_BLOCK_EXPLORER=https://be.validators-testnet.vega.rocks/rest
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.xyz/websocket
|
||||
NX_VEGA_GOVERNANCE_URL=https://governance.validators-testnet.vega.rocks
|
||||
NX_VEGA_EXPLORER_URL=https://explorer.validators-testnet.vega.rocks/
|
||||
NX_VEGA_CONSOLE_URL=https://trading.validators-testnet.vega.rocks/
|
||||
|
||||
NX_TENDERMINT_URL=https://tm.be.validators-testnet.vega.rocks
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.xyz/websocket
|
||||
|
||||
@@ -11,7 +11,6 @@ import { TxDetailsBatch } from './tx-batch';
|
||||
import { TxDetailsChainEvent } from './tx-chain-event';
|
||||
import { TxDetailsNodeVote } from './tx-node-vote';
|
||||
import { TxDetailsOrderCancel } from './tx-order-cancel';
|
||||
import { TxDetailsStopOrderCancel } from './tx-stop-order-cancel';
|
||||
import { TxDetailsOrderAmend } from './tx-order-amend';
|
||||
import { TxDetailsWithdrawSubmission } from './tx-withdraw-submission';
|
||||
import { TxDetailsDelegate } from './tx-delegation';
|
||||
@@ -86,8 +85,6 @@ function getTransactionComponent(txData?: BlockExplorerTransactionResult) {
|
||||
return TxDetailsProtocolUpgrade;
|
||||
case 'Cancel Order':
|
||||
return TxDetailsOrderCancel;
|
||||
case 'Stop Orders Cancellation':
|
||||
return TxDetailsStopOrderCancel;
|
||||
case 'Amend Order':
|
||||
return TxDetailsOrderAmend;
|
||||
case 'Validator Heartbeat':
|
||||
|
||||
@@ -41,7 +41,7 @@ export const TxDetailsIssueSignatures = ({
|
||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||
}
|
||||
|
||||
const cmd: Command = txData.command.issueSignatures;
|
||||
const cmd: Command = txData.command;
|
||||
const k = cmd.kind ? kind[cmd.kind] : null;
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||
import { MarketLink } from '../../links/';
|
||||
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||
import { TxDetailsShared } from './shared/tx-details-shared';
|
||||
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||
import { CancelSummary } from '../../order-summary/order-cancellation';
|
||||
import Hash from '../../links/hash';
|
||||
import type { components } from '../../../../types/explorer';
|
||||
|
||||
export type StopOrderCancellationTransaction =
|
||||
components['schemas']['v1StopOrdersCancellation'];
|
||||
|
||||
interface TxDetailsStopOrderCancelProps {
|
||||
txData: BlockExplorerTransactionResult | undefined;
|
||||
pubKey: string | undefined;
|
||||
blockData: TendermintBlocksResponse | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Someone cancelled a stop order
|
||||
*/
|
||||
export const TxDetailsStopOrderCancel = ({
|
||||
txData,
|
||||
pubKey,
|
||||
blockData,
|
||||
}: TxDetailsStopOrderCancelProps) => {
|
||||
if (!txData || !txData.command) {
|
||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||
}
|
||||
|
||||
const command: StopOrderCancellationTransaction =
|
||||
txData.command.stopOrdersCancellation;
|
||||
|
||||
const { marketId, stopOrderId } = command;
|
||||
|
||||
return (
|
||||
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||
<TxDetailsShared txData={txData} pubKey={pubKey} blockData={blockData} />
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Cancel stop order')}</TableCell>
|
||||
<TableCell>
|
||||
{stopOrderId ? (
|
||||
<Hash text={stopOrderId} />
|
||||
) : (
|
||||
<CancelSummary orderId={stopOrderId} marketId={marketId} />
|
||||
)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
{marketId ? (
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Market')}</TableCell>
|
||||
<TableCell>
|
||||
<MarketLink id={marketId} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
) : null}
|
||||
</TableWithTbody>
|
||||
);
|
||||
};
|
||||
@@ -34,7 +34,6 @@ export type FilterOption =
|
||||
| 'Protocol Upgrade'
|
||||
| 'Register new Node'
|
||||
| 'State Variable Proposal'
|
||||
| 'Stop Orders Cancellation'
|
||||
| 'Submit Oracle Data'
|
||||
| 'Submit Order'
|
||||
| 'Transfer Funds'
|
||||
@@ -54,7 +53,6 @@ export const PrimaryFilterOptions: FilterOption[] = [
|
||||
'Delegate',
|
||||
'Liquidity Provision Order',
|
||||
'Proposal',
|
||||
'Stop Orders Cancellation',
|
||||
'Submit Oracle Data',
|
||||
'Submit Order',
|
||||
'Transfer Funds',
|
||||
|
||||
@@ -22,11 +22,6 @@ import { Footer } from '../components/footer/footer';
|
||||
import { Header } from '../components/header';
|
||||
import { Routes } from './route-names';
|
||||
import { useExplorerNodeNamesLazyQuery } from './validators/__generated__/NodeNames';
|
||||
import {
|
||||
ProtocolUpgradeCountdownMode,
|
||||
ProtocolUpgradeInProgressNotification,
|
||||
ProtocolUpgradeProposalNotification,
|
||||
} from '@vegaprotocol/proposals';
|
||||
|
||||
const DialogsContainer = () => {
|
||||
const { isOpen, id, trigger, asJson, setOpen } = useAssetDetailsDialogStore();
|
||||
@@ -67,10 +62,6 @@ export const Layout = () => {
|
||||
/>
|
||||
)}
|
||||
<Header />
|
||||
<ProtocolUpgradeProposalNotification
|
||||
mode={ProtocolUpgradeCountdownMode.IN_ESTIMATED_TIME_REMAINING}
|
||||
/>
|
||||
<ProtocolUpgradeInProgressNotification />
|
||||
</div>
|
||||
<div className={fixedWidthClasses}>
|
||||
<main className="p-4">
|
||||
|
||||
@@ -48,11 +48,9 @@ query ExplorerPartyAssets($partyId: ID!) {
|
||||
}
|
||||
stakingSummary {
|
||||
currentStakeAvailable
|
||||
linkings(pagination: { last: 100 }) {
|
||||
linkings(pagination: { first: 100 }) {
|
||||
edges {
|
||||
node {
|
||||
type
|
||||
status
|
||||
amount
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ export type ExplorerPartyAssetsQueryVariables = Types.Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type ExplorerPartyAssetsQuery = { __typename?: 'Query', partiesConnection?: { __typename?: 'PartyConnection', edges: Array<{ __typename?: 'PartyEdge', node: { __typename?: 'Party', id: string, delegationsConnection?: { __typename?: 'DelegationsConnection', edges?: Array<{ __typename?: 'DelegationEdge', node: { __typename?: 'Delegation', amount: string, epoch: number, node: { __typename?: 'Node', id: string, name: string } } } | null> | null } | null, stakingSummary: { __typename?: 'StakingSummary', currentStakeAvailable: string, linkings: { __typename?: 'StakesConnection', edges?: Array<{ __typename?: 'StakeLinkingEdge', node: { __typename?: 'StakeLinking', type: Types.StakeLinkingType, status: Types.StakeLinkingStatus, amount: string } } | null> | null } }, accountsConnection?: { __typename?: 'AccountsConnection', edges?: Array<{ __typename?: 'AccountEdge', node: { __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', name: string, id: string, decimals: number, symbol: string, source: { __typename: 'BuiltinAsset' } | { __typename: 'ERC20', contractAddress: string } }, market?: { __typename?: 'Market', id: string, decimalPlaces: number, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } } } } | null } } | null> | null } | null } }> } | null };
|
||||
export type ExplorerPartyAssetsQuery = { __typename?: 'Query', partiesConnection?: { __typename?: 'PartyConnection', edges: Array<{ __typename?: 'PartyEdge', node: { __typename?: 'Party', id: string, delegationsConnection?: { __typename?: 'DelegationsConnection', edges?: Array<{ __typename?: 'DelegationEdge', node: { __typename?: 'Delegation', amount: string, epoch: number, node: { __typename?: 'Node', id: string, name: string } } } | null> | null } | null, stakingSummary: { __typename?: 'StakingSummary', currentStakeAvailable: string, linkings: { __typename?: 'StakesConnection', edges?: Array<{ __typename?: 'StakeLinkingEdge', node: { __typename?: 'StakeLinking', amount: string } } | null> | null } }, accountsConnection?: { __typename?: 'AccountsConnection', edges?: Array<{ __typename?: 'AccountEdge', node: { __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', name: string, id: string, decimals: number, symbol: string, source: { __typename: 'BuiltinAsset' } | { __typename: 'ERC20', contractAddress: string } }, market?: { __typename?: 'Market', id: string, decimalPlaces: number, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } } } } | null } } | null> | null } | null } }> } | null };
|
||||
|
||||
export const ExplorerPartyAssetsAccountsFragmentDoc = gql`
|
||||
fragment ExplorerPartyAssetsAccounts on AccountBalance {
|
||||
@@ -64,11 +64,9 @@ export const ExplorerPartyAssetsDocument = gql`
|
||||
}
|
||||
stakingSummary {
|
||||
currentStakeAvailable
|
||||
linkings(pagination: {last: 100}) {
|
||||
linkings(pagination: {first: 100}) {
|
||||
edges {
|
||||
node {
|
||||
type
|
||||
status
|
||||
amount
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,15 +42,9 @@ export const PartyBlockStake = ({
|
||||
linkedLength && linkedLength > 0
|
||||
? p?.stakingSummary?.linkings?.edges
|
||||
?.reduce((total, e) => {
|
||||
const accumulator = new BigNumber(total);
|
||||
const diff = new BigNumber(e?.node.amount || 0);
|
||||
if (e?.node.type === 'TYPE_LINK') {
|
||||
return accumulator.plus(diff);
|
||||
} else if (e?.node.type === 'TYPE_UNLINK') {
|
||||
return accumulator.minus(diff);
|
||||
} else {
|
||||
return accumulator;
|
||||
}
|
||||
return new BigNumber(total).plus(
|
||||
new BigNumber(e?.node.amount || 0)
|
||||
);
|
||||
}, new BigNumber(0))
|
||||
.toString()
|
||||
: '0';
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<meta name="og:site_name" content="Vega Protocol - Explorer" />
|
||||
<meta name="og:image" content="https://static.vega.xyz/favicon.ico" />
|
||||
|
||||
<meta name="twitter:card" content="https://static.vega.xyz/favicon.ico" />
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content="Vega Protocol - Explorer" />
|
||||
<meta name="twitter:description" content="Vega Protocol - Explorer" />
|
||||
<meta name="twitter:image" content="https://static.vega.xyz/favicon.ico" />
|
||||
|
||||
@@ -220,7 +220,6 @@ describe(
|
||||
cy.getByTestId(changeVoteButton).should('be.visible').click();
|
||||
voteForProposal('for');
|
||||
// 3001-VOTE-064
|
||||
cy.getByTestId('user-voted-yes').should('exist');
|
||||
getProposalInformationFromTable('Tokens for proposal')
|
||||
.should('have.text', (1).toFixed(2))
|
||||
.and('be.visible');
|
||||
@@ -361,34 +360,6 @@ describe(
|
||||
stakingPageDisassociateAllTokens();
|
||||
});
|
||||
|
||||
it('Error message should be displayed if error returned from wallet when voting', function () {
|
||||
const errorMsg =
|
||||
'Application error: party has already submitted the maximum number of transactions of this type per epoch (3)';
|
||||
|
||||
createRawProposal();
|
||||
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||
getProposalFromTitle(rawProposal.rationale.title).within(() =>
|
||||
cy.getByTestId(viewProposalButton).click()
|
||||
);
|
||||
cy.intercept('POST', '/api/v2/requests', {
|
||||
jsonrpc: '2.0',
|
||||
error: {
|
||||
code: 2001,
|
||||
message: 'Application error',
|
||||
data: 'party has already submitted the maximum number of transactions of this type per epoch (3)',
|
||||
},
|
||||
id: '-PK5EGmErnjLhAmzMeclC',
|
||||
});
|
||||
cy.contains('Vote breakdown').should('be.visible', { timeout: 10000 });
|
||||
cy.getByTestId('vote-buttons').contains('for').click();
|
||||
cy.getByTestId('dialog-title').should(
|
||||
'have.text',
|
||||
'Transaction failed'
|
||||
);
|
||||
cy.getByTestId('Error').should('have.text', errorMsg);
|
||||
});
|
||||
});
|
||||
|
||||
it('Able to see successor market details with new and updated values', function () {
|
||||
cy.createMarket();
|
||||
cy.reload();
|
||||
|
||||
@@ -29,7 +29,6 @@ const toastPanel = 'toast-panel';
|
||||
const toastClose = 'toast-close';
|
||||
const withdrawalDialogContent = 'dialog-content';
|
||||
const toastCompleteWithdrawal = 'toast-complete-withdrawal';
|
||||
const scrollBar = '.ag-body-horizontal-scroll-viewport';
|
||||
const usdtName = 'USDC (local)';
|
||||
const usdcEthAddress = '0x1b8a1B6CBE5c93609b46D1829Cc7f3Cb8eeE23a0';
|
||||
const usdcSymbol = 'tUSDC';
|
||||
@@ -200,17 +199,20 @@ context(
|
||||
);
|
||||
cy.getByTestId(toastClose).click();
|
||||
});
|
||||
cy.get("[row-id='0']").within(() => {
|
||||
cy.get(tableAssetSymbol).should('have.text', usdcSymbol);
|
||||
cy.get(tableAmount).should('have.text', '110.00');
|
||||
cy.get(tableReceiverAddress)
|
||||
.find('a')
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', 'https://sepolia.etherscan.io/address/');
|
||||
cy.get(tableCreatedTimeStamp).should('not.be.empty');
|
||||
});
|
||||
cy.get(tableTxHash)
|
||||
.eq(1)
|
||||
.should('have.text', 'Complete withdrawal')
|
||||
.parent()
|
||||
.within(() => {
|
||||
cy.get(tableAssetSymbol).should('have.text', usdcSymbol);
|
||||
cy.get(tableAmount).should('have.text', '110.00');
|
||||
cy.get(tableReceiverAddress)
|
||||
.find('a')
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', 'https://sepolia.etherscan.io/address/');
|
||||
cy.get(tableCreatedTimeStamp).should('not.be.empty');
|
||||
});
|
||||
ethereumWalletConnect();
|
||||
cy.get(scrollBar).scrollTo('right');
|
||||
cy.getByTestId(completeWithdrawalButton).first().click();
|
||||
cy.getByTestId(toast)
|
||||
.last(txTimeout)
|
||||
|
||||
@@ -119,7 +119,6 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
|
||||
});
|
||||
});
|
||||
|
||||
// 0006-NETW-001 0006-NETW-002
|
||||
it('should display network data', function () {
|
||||
cy.getByTestId('git-network-data')
|
||||
.should('contain.text', 'Reading network data from')
|
||||
@@ -131,37 +130,6 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
|
||||
});
|
||||
});
|
||||
|
||||
// 0006-NETW-003 0006-NETW-008 0006-NETW-009 0006-NETW-010 0006-NETW-012 0006-NETW-013 0006-NETW-017 0006-NETW-018 0006-NETW-019 0006-NETW-020
|
||||
it('should have option to switch to different network node', function () {
|
||||
cy.getByTestId('git-network-data').within(() => {
|
||||
cy.getByTestId('link').click();
|
||||
});
|
||||
cy.getByTestId('node-row').within(() => {
|
||||
cy.getByTestId('node-url-0')
|
||||
.parent()
|
||||
.should('have.text', 'http://localhost:3008/graphql');
|
||||
cy.getByTestId('response-time-cell')
|
||||
.invoke('text')
|
||||
.should('not.be.empty')
|
||||
.and('not.eq', 'Checking');
|
||||
cy.getByTestId('block-height-cell')
|
||||
.invoke('text')
|
||||
.should('not.be.empty')
|
||||
.then((currentBlockHeight) => {
|
||||
// Check that block height updates automatically
|
||||
cy.getByTestId('block-height-cell')
|
||||
.invoke('text')
|
||||
.should('not.eq', currentBlockHeight);
|
||||
});
|
||||
cy.getByTestId('subscription-cell').should('have.text', 'Yes');
|
||||
});
|
||||
cy.getByTestId('connect').should('be.disabled');
|
||||
cy.getByTestId('node-url-custom').click();
|
||||
cy.get('input').should('exist');
|
||||
cy.getByTestId('connect').should('be.disabled');
|
||||
cy.getByTestId('icon-cross').click();
|
||||
});
|
||||
|
||||
it('should display eth data', function () {
|
||||
cy.getByTestId('git-eth-data')
|
||||
.should('contain.text', 'Reading Ethereum data from')
|
||||
@@ -170,7 +138,6 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
|
||||
});
|
||||
});
|
||||
|
||||
// 0006-NETW-011
|
||||
it('should contain link for known issues on Github', function () {
|
||||
cy.getByTestId('git-info').within(() => {
|
||||
cy.contains('Known issues and feedback on')
|
||||
|
||||
@@ -84,10 +84,9 @@ export function stakingPageAssociateTokens(
|
||||
.length
|
||||
) {
|
||||
cy.get(tokenInputApprove, txTimeout).should('be.enabled').click();
|
||||
cy.contains(
|
||||
'Approve $VEGA Tokens for staking on Vega',
|
||||
txTimeout
|
||||
).should('be.visible');
|
||||
cy.contains('Approve $VEGA Tokens for staking on Vega').should(
|
||||
'be.visible'
|
||||
);
|
||||
cy.contains(
|
||||
'Approve $VEGA Tokens for staking on Vega',
|
||||
txTimeout
|
||||
@@ -182,7 +181,7 @@ export function clickOnValidatorFromList(
|
||||
} else {
|
||||
cy.get(`[row-id="${validatorNumber}"]`)
|
||||
.should('be.visible')
|
||||
.first()
|
||||
.find(stakeValidatorListName)
|
||||
.as('validatorOnList');
|
||||
cy.get('@validatorOnList').click();
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ NX_VEGA_REST_URL=https://api.n00.stagnet1.vega.xyz/api/v2/
|
||||
NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.rocks
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket
|
||||
|
||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet
|
||||
|
||||
#Test configuration variables
|
||||
CYPRESS_FAIRGROUND=false
|
||||
|
||||
@@ -19,9 +19,6 @@ NX_DELEGATIONS_PAGINATION=50
|
||||
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz
|
||||
NX_VEGA_REST_URL=http://localhost:3008/api/v2/
|
||||
|
||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet
|
||||
|
||||
NX_TENDERMINT_URL=http://localhost:26617
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
|
||||
|
||||
@@ -29,4 +26,4 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
|
||||
CYPRESS_FAIRGROUND=false
|
||||
|
||||
# Cosmic elevator flags
|
||||
NX_SUCCESSOR_MARKETS=false
|
||||
NX_SUCCESSOR_MARKETS=false
|
||||
@@ -14,11 +14,8 @@ NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/annou
|
||||
NX_VEGA_REST_URL=https://api.n00.devnet1.vega.xyz/api/v2/
|
||||
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
|
||||
|
||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet
|
||||
|
||||
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket
|
||||
|
||||
# Cosmic elevator flags
|
||||
NX_SUCCESSOR_MARKETS=true
|
||||
NX_SUCCESSOR_MARKETS=true
|
||||
@@ -14,11 +14,9 @@ NX_DELEGATIONS_PAGINATION=50
|
||||
NX_TRANCHES_SERVICE_URL=https://tranches-mainnet-k8s.ops.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||
NX_VEGA_REST_URL=https://api.vega.community/api/v2/
|
||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet
|
||||
|
||||
NX_TENDERMINT_URL=https://be.vega.community
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
|
||||
|
||||
# Cosmic elevator flags
|
||||
NX_SUCCESSOR_MARKETS=false
|
||||
NX_SUCCESSOR_MARKETS=false
|
||||
@@ -13,11 +13,9 @@ NX_DELEGATIONS_PAGINATION=50
|
||||
NX_TRANCHES_SERVICE_URL=https://tranches-mainnet-mirror-k8s.ops.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||
NX_VEGA_REST_URL=https://api.mainnet-mirror.vega.rocks/api/v2/
|
||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet
|
||||
|
||||
NX_TENDERMINT_URL=https://be.mainnet-mirror.vega.rocks
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket
|
||||
|
||||
# Cosmic elevator flags
|
||||
NX_SUCCESSOR_MARKETS=false
|
||||
NX_SUCCESSOR_MARKETS=false
|
||||
@@ -10,11 +10,8 @@ NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
NX_VEGA_REST_URL=https://api.n00.stagnet1.vega.xyz/api/v2/
|
||||
|
||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet
|
||||
|
||||
NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.rocks
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket
|
||||
|
||||
# Cosmic elevator flags
|
||||
NX_SUCCESSOR_MARKETS=true
|
||||
NX_SUCCESSOR_MARKETS=true
|
||||
@@ -15,11 +15,8 @@ NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/annou
|
||||
NX_VEGA_REST_URL=https://api.n07.testnet.vega.xyz/api/v2/
|
||||
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
|
||||
|
||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet
|
||||
|
||||
NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket
|
||||
|
||||
# Cosmic elevator flags
|
||||
NX_SUCCESSOR_MARKETS=true
|
||||
NX_SUCCESSOR_MARKETS=true
|
||||
@@ -12,11 +12,8 @@ NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/annou
|
||||
NX_VEGA_REST_URL=https://api-validators-testnet.vega.rocks/api/v2/
|
||||
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
|
||||
|
||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet
|
||||
|
||||
NX_TENDERMINT_URL=https://tm.be.validators-testnet.vega.rocks
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.
|
||||
|
||||
# Cosmic elevator flags
|
||||
NX_SUCCESSOR_MARKETS=false
|
||||
NX_SUCCESSOR_MARKETS=false
|
||||
@@ -6,7 +6,6 @@ import { Nav } from '../nav';
|
||||
import { Networks, useEnvironment } from '@vegaprotocol/environment';
|
||||
import {
|
||||
ProtocolUpgradeCountdownMode,
|
||||
ProtocolUpgradeInProgressNotification,
|
||||
ProtocolUpgradeProposalNotification,
|
||||
} from '@vegaprotocol/proposals';
|
||||
import { ViewingAsBanner } from '@vegaprotocol/ui-toolkit';
|
||||
@@ -50,7 +49,6 @@ const NotificationsContainer = () => {
|
||||
<ProtocolUpgradeProposalNotification
|
||||
mode={ProtocolUpgradeCountdownMode.IN_ESTIMATED_TIME_REMAINING}
|
||||
/>
|
||||
<ProtocolUpgradeInProgressNotification />
|
||||
{isReadOnly ? (
|
||||
<ViewingAsBanner pubKey={pubKey} disconnect={disconnect} />
|
||||
) : null}
|
||||
|
||||
@@ -626,8 +626,7 @@
|
||||
"status-tendermint": "Consensus",
|
||||
"status-ersatz": "Standby",
|
||||
"status-pending": "Candidate",
|
||||
"ersatzDescription1": "To be promoted, a standby validator must have more than the lowest consensus stake, plus a bonus given to existing validators, and only one standby validator can be promoted per epoch. Currently this requires a minimum of",
|
||||
"ersatzDescription2": "stake assuming no performance penalty incurred.",
|
||||
"ersatzDescription": "To be promoted, a standby validator must have more than the lowest consensus stake, plus a bonus given to existing validators. This currently requires a minimum of {{stakeNeededForPromotion}} stake assuming no penalties. Only one validator per epoch can be promoted.",
|
||||
"pendingDescription1": "Anyone can",
|
||||
"pendingDescriptionLinkText": "set up and run a node on Vega",
|
||||
"pendingDescription2": ". A node can move from being a candidate into standby based on how much nomination it attracts, assuming it has proven reliability by sending heartbeats to the network.",
|
||||
@@ -785,7 +784,6 @@
|
||||
"PerformancePenaltyDescription": "Performance score is a measure of how often a validator proposed blocks in the last epoch relative to how many they should be expected to propose based on their voting power. Performance penalty is applied for having a performance score of less than 1",
|
||||
"UnnormalisedVotingPowerDescription": "The voting power of the validator based on their final validator score after all penalties have been applied",
|
||||
"NormalisedVotingPowerDescription": "The voting power of the validator, adjusted to ensure all validator scores sum to 1, used for distribution of rewards",
|
||||
"NonConsensusVotingPowerDescription": "The voting power of the validator. Only consensus validators have voting power",
|
||||
"Score": "Score",
|
||||
"performancePenalty": "Performance penalty",
|
||||
"overstaked": "Overstaked",
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<meta name="og:site_name" content="Vega Protocol - Governance" />
|
||||
<meta name="og:image" content="https://static.vega.xyz/favicon.ico" />
|
||||
|
||||
<meta name="twitter:card" content="https://static.vega.xyz/favicon.ico" />
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content="Vega Protocol - Governance" />
|
||||
<meta name="twitter:description" content="Vega Protocol - Governance" />
|
||||
<meta name="twitter:image" content="https://static.vega.xyz/favicon.ico" />
|
||||
|
||||
+38
-21
@@ -1,27 +1,44 @@
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import { RoundedWrapper, ShowMore } from '@vegaprotocol/ui-toolkit';
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { RoundedWrapper } from '@vegaprotocol/ui-toolkit';
|
||||
import { SubHeading } from '../../../../components/heading';
|
||||
import { CollapsibleToggle } from '../../../../components/collapsible-toggle';
|
||||
|
||||
export const ProposalDescription = ({
|
||||
description,
|
||||
}: {
|
||||
description: string;
|
||||
}) => (
|
||||
<section data-testid="proposal-description">
|
||||
<RoundedWrapper paddingBottom={true} marginBottomLarge={true}>
|
||||
<div className="p-2">
|
||||
<ShowMore>
|
||||
<ReactMarkdown
|
||||
className="react-markdown-container"
|
||||
/* Prevents HTML embedded in the description from rendering */
|
||||
skipHtml={true}
|
||||
/* Stops users embedding images which could be used for tracking */
|
||||
disallowedElements={['img']}
|
||||
linkTarget="_blank"
|
||||
>
|
||||
{description}
|
||||
</ReactMarkdown>
|
||||
</ShowMore>
|
||||
</div>
|
||||
</RoundedWrapper>
|
||||
</section>
|
||||
);
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [showDescription, setShowDescription] = useState(false);
|
||||
|
||||
return (
|
||||
<section data-testid="proposal-description">
|
||||
<CollapsibleToggle
|
||||
toggleState={showDescription}
|
||||
setToggleState={setShowDescription}
|
||||
dataTestId={'proposal-description-toggle'}
|
||||
>
|
||||
<SubHeading title={t('proposalDescription')} />
|
||||
</CollapsibleToggle>
|
||||
|
||||
{showDescription && (
|
||||
<RoundedWrapper paddingBottom={true} marginBottomLarge={true}>
|
||||
<div className="p-2">
|
||||
<ReactMarkdown
|
||||
className="react-markdown-container"
|
||||
/* Prevents HTML embedded in the description from rendering */
|
||||
skipHtml={true}
|
||||
/* Stops users embedding images which could be used for tracking */
|
||||
disallowedElements={['img']}
|
||||
linkTarget="_blank"
|
||||
>
|
||||
{description}
|
||||
</ReactMarkdown>
|
||||
</div>
|
||||
</RoundedWrapper>
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
+9
-22
@@ -24,7 +24,6 @@ import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
|
||||
import type { MockedResponse } from '@apollo/client/testing';
|
||||
import { FLAGS } from '@vegaprotocol/environment';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import { VoteState } from '../vote-details/use-user-vote';
|
||||
|
||||
jest.mock('@vegaprotocol/proposals', () => ({
|
||||
...jest.requireActual('@vegaprotocol/proposals'),
|
||||
@@ -37,8 +36,7 @@ jest.mock('@vegaprotocol/proposals', () => ({
|
||||
const renderComponent = (
|
||||
proposal: ProposalQuery['proposal'],
|
||||
isListItem = true,
|
||||
mocks: MockedResponse[] = [],
|
||||
voteState?: VoteState
|
||||
mocks: MockedResponse[] = []
|
||||
) =>
|
||||
render(
|
||||
<AppStateProvider>
|
||||
@@ -49,7 +47,6 @@ const renderComponent = (
|
||||
proposal={proposal}
|
||||
isListItem={isListItem}
|
||||
networkParams={mockNetworkParams}
|
||||
voteState={voteState}
|
||||
/>
|
||||
</VegaWalletContext.Provider>
|
||||
</MockedProvider>
|
||||
@@ -389,15 +386,10 @@ describe('Proposal header', () => {
|
||||
closingDatetime: nextWeek.toString(),
|
||||
},
|
||||
});
|
||||
renderComponent(
|
||||
proposal,
|
||||
true,
|
||||
[
|
||||
// @ts-ignore generateProposal always creates an id
|
||||
createUserVoteQueryMock(proposal.id, VoteValue.VALUE_NO),
|
||||
],
|
||||
VoteState.No
|
||||
);
|
||||
renderComponent(proposal, true, [
|
||||
// @ts-ignore generateProposal always creates an id
|
||||
createUserVoteQueryMock(proposal.id, VoteValue.VALUE_NO),
|
||||
]);
|
||||
expect(await screen.findByTestId('user-voted-no')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -408,15 +400,10 @@ describe('Proposal header', () => {
|
||||
closingDatetime: nextWeek.toString(),
|
||||
},
|
||||
});
|
||||
renderComponent(
|
||||
proposal,
|
||||
true,
|
||||
[
|
||||
// @ts-ignore generateProposal always creates an id
|
||||
createUserVoteQueryMock(proposal.id, VoteValue.VALUE_YES),
|
||||
],
|
||||
VoteState.Yes
|
||||
);
|
||||
renderComponent(proposal, true, [
|
||||
// @ts-ignore generateProposal always creates an id
|
||||
createUserVoteQueryMock(proposal.id, VoteValue.VALUE_YES),
|
||||
]);
|
||||
expect(await screen.findByTestId('user-voted-yes')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
+2
-3
@@ -8,26 +8,25 @@ import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
|
||||
import { truncateMiddle } from '../../../../lib/truncate-middle';
|
||||
import { CurrentProposalState } from '../current-proposal-state';
|
||||
import { ProposalInfoLabel } from '../proposal-info-label';
|
||||
import { useUserVote } from '../vote-details/use-user-vote';
|
||||
import { ProposalVotingStatus } from '../proposal-voting-status';
|
||||
import type { NetworkParamsResult } from '@vegaprotocol/network-parameters';
|
||||
import { useSuccessorMarketProposalDetails } from '@vegaprotocol/proposals';
|
||||
import { FLAGS } from '@vegaprotocol/environment';
|
||||
import Routes from '../../../routes';
|
||||
import { Link } from 'react-router-dom';
|
||||
import type { VoteState } from '../vote-details/use-user-vote';
|
||||
|
||||
export const ProposalHeader = ({
|
||||
proposal,
|
||||
networkParams,
|
||||
isListItem = true,
|
||||
voteState,
|
||||
}: {
|
||||
proposal: ProposalFieldsFragment | ProposalQuery['proposal'];
|
||||
networkParams: Partial<NetworkParamsResult>;
|
||||
isListItem?: boolean;
|
||||
voteState?: VoteState | null;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { voteState } = useUserVote(proposal?.id);
|
||||
const change = proposal?.terms.change;
|
||||
|
||||
let details: ReactNode;
|
||||
|
||||
+152
-138
@@ -15,6 +15,8 @@ import {
|
||||
SettlementAssetInfoPanel,
|
||||
} from '@vegaprotocol/markets';
|
||||
import {
|
||||
Accordion,
|
||||
AccordionItem,
|
||||
Button,
|
||||
CopyWithTooltip,
|
||||
Dialog,
|
||||
@@ -41,9 +43,6 @@ export const useMarketDataDialogStore = create<MarketDataDialogState>(
|
||||
})
|
||||
);
|
||||
|
||||
const marketDataHeaderStyles =
|
||||
'font-alpha calt text-base border-b border-vega-dark-200 mt-2 py-2';
|
||||
|
||||
export const ProposalMarketData = ({
|
||||
marketData,
|
||||
parentMarketData,
|
||||
@@ -77,14 +76,6 @@ export const ProposalMarketData = ({
|
||||
parentTerminationData !== undefined &&
|
||||
isEqual(terminationData, parentTerminationData);
|
||||
|
||||
const showParentPriceMonitoringBounds =
|
||||
parentMarketData?.priceMonitoringSettings?.parameters?.triggers !==
|
||||
undefined &&
|
||||
!isEqual(
|
||||
marketData.priceMonitoringSettings?.parameters?.triggers,
|
||||
parentMarketData?.priceMonitoringSettings?.parameters?.triggers
|
||||
);
|
||||
|
||||
const getSigners = (data: DataSourceDefinition) => {
|
||||
if (data.sourceType.__typename === 'DataSourceDefinitionExternal') {
|
||||
const signers = data.sourceType.sourceType.signers || [];
|
||||
@@ -117,141 +108,164 @@ export const ProposalMarketData = ({
|
||||
</Button>
|
||||
</div>
|
||||
<div className="mb-10">
|
||||
<h2 className={marketDataHeaderStyles}>{t('Key details')}</h2>
|
||||
<KeyDetailsInfoPanel
|
||||
market={marketData}
|
||||
parentMarket={parentMarketData}
|
||||
/>
|
||||
|
||||
<h2 className={marketDataHeaderStyles}>{t('Instrument')}</h2>
|
||||
<InstrumentInfoPanel
|
||||
market={marketData}
|
||||
parentMarket={parentMarketData}
|
||||
/>
|
||||
|
||||
{isEqual(
|
||||
getSigners(settlementData),
|
||||
getSigners(terminationData)
|
||||
) ? (
|
||||
<>
|
||||
<h2 className={marketDataHeaderStyles}>{t('Oracle')}</h2>
|
||||
|
||||
<OracleInfoPanel
|
||||
market={marketData}
|
||||
type="settlementData"
|
||||
parentMarket={
|
||||
isParentSettlementDataEqual ? undefined : parentMarketData
|
||||
<Accordion>
|
||||
<AccordionItem
|
||||
itemId="key-details"
|
||||
title={t('Key details')}
|
||||
content={
|
||||
<KeyDetailsInfoPanel
|
||||
market={marketData}
|
||||
parentMarket={parentMarketData}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<AccordionItem
|
||||
itemId="instrument"
|
||||
title={t('Instrument')}
|
||||
content={
|
||||
<InstrumentInfoPanel
|
||||
market={marketData}
|
||||
parentMarket={parentMarketData}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
{isEqual(
|
||||
getSigners(settlementData),
|
||||
getSigners(terminationData)
|
||||
) ? (
|
||||
<AccordionItem
|
||||
itemId="oracles"
|
||||
title={t('Oracle')}
|
||||
content={
|
||||
<OracleInfoPanel
|
||||
market={marketData}
|
||||
type="settlementData"
|
||||
parentMarket={
|
||||
isParentSettlementDataEqual
|
||||
? undefined
|
||||
: parentMarketData
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<h2 className={marketDataHeaderStyles}>
|
||||
{t('Settlement Oracle')}
|
||||
</h2>
|
||||
<OracleInfoPanel
|
||||
market={marketData}
|
||||
type="settlementData"
|
||||
parentMarket={
|
||||
isParentSettlementDataEqual ? undefined : parentMarketData
|
||||
}
|
||||
/>
|
||||
|
||||
<h2 className={marketDataHeaderStyles}>
|
||||
{t('Termination Oracle')}
|
||||
</h2>
|
||||
<OracleInfoPanel
|
||||
market={marketData}
|
||||
type="termination"
|
||||
parentMarket={
|
||||
isParentTerminationDataEqual ? undefined : parentMarketData
|
||||
}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/*Note: successor markets will not differ in their settlement*/}
|
||||
{/*assets, so no need to pass in parent market data for comparison.*/}
|
||||
|
||||
<h2 className={marketDataHeaderStyles}>{t('Settlement assets')}</h2>
|
||||
<SettlementAssetInfoPanel
|
||||
market={marketData}
|
||||
parentMarket={parentMarketData}
|
||||
/>
|
||||
|
||||
<h2 className={marketDataHeaderStyles}>{t('Metadata')}</h2>
|
||||
<MetadataInfoPanel
|
||||
market={marketData}
|
||||
parentMarket={parentMarketData}
|
||||
/>
|
||||
|
||||
<h2 className={marketDataHeaderStyles}>{t('Risk model')}</h2>
|
||||
<RiskModelInfoPanel
|
||||
market={marketData}
|
||||
parentMarket={parentMarketData}
|
||||
/>
|
||||
|
||||
<h2 className={marketDataHeaderStyles}>{t('Risk parameters')}</h2>
|
||||
<RiskParametersInfoPanel
|
||||
market={marketData}
|
||||
parentMarket={parentMarketData}
|
||||
/>
|
||||
|
||||
<h2 className={marketDataHeaderStyles}>{t('Risk factors')}</h2>
|
||||
<RiskFactorsInfoPanel
|
||||
market={marketData}
|
||||
parentMarket={parentMarketData}
|
||||
/>
|
||||
|
||||
{showParentPriceMonitoringBounds &&
|
||||
(
|
||||
parentMarketData?.priceMonitoringSettings?.parameters
|
||||
?.triggers || []
|
||||
).map((_, triggerIndex) => (
|
||||
) : (
|
||||
<>
|
||||
<h2 className={marketDataHeaderStyles}>
|
||||
{t(`Parent price monitoring bounds ${triggerIndex + 1}`)}
|
||||
</h2>
|
||||
<AccordionItem
|
||||
itemId="settlement-oracle"
|
||||
title={t('Settlement Oracle')}
|
||||
content={
|
||||
<OracleInfoPanel
|
||||
market={marketData}
|
||||
type="settlementData"
|
||||
parentMarket={
|
||||
isParentSettlementDataEqual
|
||||
? undefined
|
||||
: parentMarketData
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<div className="text-vega-dark-300 line-through">
|
||||
<AccordionItem
|
||||
itemId="termination-oracle"
|
||||
title={t('Termination Oracle')}
|
||||
content={
|
||||
<OracleInfoPanel
|
||||
market={marketData}
|
||||
type="termination"
|
||||
parentMarket={
|
||||
isParentTerminationDataEqual
|
||||
? undefined
|
||||
: parentMarketData
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{/*Note: successor markets will not differ in their settlement*/}
|
||||
{/*assets, so no need to pass in parent market data for comparison.*/}
|
||||
<AccordionItem
|
||||
itemId="settlement-asset"
|
||||
title={t('Settlement asset')}
|
||||
content={<SettlementAssetInfoPanel market={marketData} />}
|
||||
/>
|
||||
<AccordionItem
|
||||
itemId="metadata"
|
||||
title={t('Metadata')}
|
||||
content={
|
||||
<MetadataInfoPanel
|
||||
market={marketData}
|
||||
parentMarket={parentMarketData}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<AccordionItem
|
||||
itemId="risk-model"
|
||||
title={t('Risk model')}
|
||||
content={
|
||||
<RiskModelInfoPanel
|
||||
market={marketData}
|
||||
parentMarket={parentMarketData}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<AccordionItem
|
||||
itemId="risk-parameters"
|
||||
title={t('Risk parameters')}
|
||||
content={
|
||||
<RiskParametersInfoPanel
|
||||
market={marketData}
|
||||
parentMarket={parentMarketData}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<AccordionItem
|
||||
itemId="risk-factors"
|
||||
title={t('Risk factors')}
|
||||
content={
|
||||
<RiskFactorsInfoPanel
|
||||
market={marketData}
|
||||
parentMarket={parentMarketData}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
{(
|
||||
marketData.priceMonitoringSettings?.parameters?.triggers || []
|
||||
).map((_, triggerIndex) => (
|
||||
<AccordionItem
|
||||
itemId={`trigger-${triggerIndex}`}
|
||||
title={t(`Price monitoring bounds ${triggerIndex + 1}`)}
|
||||
content={
|
||||
<PriceMonitoringBoundsInfoPanel
|
||||
market={parentMarketData}
|
||||
market={marketData}
|
||||
parentMarket={parentMarketData}
|
||||
triggerIndex={triggerIndex}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
))}
|
||||
|
||||
{(
|
||||
marketData.priceMonitoringSettings?.parameters?.triggers || []
|
||||
).map((_, triggerIndex) => (
|
||||
<>
|
||||
<h2 className={marketDataHeaderStyles}>
|
||||
{t(`Price monitoring bounds ${triggerIndex + 1}`)}
|
||||
</h2>
|
||||
|
||||
<PriceMonitoringBoundsInfoPanel
|
||||
market={marketData}
|
||||
triggerIndex={triggerIndex}
|
||||
}
|
||||
/>
|
||||
</>
|
||||
))}
|
||||
|
||||
<h2 className={marketDataHeaderStyles}>
|
||||
{t('Liquidity monitoring parameters')}
|
||||
</h2>
|
||||
<LiquidityMonitoringParametersInfoPanel
|
||||
market={marketData}
|
||||
parentMarket={parentMarketData}
|
||||
/>
|
||||
|
||||
<h2 className={marketDataHeaderStyles}>
|
||||
{t('Liquidity price range')}
|
||||
</h2>
|
||||
<LiquidityPriceRangeInfoPanel
|
||||
market={marketData}
|
||||
parentMarket={parentMarketData}
|
||||
/>
|
||||
))}
|
||||
<AccordionItem
|
||||
itemId="liqudity-monitoring-parameters"
|
||||
title={t('Liquidity monitoring parameters')}
|
||||
content={
|
||||
<LiquidityMonitoringParametersInfoPanel
|
||||
market={marketData}
|
||||
parentMarket={parentMarketData}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<AccordionItem
|
||||
itemId="liquidity-price-range"
|
||||
title={t('Liquidity price range')}
|
||||
content={
|
||||
<LiquidityPriceRangeInfoPanel
|
||||
market={marketData}
|
||||
parentMarket={parentMarketData}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Accordion>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { VegaWalletProvider } from '@vegaprotocol/wallet';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { generateProposal } from '../../test-helpers/generate-proposals';
|
||||
import { Proposal } from './proposal';
|
||||
@@ -46,15 +44,11 @@ jest.mock('../list-asset', () => ({
|
||||
const renderComponent = (proposal: ProposalQuery['proposal']) => {
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<MockedProvider>
|
||||
<VegaWalletProvider>
|
||||
<Proposal
|
||||
restData={{}}
|
||||
proposal={proposal as ProposalQuery['proposal']}
|
||||
networkParams={mockNetworkParams}
|
||||
/>
|
||||
</VegaWalletProvider>
|
||||
</MockedProvider>
|
||||
<Proposal
|
||||
restData={{}}
|
||||
proposal={proposal as ProposalQuery['proposal']}
|
||||
networkParams={mockNetworkParams}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -19,8 +19,6 @@ import { removePaginationWrapper } from '@vegaprotocol/utils';
|
||||
import { ProposalState } from '@vegaprotocol/types';
|
||||
import { ProposalMarketChanges } from '../proposal-market-changes';
|
||||
import type { NetworkParamsResult } from '@vegaprotocol/network-parameters';
|
||||
import { useVoteSubmit } from '@vegaprotocol/proposals';
|
||||
import { useUserVote } from '../vote-details/use-user-vote';
|
||||
|
||||
export enum ProposalType {
|
||||
PROPOSAL_NEW_MARKET = 'PROPOSAL_NEW_MARKET',
|
||||
@@ -55,8 +53,6 @@ export const Proposal = ({
|
||||
mostRecentlyEnactedAssociatedMarketProposal,
|
||||
}: ProposalProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { submit, Dialog, finalizedVote, transaction } = useVoteSubmit();
|
||||
const { voteState, voteDatetime } = useUserVote(proposal?.id, finalizedVote);
|
||||
|
||||
if (!proposal) {
|
||||
return null;
|
||||
@@ -136,12 +132,10 @@ export const Proposal = ({
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<ProposalHeader
|
||||
proposal={proposal}
|
||||
isListItem={false}
|
||||
networkParams={networkParams}
|
||||
voteState={voteState}
|
||||
/>
|
||||
|
||||
<div id="details">
|
||||
@@ -213,11 +207,6 @@ export const Proposal = ({
|
||||
spamProtectionMinTokens={
|
||||
networkParams?.spam_protection_voting_min_tokens
|
||||
}
|
||||
submit={submit}
|
||||
dialog={Dialog}
|
||||
transaction={transaction}
|
||||
voteState={voteState}
|
||||
voteDatetime={voteDatetime}
|
||||
/>
|
||||
</RoundedWrapper>
|
||||
</div>
|
||||
|
||||
+1
-7
@@ -1,7 +1,6 @@
|
||||
import { RoundedWrapper } from '@vegaprotocol/ui-toolkit';
|
||||
import { ProposalHeader } from '../proposal-detail-header/proposal-header';
|
||||
import { ProposalsListItemDetails } from './proposals-list-item-details';
|
||||
import { useUserVote } from '../vote-details/use-user-vote';
|
||||
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
|
||||
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
|
||||
import type { NetworkParamsResult } from '@vegaprotocol/network-parameters';
|
||||
@@ -15,17 +14,12 @@ export const ProposalsListItem = ({
|
||||
proposal,
|
||||
networkParams,
|
||||
}: ProposalsListItemProps) => {
|
||||
const { voteState } = useUserVote(proposal?.id);
|
||||
if (!proposal || !proposal.id || !networkParams) return null;
|
||||
|
||||
return (
|
||||
<li id={proposal.id} data-testid="proposals-list-item">
|
||||
<RoundedWrapper paddingBottom={true} heightFull={true}>
|
||||
<ProposalHeader
|
||||
proposal={proposal}
|
||||
networkParams={networkParams}
|
||||
voteState={voteState}
|
||||
/>
|
||||
<ProposalHeader proposal={proposal} networkParams={networkParams} />
|
||||
<ProposalsListItemDetails proposal={proposal} />
|
||||
</RoundedWrapper>
|
||||
</li>
|
||||
|
||||
-110
@@ -1,110 +0,0 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { VoteTransactionDialog } from './vote-transaction-dialog';
|
||||
import { VoteState } from './use-user-vote';
|
||||
import { VegaTxStatus } from '@vegaprotocol/wallet';
|
||||
|
||||
describe('VoteTransactionDialog', () => {
|
||||
const mockTransactionDialog = jest.fn(({ title, content }) => (
|
||||
<div>
|
||||
<div>{title}</div>
|
||||
<div>{content?.Complete}</div>
|
||||
</div>
|
||||
));
|
||||
|
||||
it('renders without crashing', () => {
|
||||
render(
|
||||
<VoteTransactionDialog
|
||||
voteState={VoteState.Yes}
|
||||
transaction={null}
|
||||
TransactionDialog={mockTransactionDialog}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.getByTestId('vote-transaction-dialog')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders with txRequested title when voteState is Requested', () => {
|
||||
render(
|
||||
<VoteTransactionDialog
|
||||
voteState={VoteState.Requested}
|
||||
transaction={null}
|
||||
TransactionDialog={mockTransactionDialog}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.getByText('txRequested')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders with votePending title when voteState is Pending', () => {
|
||||
render(
|
||||
<VoteTransactionDialog
|
||||
voteState={VoteState.Pending}
|
||||
transaction={null}
|
||||
TransactionDialog={mockTransactionDialog}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.getByText('votePending')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders with no title when voteState is neither Requested nor Pending', () => {
|
||||
render(
|
||||
<VoteTransactionDialog
|
||||
voteState={VoteState.Yes} // or any other state other than Requested or Pending
|
||||
transaction={null}
|
||||
TransactionDialog={mockTransactionDialog}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.queryByText('txRequested')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('votePending')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders custom error message when voteState is Failed and error message exists', () => {
|
||||
render(
|
||||
<VoteTransactionDialog
|
||||
voteState={VoteState.Failed}
|
||||
transaction={{
|
||||
error: { message: 'Custom error test message', name: 'blah' },
|
||||
txHash: null,
|
||||
signature: null,
|
||||
status: VegaTxStatus.Error,
|
||||
dialogOpen: false,
|
||||
}}
|
||||
TransactionDialog={mockTransactionDialog}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.getByText('Custom error test message')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders default error message when voteState is failed and no error message exists on the tx', () => {
|
||||
render(
|
||||
<VoteTransactionDialog
|
||||
voteState={VoteState.Failed}
|
||||
transaction={{
|
||||
error: null,
|
||||
txHash: null,
|
||||
signature: null,
|
||||
status: VegaTxStatus.Error,
|
||||
dialogOpen: false,
|
||||
}}
|
||||
TransactionDialog={mockTransactionDialog}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.getByText('voteError')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders default ui (i.e. not error) when not in a failed state', () => {
|
||||
render(
|
||||
<VoteTransactionDialog
|
||||
voteState={VoteState.Yes}
|
||||
transaction={null}
|
||||
TransactionDialog={mockTransactionDialog}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.queryByText('voteError')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { VoteButtons } from './vote-buttons';
|
||||
import { VoteState } from './use-user-vote';
|
||||
@@ -24,7 +24,6 @@ describe('Vote buttons', () => {
|
||||
currentStakeAvailable={new BigNumber(1)}
|
||||
dialog={() => <div>Blah</div>}
|
||||
submit={() => Promise.resolve()}
|
||||
transaction={null}
|
||||
/>
|
||||
</VegaWalletContext.Provider>
|
||||
</MockedProvider>
|
||||
@@ -48,7 +47,6 @@ describe('Vote buttons', () => {
|
||||
currentStakeAvailable={new BigNumber(1)}
|
||||
dialog={() => <div>Blah</div>}
|
||||
submit={() => Promise.resolve()}
|
||||
transaction={null}
|
||||
/>
|
||||
</VegaWalletContext.Provider>
|
||||
</MockedProvider>
|
||||
@@ -83,7 +81,6 @@ describe('Vote buttons', () => {
|
||||
currentStakeAvailable={new BigNumber(1)}
|
||||
dialog={() => <div>Blah</div>}
|
||||
submit={() => Promise.resolve()}
|
||||
transaction={null}
|
||||
/>
|
||||
</VegaWalletContext.Provider>
|
||||
</MockedProvider>
|
||||
@@ -108,7 +105,6 @@ describe('Vote buttons', () => {
|
||||
currentStakeAvailable={new BigNumber(0)}
|
||||
dialog={() => <div>Blah</div>}
|
||||
submit={() => Promise.resolve()}
|
||||
transaction={null}
|
||||
/>
|
||||
</VegaWalletContext.Provider>
|
||||
</MockedProvider>
|
||||
@@ -136,7 +132,6 @@ describe('Vote buttons', () => {
|
||||
currentStakeAvailable={new BigNumber(1)}
|
||||
dialog={() => <div>Blah</div>}
|
||||
submit={() => Promise.resolve()}
|
||||
transaction={null}
|
||||
/>
|
||||
</VegaWalletContext.Provider>
|
||||
</MockedProvider>
|
||||
@@ -164,7 +159,6 @@ describe('Vote buttons', () => {
|
||||
currentStakeAvailable={new BigNumber(10)}
|
||||
dialog={() => <div>Blah</div>}
|
||||
submit={() => Promise.resolve()}
|
||||
transaction={null}
|
||||
/>
|
||||
</VegaWalletContext.Provider>
|
||||
</MockedProvider>
|
||||
@@ -189,7 +183,6 @@ describe('Vote buttons', () => {
|
||||
currentStakeAvailable={new BigNumber(10)}
|
||||
dialog={() => <div>Blah</div>}
|
||||
submit={() => Promise.resolve()}
|
||||
transaction={null}
|
||||
/>
|
||||
</VegaWalletContext.Provider>
|
||||
</MockedProvider>
|
||||
|
||||
@@ -17,7 +17,7 @@ import { VoteState } from './use-user-vote';
|
||||
import { ProposalMinRequirements, ProposalUserAction } from '../shared';
|
||||
import { VoteTransactionDialog } from './vote-transaction-dialog';
|
||||
import { useVoteButtonsQuery } from './__generated__/Stake';
|
||||
import type { DialogProps, VegaTxState } from '@vegaprotocol/wallet';
|
||||
import type { DialogProps } from '@vegaprotocol/wallet';
|
||||
|
||||
interface VoteButtonsContainerProps {
|
||||
voteState: VoteState | null;
|
||||
@@ -27,7 +27,6 @@ interface VoteButtonsContainerProps {
|
||||
minVoterBalance: string | null | undefined;
|
||||
spamProtectionMinTokens: string | null | undefined;
|
||||
submit: (voteValue: VoteValue, proposalId: string | null) => Promise<void>;
|
||||
transaction: VegaTxState | null;
|
||||
dialog: (props: DialogProps) => JSX.Element;
|
||||
className?: string;
|
||||
}
|
||||
@@ -68,7 +67,6 @@ export const VoteButtons = ({
|
||||
minVoterBalance,
|
||||
spamProtectionMinTokens,
|
||||
submit,
|
||||
transaction,
|
||||
dialog: Dialog,
|
||||
}: VoteButtonsProps) => {
|
||||
const { t } = useTranslation();
|
||||
@@ -190,7 +188,11 @@ export const VoteButtons = ({
|
||||
(voteState === VoteState.Yes || voteState === VoteState.No) && (
|
||||
<p data-testid="you-voted">
|
||||
<span>{t('youVoted')}:</span>{' '}
|
||||
<span className="text-white font-bold">
|
||||
<span
|
||||
className={
|
||||
voteState === VoteState.Yes ? 'text-success' : 'text-danger'
|
||||
}
|
||||
>
|
||||
{t(`voteState_${voteState}`)}
|
||||
</span>{' '}
|
||||
{voteDatetime ? (
|
||||
@@ -210,11 +212,7 @@ export const VoteButtons = ({
|
||||
</p>
|
||||
)
|
||||
)}
|
||||
<VoteTransactionDialog
|
||||
voteState={voteState}
|
||||
transaction={transaction}
|
||||
TransactionDialog={Dialog}
|
||||
/>
|
||||
<VoteTransactionDialog voteState={voteState} TransactionDialog={Dialog} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -3,30 +3,23 @@ import { formatDistanceToNow } from 'date-fns';
|
||||
import { RoundedWrapper, Icon, ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { ProposalState } from '@vegaprotocol/types';
|
||||
import { VoteProgress } from '@vegaprotocol/proposals';
|
||||
import { useVoteSubmit, VoteProgress } from '@vegaprotocol/proposals';
|
||||
import { formatNumber } from '../../../../lib/format-number';
|
||||
import { ConnectToVega } from '../../../../components/connect-to-vega';
|
||||
import { useVoteInformation } from '../../hooks';
|
||||
import { useUserVote } from './use-user-vote';
|
||||
import { CurrentProposalStatus } from '../current-proposal-status';
|
||||
import { VoteButtonsContainer } from './vote-buttons';
|
||||
import { SubHeading } from '../../../../components/heading';
|
||||
import { ProposalType } from '../proposal/proposal';
|
||||
import type { VoteValue } from '@vegaprotocol/types';
|
||||
import type { DialogProps, VegaTxState } from '@vegaprotocol/wallet';
|
||||
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
|
||||
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
|
||||
import type { VoteState } from './use-user-vote';
|
||||
|
||||
interface VoteDetailsProps {
|
||||
proposal: ProposalFieldsFragment | ProposalQuery['proposal'];
|
||||
minVoterBalance: string | null | undefined;
|
||||
spamProtectionMinTokens: string | null | undefined;
|
||||
proposalType: ProposalType | null;
|
||||
transaction: VegaTxState | null;
|
||||
submit: (voteValue: VoteValue, proposalId: string | null) => Promise<void>;
|
||||
dialog: (props: DialogProps) => JSX.Element;
|
||||
voteState: VoteState | null;
|
||||
voteDatetime: Date | null;
|
||||
}
|
||||
|
||||
export const VoteDetails = ({
|
||||
@@ -34,11 +27,6 @@ export const VoteDetails = ({
|
||||
minVoterBalance,
|
||||
spamProtectionMinTokens,
|
||||
proposalType,
|
||||
submit,
|
||||
transaction,
|
||||
dialog,
|
||||
voteState,
|
||||
voteDatetime,
|
||||
}: VoteDetailsProps) => {
|
||||
const { pubKey } = useVegaWallet();
|
||||
const {
|
||||
@@ -60,7 +48,8 @@ export const VoteDetails = ({
|
||||
} = useVoteInformation({ proposal });
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { submit, Dialog, finalizedVote } = useVoteSubmit();
|
||||
const { voteState, voteDatetime } = useUserVote(proposal?.id, finalizedVote);
|
||||
const defaultDecimals = 2;
|
||||
const daysLeft = t('daysLeft', {
|
||||
daysLeft: formatDistanceToNow(new Date(proposal?.terms.closingDatetime)),
|
||||
@@ -230,8 +219,7 @@ export const VoteDetails = ({
|
||||
spamProtectionMinTokens={spamProtectionMinTokens}
|
||||
className="flex"
|
||||
submit={submit}
|
||||
transaction={transaction}
|
||||
dialog={dialog}
|
||||
dialog={Dialog}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
|
||||
+2
-6
@@ -1,10 +1,9 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { VoteState } from './use-user-vote';
|
||||
import type { DialogProps, VegaTxState } from '@vegaprotocol/wallet';
|
||||
import type { DialogProps } from '@vegaprotocol/wallet';
|
||||
|
||||
interface VoteTransactionDialogProps {
|
||||
voteState: VoteState;
|
||||
transaction: VegaTxState | null;
|
||||
TransactionDialog: (props: DialogProps) => JSX.Element;
|
||||
}
|
||||
|
||||
@@ -21,15 +20,12 @@ const dialogTitle = (voteState: VoteState): string | undefined => {
|
||||
|
||||
export const VoteTransactionDialog = ({
|
||||
voteState,
|
||||
transaction,
|
||||
TransactionDialog,
|
||||
}: VoteTransactionDialogProps) => {
|
||||
// Render a custom message if the voting fails otherwise
|
||||
// pass undefined so that the default vega transaction dialog UI gets used
|
||||
const customMessage =
|
||||
voteState === VoteState.Failed ? (
|
||||
<p>{transaction?.error?.message || t('voteError')}</p>
|
||||
) : undefined;
|
||||
voteState === VoteState.Failed ? <p>{t('voteError')}</p> : undefined;
|
||||
|
||||
return (
|
||||
<div data-testid="vote-transaction-dialog">
|
||||
|
||||
+2
-2
@@ -389,10 +389,10 @@ export const ConsensusValidatorsTable = ({
|
||||
},
|
||||
{
|
||||
field: ValidatorFields.NORMALISED_VOTING_POWER,
|
||||
headerName: t('votingPower').toString(),
|
||||
headerName: t(ValidatorFields.NORMALISED_VOTING_POWER).toString(),
|
||||
headerTooltip: t('NormalisedVotingPowerDescription').toString(),
|
||||
cellRenderer: VotingPowerRenderer,
|
||||
width: 120,
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
field: ValidatorFields.TOTAL_PENALTIES,
|
||||
|
||||
+2
-11
@@ -20,7 +20,6 @@ import {
|
||||
TotalStakeRenderer,
|
||||
StakeShareRenderer,
|
||||
PendingStakeRenderer,
|
||||
VotingPowerRenderer,
|
||||
} from './shared';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import type { ColDef } from 'ag-grid-community';
|
||||
@@ -40,6 +39,7 @@ interface StandbyPendingValidatorsTableProps extends ValidatorsTableProps {
|
||||
export const StandbyPendingValidatorsTable = ({
|
||||
data,
|
||||
previousEpochData,
|
||||
totalStake,
|
||||
stakeNeededForPromotion,
|
||||
stakeNeededForPromotionDescription,
|
||||
validatorsView,
|
||||
@@ -132,8 +132,6 @@ export const StandbyPendingValidatorsTable = ({
|
||||
name,
|
||||
},
|
||||
[ValidatorFields.STAKE]: stakedTotal,
|
||||
[ValidatorFields.NORMALISED_VOTING_POWER]: '0%',
|
||||
[ValidatorFields.UNNORMALISED_VOTING_POWER]: '0%',
|
||||
[ValidatorFields.STAKE_NEEDED_FOR_PROMOTION]:
|
||||
individualStakeNeededForPromotion || null,
|
||||
[ValidatorFields.STAKE_NEEDED_FOR_PROMOTION_DESCRIPTION]:
|
||||
@@ -225,14 +223,7 @@ export const StandbyPendingValidatorsTable = ({
|
||||
headerName: t(ValidatorFields.STAKE_SHARE).toString(),
|
||||
headerTooltip: t('StakeShareDescription').toString(),
|
||||
cellRenderer: StakeShareRenderer,
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
field: ValidatorFields.NORMALISED_VOTING_POWER,
|
||||
headerName: t('votingPower').toString(),
|
||||
headerTooltip: t('NonConsensusVotingPowerDescription').toString(),
|
||||
cellRenderer: VotingPowerRenderer,
|
||||
width: 120,
|
||||
width: 100,
|
||||
},
|
||||
// {
|
||||
// field: ValidatorFields.STAKE_NEEDED_FOR_PROMOTION,
|
||||
|
||||
@@ -17,10 +17,6 @@ import type { PreviousEpochQuery } from '../../__generated__/PreviousEpoch';
|
||||
import type { StakingQuery } from '../../__generated__/Staking';
|
||||
import type { StakingDelegationFieldsFragment } from '../../__generated__/Staking';
|
||||
import type { ValidatorWithUserData } from './shared';
|
||||
import {
|
||||
NetworkParams,
|
||||
useNetworkParams,
|
||||
} from '@vegaprotocol/network-parameters';
|
||||
|
||||
export interface ValidatorsTableProps {
|
||||
nodesData: NodesQuery | undefined;
|
||||
@@ -45,9 +41,6 @@ export const ValidatorTables = ({
|
||||
const {
|
||||
appState: { decimals },
|
||||
} = useAppState();
|
||||
const { params } = useNetworkParams([
|
||||
NetworkParams.network_validators_incumbentBonus,
|
||||
]);
|
||||
|
||||
const [validatorsView, setValidatorsView] = useState<ValidatorsView>('all');
|
||||
const totalStake = useMemo(
|
||||
@@ -59,10 +52,6 @@ export const ValidatorTables = ({
|
||||
() => userStakingData?.party?.stakingSummary.currentStakeAvailable || '0',
|
||||
[userStakingData?.party?.stakingSummary.currentStakeAvailable]
|
||||
);
|
||||
const incumbentBonus = useMemo(
|
||||
() => new BigNumber(params?.network_validators_incumbentBonus),
|
||||
[params?.network_validators_incumbentBonus]
|
||||
);
|
||||
|
||||
let stakeNeededForPromotion = undefined;
|
||||
let delegations: StakingDelegationFieldsFragment[] | undefined = undefined;
|
||||
@@ -137,23 +126,28 @@ export const ValidatorTables = ({
|
||||
consensusValidators.length &&
|
||||
(standbyValidators.length || pendingValidators.length)
|
||||
) {
|
||||
const lowestConsensusStake = consensusValidators.reduce(
|
||||
const lowestRankingConsensusScore = consensusValidators.reduce(
|
||||
(lowest: ValidatorWithUserData, validator: ValidatorWithUserData) => {
|
||||
if (Number(validator.stakedTotal) < Number(lowest.stakedTotal)) {
|
||||
if (
|
||||
Number(validator.rankingScore.rankingScore) <
|
||||
Number(lowest.rankingScore.rankingScore)
|
||||
) {
|
||||
lowest = validator;
|
||||
}
|
||||
return lowest;
|
||||
}
|
||||
).stakedTotal;
|
||||
).rankingScore.rankingScore;
|
||||
|
||||
const lowestRankingBigNum = toBigNum(lowestConsensusStake, decimals);
|
||||
const lowestRankingBigNum = toBigNum(lowestRankingConsensusScore, 0);
|
||||
const consensusStakedTotal = consensusValidators.reduce((acc, cur) => {
|
||||
return acc.plus(toBigNum(cur.stakedTotal, decimals));
|
||||
}, new BigNumber(0));
|
||||
|
||||
stakeNeededForPromotion = formatNumber(
|
||||
lowestRankingBigNum.multipliedBy(incumbentBonus.plus(1)),
|
||||
lowestRankingBigNum.times(consensusStakedTotal),
|
||||
2
|
||||
).toString();
|
||||
}
|
||||
|
||||
return (
|
||||
<section data-testid="validator-tables">
|
||||
<div className="grid w-full justify-end">
|
||||
@@ -193,18 +187,12 @@ export const ValidatorTables = ({
|
||||
<div className="mb-10">
|
||||
<SubHeading title={t('status-ersatz')} />
|
||||
<p>
|
||||
<span>
|
||||
<Trans i18nKey="ersatzDescription1" />
|
||||
</span>
|
||||
|
||||
<span className="text-white font-bold">
|
||||
{' '}
|
||||
{stakeNeededForPromotion}{' '}
|
||||
</span>
|
||||
|
||||
<span>
|
||||
<Trans i18nKey="ersatzDescription2" />
|
||||
</span>
|
||||
<Trans
|
||||
i18nKey="ersatzDescription"
|
||||
values={{
|
||||
stakeNeededForPromotion,
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
<StandbyPendingValidatorsTable
|
||||
data={standbyValidators}
|
||||
|
||||
@@ -68,7 +68,7 @@ export const calculateOverstakedPenalty = (nodeId: string, nodes: Node[]) => {
|
||||
}
|
||||
const penalty = new BigNumber(1)
|
||||
.minus(
|
||||
new BigNumber(node.rewardScore?.rawValidatorScore || 1).dividedBy(tts)
|
||||
new BigNumber(node.rewardScore?.rawValidatorScore || 0).dividedBy(tts)
|
||||
)
|
||||
.times(100);
|
||||
return penalty.isLessThan(0) ? new BigNumber(0) : penalty;
|
||||
|
||||
@@ -36,4 +36,4 @@ CYPRESS_VEGA_WALLET_API_TOKEN=
|
||||
|
||||
# Cosmic elevator flags (MUST be doubled with CYPRESS_ prefix)
|
||||
NX_SUCCESSOR_MARKETS=true
|
||||
CYPRESS_NX_SUCCESSOR_MARKETS=true
|
||||
CYPRESS_NX_SUCCESSOR_MARKETS=true
|
||||
@@ -256,15 +256,8 @@ describe('Closed markets', { tags: '@smoke' }, () => {
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
.find('[col-id="code"]')
|
||||
.find('[data-testid="market-code"]')
|
||||
.should('have.text', settledMarket.tradableInstrument.instrument.code);
|
||||
|
||||
// 6001-MARK-071
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
.find('[title="Future"]')
|
||||
.should('have.text', 'Futr');
|
||||
|
||||
// 6001-MARK-002
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
|
||||
@@ -4,8 +4,7 @@ import * as Schema from '@vegaprotocol/types';
|
||||
|
||||
const rowSelector =
|
||||
'[data-testid="tab-open-markets"] .ag-center-cols-container .ag-row';
|
||||
const colInstrumentCode =
|
||||
'[col-id="tradableInstrument.instrument.code"] [data-testid="market-code"]';
|
||||
const colInstrumentCode = '[col-id="tradableInstrument.instrument.code"]';
|
||||
|
||||
describe('markets all table', { tags: '@smoke' }, () => {
|
||||
beforeEach(() => {
|
||||
@@ -69,12 +68,6 @@ describe('markets all table', { tags: '@smoke' }, () => {
|
||||
.find(colInstrumentCode)
|
||||
.should('have.text', 'SOLUSD');
|
||||
|
||||
// 6001-MARK-073
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
.find('[title="Future"]')
|
||||
.should('have.text', 'Futr');
|
||||
|
||||
// 6001-MARK-036
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
import {
|
||||
AuctionTrigger,
|
||||
MarketState,
|
||||
MarketTradingMode,
|
||||
} from '@vegaprotocol/types';
|
||||
|
||||
describe('markets selector', { tags: '@smoke' }, () => {
|
||||
const list = 'market-selector-list';
|
||||
const searchInput = 'search-term';
|
||||
|
||||
beforeEach(() => {
|
||||
cy.window().then((window) => {
|
||||
window.localStorage.setItem('marketId', 'market-1');
|
||||
});
|
||||
cy.setOnBoardingViewed();
|
||||
cy.mockTradingPage(
|
||||
MarketState.STATE_ACTIVE,
|
||||
MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
|
||||
AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
|
||||
);
|
||||
cy.mockSubscription();
|
||||
cy.visit('/');
|
||||
|
||||
cy.wait('@Markets');
|
||||
cy.wait('@MarketsData');
|
||||
});
|
||||
|
||||
// 6001-MARK-066
|
||||
it('can open popover to view markets', () => {
|
||||
cy.getByTestId('market-selector').should('not.exist');
|
||||
cy.getByTestId('header-title').should('be.visible').click();
|
||||
cy.getByTestId('market-selector').should('be.visible');
|
||||
});
|
||||
|
||||
// need function keyword as we need 'this' to access market data
|
||||
it('displays data as expected', () => {
|
||||
// TODO: load data from mocks in. Using alias and wrap intermittently fails
|
||||
const data = [
|
||||
{
|
||||
code: 'SOLUSD',
|
||||
markPrice: '84.41',
|
||||
vol: '0.00',
|
||||
},
|
||||
{
|
||||
code: 'ETHBTC.QM21',
|
||||
markPrice: '46,126.90058',
|
||||
vol: '0.00',
|
||||
},
|
||||
{
|
||||
code: 'BTCUSD.MF21',
|
||||
markPrice: '46,126.90058',
|
||||
vol: '0.00',
|
||||
},
|
||||
{
|
||||
code: 'AAPL.MF21',
|
||||
markPrice: '46,126.90058',
|
||||
vol: '0.00',
|
||||
},
|
||||
];
|
||||
cy.getByTestId('header-title').should('be.visible').click();
|
||||
cy.getByTestId(list)
|
||||
.find('a')
|
||||
.each((item, i) => {
|
||||
const market = data[i];
|
||||
// 6001-MARK-021
|
||||
// 6001-MARK-022
|
||||
expect(item.find('h3').text()).equals(market.code);
|
||||
expect(
|
||||
item.find('[data-testid="market-selector-volume"]').text()
|
||||
).contains(market.vol);
|
||||
// 6001-MARK-024
|
||||
expect(
|
||||
item.find('[data-testid="market-selector-price"]').text()
|
||||
).contains(market.markPrice);
|
||||
// 6001-MARK-025
|
||||
expect(item.find('[data-testid="sparkline-svg"]')).to.not.exist;
|
||||
});
|
||||
});
|
||||
|
||||
it('can use the filter options', () => {
|
||||
cy.getByTestId('header-title').should('be.visible').click();
|
||||
|
||||
// 6001-MARK-027
|
||||
// product type
|
||||
cy.getByTestId('product-Spot').click();
|
||||
cy.getByTestId(list).contains('Spot markets coming soon.');
|
||||
cy.getByTestId('product-Perpetual').click();
|
||||
cy.getByTestId(list).contains('Perpetual markets coming soon.');
|
||||
cy.getByTestId('product-Future').click();
|
||||
cy.getByTestId(list).find('a').should('have.length', 4);
|
||||
|
||||
// 6001-MARK-029
|
||||
cy.getByTestId(searchInput).clear().type('btc');
|
||||
cy.getByTestId(list).find('a').should('have.length', 2);
|
||||
cy.getByTestId(list).find('a').eq(1).contains('BTCUSD.MF21');
|
||||
cy.getByTestId(list).find('a').eq(0).contains('ETHBTC.QM21');
|
||||
|
||||
cy.getByTestId(searchInput).clear();
|
||||
cy.getByTestId(list).find('a').should('have.length', 4);
|
||||
});
|
||||
|
||||
it('can sort by by top gaining and top losing market', () => {
|
||||
cy.getByTestId('header-title').should('be.visible').click();
|
||||
|
||||
// 6001-MARK-030
|
||||
// 6001-MARK-031
|
||||
// 6001-MARK-032
|
||||
// 6001-MARK-033
|
||||
cy.getByTestId(' sort-trigger').click();
|
||||
cy.getByTestId('sort-item-Gained')
|
||||
.contains('Top gaining')
|
||||
.should('be.visible');
|
||||
cy.getByTestId('sort-item-Lost')
|
||||
.contains('Top losing')
|
||||
.should('be.visible');
|
||||
cy.getByTestId('sort-item-New')
|
||||
.contains('New markets')
|
||||
.should('be.visible');
|
||||
});
|
||||
|
||||
it('can filter by settlement asset', () => {
|
||||
cy.getByTestId('header-title').should('be.visible').click();
|
||||
|
||||
// 6001-MARK-028
|
||||
cy.getByTestId('asset-trigger').click();
|
||||
cy.getByTestId('asset-id-asset-3').contains('tBTC').click();
|
||||
cy.getByTestId(list).find('a').should('have.length', 1);
|
||||
cy.getByTestId(list).find('a').eq(0).contains('ETHBTC.QM21');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,227 @@
|
||||
import { aliasGQLQuery, checkSorting } from '@vegaprotocol/cypress';
|
||||
import type { ProposalsListQuery } from '@vegaprotocol/proposals';
|
||||
|
||||
const rowSelector =
|
||||
'[data-testid="tab-proposed-markets"] .ag-center-cols-container .ag-row';
|
||||
const colMarketId = '[col-id="market"]';
|
||||
|
||||
describe('markets proposed table', { tags: '@smoke' }, () => {
|
||||
before(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.setOnBoardingViewed();
|
||||
cy.visit('/#/markets/all');
|
||||
cy.get('[data-testid="Proposed markets"]').click();
|
||||
});
|
||||
|
||||
it('can see table headers', () => {
|
||||
const headers = [
|
||||
'Market',
|
||||
'Description',
|
||||
'Settlement asset',
|
||||
'State',
|
||||
'Parent market',
|
||||
'Voting',
|
||||
'Closing date',
|
||||
'Enactment date',
|
||||
'',
|
||||
];
|
||||
cy.getByTestId('tab-proposed-markets').within(($headers) => {
|
||||
cy.wrap($headers)
|
||||
.get('.ag-header-cell-text')
|
||||
.each(($header, i) => {
|
||||
cy.wrap($header).should('have.text', headers[i]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('renders markets correctly', () => {
|
||||
// 6001-MARK-049
|
||||
cy.get(rowSelector).first().find(colMarketId).should('have.text', 'ETHUSD');
|
||||
|
||||
// 6001-MARK-050
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
.find('[col-id="description"]')
|
||||
.should('have.text', 'ETHUSD');
|
||||
|
||||
// 6001-MARK-051
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
.find('[col-id="asset"]')
|
||||
.should('have.text', 'tDAI TEST');
|
||||
|
||||
// 6001-MARK-052
|
||||
// 6001-MARK-053
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
.find('[col-id="state"]')
|
||||
.should('have.text', 'Open');
|
||||
|
||||
// 6001-MARK-054
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
.find('[col-id="voting"]')
|
||||
.should('have.text', '');
|
||||
|
||||
// 6001-MARK-056
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
.find('[col-id="closing-date"]')
|
||||
.should('not.be.empty');
|
||||
|
||||
// 6001-MARK-057
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
.find('[col-id="enactment-date"]')
|
||||
.should('not.be.empty');
|
||||
});
|
||||
|
||||
it('can open row actions', () => {
|
||||
// 6001-MARK-058
|
||||
cy.get('.ag-pinned-right-cols-container')
|
||||
.find('[col-id="proposal-actions"]')
|
||||
.first()
|
||||
.find('button')
|
||||
.click();
|
||||
|
||||
const dropdownContent = '[data-testid="proposal-actions-content"]';
|
||||
const dropdownContentItem = '[role="menuitem"]';
|
||||
|
||||
// 6001-MARK-059
|
||||
cy.get(dropdownContent)
|
||||
.find(dropdownContentItem)
|
||||
.eq(0)
|
||||
.find('a')
|
||||
.should('have.text', 'View proposal')
|
||||
.and(
|
||||
'have.attr',
|
||||
'href',
|
||||
`${Cypress.env(
|
||||
'VEGA_TOKEN_URL'
|
||||
)}/proposals/e9ec6d5c46a7e7bcabf9ba7a893fa5a5eeeec08b731f06f7a6eb7bf0e605b829`
|
||||
);
|
||||
});
|
||||
|
||||
// 6001-MARK-060
|
||||
it('can see proposed market link', () => {
|
||||
cy.getByTestId('tab-proposed-markets')
|
||||
.find('[data-testid="external-link"]')
|
||||
.should('have.length', 11)
|
||||
.last()
|
||||
.should('have.text', 'Propose a new market')
|
||||
.and(
|
||||
'have.attr',
|
||||
'href',
|
||||
`${Cypress.env('VEGA_TOKEN_URL')}/proposals/propose/new-market`
|
||||
);
|
||||
});
|
||||
it('proposed markets tab should be sorted properly', () => {
|
||||
// 6001-MARK-062
|
||||
cy.get('[data-testid="Proposed markets"]').click({ force: true });
|
||||
const marketColDefault = [
|
||||
'ETHUSD',
|
||||
'LINKUSD',
|
||||
'ETHUSD',
|
||||
'ETHDAI.MF21',
|
||||
'AAPL.MF21',
|
||||
'BTCUSD.MF21',
|
||||
'TSLA.QM21',
|
||||
'AAVEDAI.MF21',
|
||||
'ETHBTC.QM21',
|
||||
'UNIDAI.MF21',
|
||||
];
|
||||
const marketColAsc = [
|
||||
'AAPL.MF21',
|
||||
'AAVEDAI.MF21',
|
||||
'BTCUSD.MF21',
|
||||
'ETHBTC.QM21',
|
||||
'ETHDAI.MF21',
|
||||
'ETHUSD',
|
||||
'ETHUSD',
|
||||
'LINKUSD',
|
||||
'TSLA.QM21',
|
||||
'UNIDAI.MF21',
|
||||
];
|
||||
const marketColDesc = [
|
||||
'UNIDAI.MF21',
|
||||
'TSLA.QM21',
|
||||
'LINKUSD',
|
||||
'ETHUSD',
|
||||
'ETHUSD',
|
||||
'ETHDAI.MF21',
|
||||
'ETHBTC.QM21',
|
||||
'BTCUSD.MF21',
|
||||
'AAVEDAI.MF21',
|
||||
'AAPL.MF21',
|
||||
];
|
||||
checkSorting('market', marketColDefault, marketColAsc, marketColDesc);
|
||||
|
||||
const stateColDefault = [
|
||||
'Open',
|
||||
'Passed',
|
||||
'Waiting for Node Vote',
|
||||
'Open',
|
||||
'Passed',
|
||||
'Open',
|
||||
'Passed',
|
||||
'Open',
|
||||
'Waiting for Node Vote',
|
||||
'Open',
|
||||
];
|
||||
const stateColAsc = [
|
||||
'Open',
|
||||
'Open',
|
||||
'Open',
|
||||
'Open',
|
||||
'Open',
|
||||
'Passed',
|
||||
'Passed',
|
||||
'Passed',
|
||||
'Waiting for Node Vote',
|
||||
'Waiting for Node Vote',
|
||||
];
|
||||
const stateColDesc = [
|
||||
'Waiting for Node Vote',
|
||||
'Waiting for Node Vote',
|
||||
'Passed',
|
||||
'Passed',
|
||||
'Passed',
|
||||
'Open',
|
||||
'Open',
|
||||
'Open',
|
||||
'Open',
|
||||
'Open',
|
||||
];
|
||||
checkSorting('state', stateColDefault, stateColAsc, stateColDesc);
|
||||
});
|
||||
|
||||
it('can drag and drop columns', () => {
|
||||
// 6001-MARK-063
|
||||
cy.get(colMarketId).realMouseDown().realMouseMove(700, 15).realMouseUp();
|
||||
cy.get(colMarketId).should(($element) => {
|
||||
const attributeValue = $element.attr('aria-colindex');
|
||||
expect(attributeValue).not.to.equal('1');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('no markets proposed', { tags: '@smoke', testIsolation: true }, () => {
|
||||
before(() => {
|
||||
cy.mockTradingPage();
|
||||
const proposal: ProposalsListQuery = {};
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(req, 'ProposalsList', proposal);
|
||||
});
|
||||
cy.mockSubscription();
|
||||
cy.setOnBoardingViewed();
|
||||
});
|
||||
|
||||
it.skip('can see no markets message', () => {
|
||||
cy.visit('/#/markets/all');
|
||||
cy.get('[data-testid="Proposed markets"]').click();
|
||||
|
||||
// 6001-MARK-061
|
||||
cy.getByTestId('tab-proposed-markets').should('contain.text', 'No markets');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,30 @@
|
||||
describe('Settings page', { tags: '@smoke' }, () => {
|
||||
beforeEach(() => {
|
||||
cy.clearLocalStorage();
|
||||
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.setOnBoardingViewed();
|
||||
cy.visit('/');
|
||||
|
||||
// Only click if not already active otherwise sidebar will close
|
||||
cy.get('[data-testid="sidebar-content"]').then(($sidebarContent) => {
|
||||
if ($sidebarContent.find('h2').text() !== 'Settings') {
|
||||
cy.get('[data-testid="sidebar"] [data-testid="Settings"]').click();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('telemetry checkbox should work well', () => {
|
||||
const telemetrySwitch = '#switch-settings-telemetry-switch';
|
||||
cy.get(telemetrySwitch).should('have.attr', 'data-state', 'unchecked');
|
||||
cy.get(telemetrySwitch).click();
|
||||
cy.get(telemetrySwitch).should('have.attr', 'data-state', 'checked');
|
||||
cy.reload();
|
||||
cy.get(telemetrySwitch).should('have.attr', 'data-state', 'checked');
|
||||
cy.get(telemetrySwitch).click();
|
||||
cy.get(telemetrySwitch).should('have.attr', 'data-state', 'unchecked');
|
||||
cy.reload();
|
||||
cy.get(telemetrySwitch).should('have.attr', 'data-state', 'unchecked');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,186 @@
|
||||
interface ItemInfoType {
|
||||
name: string;
|
||||
infoText: string;
|
||||
}
|
||||
|
||||
type CheckMenuItemsFnType = (
|
||||
triggerSelector: string,
|
||||
validTexts: string[],
|
||||
clickItem?: string
|
||||
) => void;
|
||||
type CheckMenuItemCheckboxFnType = (
|
||||
buttonText: string,
|
||||
items: ItemInfoType[]
|
||||
) => void;
|
||||
|
||||
const menuItemRadio = 'div[role="menuitemradio"]';
|
||||
const menuItemCheckbox = 'div[role="menuitemcheckbox"]';
|
||||
const button = 'button';
|
||||
const indicatorInfo = '.indicator-info-wrapper';
|
||||
|
||||
const checkMenuItems: CheckMenuItemsFnType = (
|
||||
triggerSelector,
|
||||
validTexts,
|
||||
clickItem
|
||||
) => {
|
||||
cy.get(triggerSelector).click();
|
||||
|
||||
cy.get(menuItemRadio)
|
||||
.should('have.length', validTexts.length)
|
||||
.each(($el, index) => {
|
||||
const text = $el.text().trim();
|
||||
expect(text).to.equal(validTexts[index]);
|
||||
});
|
||||
|
||||
if (clickItem) {
|
||||
cy.contains(menuItemRadio, clickItem).click();
|
||||
cy.get(triggerSelector).click();
|
||||
cy.get(`${menuItemRadio}[data-state="checked"]`)
|
||||
.invoke('text')
|
||||
.then((text: string) => {
|
||||
expect(text.trim()).to.equal(clickItem);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const checkMenuItemCheckbox: CheckMenuItemCheckboxFnType = (
|
||||
buttonText,
|
||||
items
|
||||
) => {
|
||||
items.forEach((item) => {
|
||||
cy.contains(button, buttonText).click();
|
||||
cy.contains(menuItemCheckbox, item.name).click();
|
||||
});
|
||||
|
||||
cy.contains(button, buttonText).click();
|
||||
cy.get(menuItemCheckbox)
|
||||
.should('have.length', items.length)
|
||||
.each(($el, index) => {
|
||||
const text = $el.text();
|
||||
expect(text).to.equal(items[index].name);
|
||||
});
|
||||
|
||||
items.forEach((item, index) => {
|
||||
cy.get(indicatorInfo)
|
||||
.eq(index + 1)
|
||||
.invoke('text')
|
||||
.should('eq', item.infoText);
|
||||
});
|
||||
|
||||
cy.contains(button, buttonText).click({ force: true });
|
||||
};
|
||||
|
||||
function getButtonSelectorByText(text: string): string {
|
||||
return `${button}[aria-haspopup="menu"]:contains(${text})`;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.setOnBoardingViewed();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Markets');
|
||||
});
|
||||
|
||||
describe(
|
||||
'chart display options',
|
||||
{ tags: '@smoke', testIsolation: true },
|
||||
() => {
|
||||
it('change time interval', () => {
|
||||
// 6004-CHAR-001
|
||||
checkMenuItems(
|
||||
getButtonSelectorByText('Interval:'),
|
||||
['1m', '5m', '15m', '1H', '6H', '1D'],
|
||||
'1m'
|
||||
);
|
||||
});
|
||||
|
||||
it('change display type', () => {
|
||||
// 6004-CHAR-002
|
||||
// 6004-CHAR-003
|
||||
checkMenuItems(
|
||||
'[aria-label$="chart icon"]',
|
||||
['Mountain', 'Candlestick', 'Line', 'OHLC'],
|
||||
'Mountain'
|
||||
);
|
||||
});
|
||||
|
||||
it('Overlays', () => {
|
||||
// 6004-CHAR-004
|
||||
// 6004-CHAR-008
|
||||
// 6004-CHAR-009
|
||||
// 6004-CHAR-034
|
||||
// 6004-CHAR-037
|
||||
// 6004-CHAR-039
|
||||
// 6004-CHAR-041
|
||||
|
||||
const overlayInfo: ItemInfoType[] = [
|
||||
{
|
||||
name: 'Bollinger bands',
|
||||
infoText: 'Bollinger: Upper 174.78590Lower 173.38014',
|
||||
},
|
||||
{
|
||||
name: 'Envelope',
|
||||
infoText: 'Envelope: Upper 191.29000Lower 156.51000',
|
||||
},
|
||||
{ name: 'EMA', infoText: 'EMA: 174.06793' },
|
||||
{ name: 'Moving average', infoText: 'Moving average: 174.08302' },
|
||||
{
|
||||
name: 'Price monitoring bounds',
|
||||
infoText:
|
||||
'Price Monitoring Bounds 1: Min 162.56291Max 182.96869Reference 172.47489',
|
||||
},
|
||||
];
|
||||
|
||||
checkMenuItemCheckbox('Overlays', overlayInfo);
|
||||
});
|
||||
|
||||
it('Studies', () => {
|
||||
// 6004-CHAR-005
|
||||
// 6004-CHAR-006
|
||||
// 6004-CHAR-007
|
||||
// 6004-CHAR-042
|
||||
// 6004-CHAR-045
|
||||
// 6004-CHAR-047
|
||||
// 6004-CHAR-049
|
||||
// 6004-CHAR-051
|
||||
const studyInfo: ItemInfoType[] = [
|
||||
{
|
||||
name: 'Eldar-ray',
|
||||
infoText: 'Eldar-ray: Bull -0.08376Bear -0.58376',
|
||||
},
|
||||
{ name: 'Force index', infoText: 'Force index: 987.48858' },
|
||||
{ name: 'MACD', infoText: 'MACD: S -0.06420D 0.00359MACD -0.06062' },
|
||||
{ name: 'RSI', infoText: 'RSI: 47.08648' },
|
||||
{ name: 'Volume', infoText: 'Volume: 55,000' },
|
||||
];
|
||||
cy.get(indicatorInfo).eq(1).realHover();
|
||||
cy.get('.chart__wrapper [data-testid="split-view-view"]')
|
||||
.last()
|
||||
.find('[role="button"][title="Close"]')
|
||||
.click({ force: true });
|
||||
cy.get(indicatorInfo).should('have.length', 1);
|
||||
|
||||
checkMenuItemCheckbox('Studies', studyInfo);
|
||||
});
|
||||
|
||||
it('price details', () => {
|
||||
// 6004-CHAR-010
|
||||
const expectedDateRegex = new RegExp(
|
||||
/^\d{2}:\d{2} \d{2} [A-Za-z]{3} \d{4}$/
|
||||
);
|
||||
const expectedOhlc = `O 173.60000H 174.00000L 173.50000C 173.90000Change −0.60000(−0.34%)`;
|
||||
cy.get(indicatorInfo)
|
||||
.eq(0)
|
||||
.invoke('text')
|
||||
.then((text) => {
|
||||
const actualDate = text.slice(0, -67);
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(actualDate);
|
||||
const actualOhlc = text.slice(-67);
|
||||
assert.isTrue(expectedDateRegex.test(actualDate));
|
||||
assert.strictEqual(actualOhlc, expectedOhlc);
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,110 @@
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { testOrderSubmission } from '../support/order-validation';
|
||||
import type { OrderSubmission } from '@vegaprotocol/wallet';
|
||||
import { createOrder } from '../support/create-order';
|
||||
|
||||
describe('must submit order', { tags: '@smoke' }, () => {
|
||||
// 7002-SORD-039
|
||||
before(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Markets');
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.setVegaWallet();
|
||||
});
|
||||
|
||||
it('successfully places market buy order', () => {
|
||||
// 7002-SORD-010
|
||||
// 0003-WTXN-012
|
||||
// 0003-WTXN-003
|
||||
cy.mockVegaWalletTransaction();
|
||||
const order: OrderSubmission = {
|
||||
marketId: 'market-0',
|
||||
type: Schema.OrderType.TYPE_MARKET,
|
||||
side: Schema.Side.SIDE_BUY,
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_FOK,
|
||||
postOnly: false,
|
||||
reduceOnly: false,
|
||||
size: '100',
|
||||
};
|
||||
createOrder(order);
|
||||
testOrderSubmission(order);
|
||||
});
|
||||
|
||||
it('successfully places market sell order', () => {
|
||||
cy.mockVegaWalletTransaction();
|
||||
const order: OrderSubmission = {
|
||||
marketId: 'market-0',
|
||||
type: Schema.OrderType.TYPE_MARKET,
|
||||
side: Schema.Side.SIDE_SELL,
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_IOC,
|
||||
size: '100',
|
||||
postOnly: false,
|
||||
reduceOnly: false,
|
||||
};
|
||||
createOrder(order);
|
||||
testOrderSubmission(order);
|
||||
});
|
||||
|
||||
it('successfully places limit buy order', () => {
|
||||
// 7002-SORD-017
|
||||
cy.mockVegaWalletTransaction();
|
||||
const order: OrderSubmission = {
|
||||
marketId: 'market-0',
|
||||
type: Schema.OrderType.TYPE_LIMIT,
|
||||
side: Schema.Side.SIDE_BUY,
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
size: '100',
|
||||
postOnly: false,
|
||||
reduceOnly: false,
|
||||
price: '200',
|
||||
};
|
||||
createOrder(order);
|
||||
testOrderSubmission(order, { price: '20000000' });
|
||||
});
|
||||
|
||||
it('successfully places limit sell order', () => {
|
||||
cy.mockVegaWalletTransaction();
|
||||
const order: OrderSubmission = {
|
||||
marketId: 'market-0',
|
||||
type: Schema.OrderType.TYPE_LIMIT,
|
||||
side: Schema.Side.SIDE_SELL,
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GFN,
|
||||
size: '100',
|
||||
postOnly: false,
|
||||
reduceOnly: false,
|
||||
price: '50000',
|
||||
};
|
||||
createOrder(order);
|
||||
testOrderSubmission(order, { price: '5000000000' });
|
||||
});
|
||||
|
||||
it('successfully places GTT limit buy order', () => {
|
||||
cy.mockVegaWalletTransaction();
|
||||
const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000);
|
||||
const order: OrderSubmission = {
|
||||
marketId: 'market-0',
|
||||
type: Schema.OrderType.TYPE_LIMIT,
|
||||
side: Schema.Side.SIDE_SELL,
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTT,
|
||||
size: '100',
|
||||
price: '1.00',
|
||||
expiresAt: expiresAt.toISOString().substring(0, 16),
|
||||
postOnly: false,
|
||||
reduceOnly: false,
|
||||
};
|
||||
|
||||
createOrder(order);
|
||||
testOrderSubmission(order, {
|
||||
price: '100000',
|
||||
expiresAt:
|
||||
new Date(order.expiresAt as string).getTime().toString() + '000000',
|
||||
postOnly: false,
|
||||
reduceOnly: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -23,7 +23,7 @@ describe('deal ticket basics', { tags: '@smoke' }, () => {
|
||||
// 0003-WTXN-001
|
||||
cy.getByTestId('connect-vega-wallet'); // Not connected
|
||||
cy.getByTestId(placeOrderBtn).should('exist');
|
||||
cy.getByTestId('order-connect-wallet').should('exist');
|
||||
cy.getByTestId('get-started-button').should('exist');
|
||||
});
|
||||
|
||||
it('must be able to select order direction - long/short', function () {
|
||||
@@ -44,7 +44,7 @@ describe('deal ticket basics', { tags: '@smoke' }, () => {
|
||||
mockConnectWallet();
|
||||
cy.getByTestId(toggleLimit).click();
|
||||
cy.getByTestId(orderPriceField).clear().type('101');
|
||||
cy.getByTestId('order-connect-wallet').click();
|
||||
cy.getByTestId('get-started-button').click();
|
||||
cy.getByTestId('dialog-content').should('be.visible');
|
||||
cy.getByTestId('connectors-list')
|
||||
.find('[data-testid="connector-jsonRpc"]')
|
||||
@@ -54,15 +54,6 @@ describe('deal ticket basics', { tags: '@smoke' }, () => {
|
||||
cy.getByTestId(toggleLimit).next('input').should('be.checked');
|
||||
cy.getByTestId(orderPriceField).should('have.value', '101');
|
||||
});
|
||||
|
||||
it('sidebar should be open after reload', () => {
|
||||
cy.mockTradingPage();
|
||||
cy.getByTestId('deal-ticket-form').should('be.visible');
|
||||
cy.getByTestId('Order').click();
|
||||
cy.getByTestId('deal-ticket-form').should('not.exist');
|
||||
cy.reload();
|
||||
cy.getByTestId('deal-ticket-form').should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
describe(
|
||||
|
||||
@@ -64,7 +64,7 @@ describe('deal ticker order validation', { tags: '@smoke' }, () => {
|
||||
cy.getByTestId(orderSizeField).clear().type('1');
|
||||
cy.getByTestId(orderPriceField).clear().type('1.123456');
|
||||
cy.getByTestId(placeOrderBtn).click();
|
||||
cy.getByTestId('deal-ticket-error-message-price').should(
|
||||
cy.getByTestId('deal-ticket-error-message-price-limit').should(
|
||||
'have.text',
|
||||
'Price accepts up to 5 decimal places'
|
||||
);
|
||||
@@ -87,7 +87,7 @@ describe('deal ticker order validation', { tags: '@smoke' }, () => {
|
||||
cy.getByTestId(orderSizeField).clear().type('1.234');
|
||||
// 7002-SORD-060
|
||||
cy.getByTestId(placeOrderBtn).should('be.enabled');
|
||||
cy.getByTestId('deal-ticket-error-message-size').should(
|
||||
cy.getByTestId('deal-ticket-error-message-size-market').should(
|
||||
'have.text',
|
||||
'Size must be whole numbers for this market'
|
||||
);
|
||||
@@ -96,7 +96,7 @@ describe('deal ticker order validation', { tags: '@smoke' }, () => {
|
||||
it('must warn if order size is set to 0', function () {
|
||||
cy.getByTestId(orderSizeField).clear().type('0');
|
||||
cy.getByTestId(placeOrderBtn).should('be.enabled');
|
||||
cy.getByTestId('deal-ticket-error-message-size').should(
|
||||
cy.getByTestId('deal-ticket-error-message-size-market').should(
|
||||
'have.text',
|
||||
'Size cannot be lower than 1'
|
||||
);
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
import { aliasGQLQuery } from '@vegaprotocol/cypress';
|
||||
import {
|
||||
accountsQuery,
|
||||
amendGeneralAccountBalance,
|
||||
amendMarginAccountBalance,
|
||||
} from '@vegaprotocol/mock';
|
||||
|
||||
describe.skip(
|
||||
'account validation',
|
||||
{ tags: '@regression', testIsolation: true },
|
||||
() => {
|
||||
describe('zero balance error', () => {
|
||||
beforeEach(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage();
|
||||
let accounts = accountsQuery();
|
||||
accounts = amendMarginAccountBalance(accounts, 'market-0', '1000');
|
||||
accounts = amendGeneralAccountBalance(accounts, 'market-0', '0');
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(req, 'Accounts', accounts);
|
||||
});
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Markets');
|
||||
});
|
||||
|
||||
it('should show an error if your balance is zero', () => {
|
||||
const accounts = accountsQuery();
|
||||
amendMarginAccountBalance(accounts, 'market-0', '0');
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(req, 'Accounts', accounts);
|
||||
});
|
||||
// 7002-SORD-060
|
||||
cy.getByTestId('place-order').should('be.enabled');
|
||||
// 7002-SORD-003
|
||||
cy.getByTestId('deal-ticket-error-message-zero-balance').should(
|
||||
'have.text',
|
||||
'You need ' +
|
||||
'tDAI' +
|
||||
' in your wallet to trade in this market. See all your collateral.Make a deposit'
|
||||
);
|
||||
cy.getByTestId('deal-ticket-deposit-dialog-button').should('exist');
|
||||
});
|
||||
});
|
||||
|
||||
describe('not enough balance warning', () => {
|
||||
beforeEach(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage();
|
||||
let accounts = accountsQuery();
|
||||
accounts = amendMarginAccountBalance(accounts, 'market-0', '1000');
|
||||
accounts = amendGeneralAccountBalance(accounts, 'market-0', '1');
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(req, 'Accounts', accounts);
|
||||
});
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Markets');
|
||||
|
||||
cy.get('[data-testid="deal-ticket-form"]').then(($form) => {
|
||||
if (!$form.length) {
|
||||
cy.getByTestId('Order').click();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should display info and button for deposit', () => {
|
||||
// 7002-SORD-003
|
||||
|
||||
// warning should show immediately
|
||||
cy.getByTestId('deal-ticket-warning-margin').should(
|
||||
'contain.text',
|
||||
'You may not have enough margin available to open this position'
|
||||
);
|
||||
cy.getByTestId('deal-ticket-warning-margin').should(
|
||||
'contain.text',
|
||||
'You may not have enough margin available to open this position. 5.00 tDAI is currently required. You have only 0.01001 tDAI available.'
|
||||
);
|
||||
cy.getByTestId('deal-ticket-deposit-dialog-button').click();
|
||||
cy.getByTestId('sidebar-content')
|
||||
.find('h2')
|
||||
.eq(0)
|
||||
.should('have.text', 'Deposit');
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
import type { OrderSubmission } from '@vegaprotocol/wallet';
|
||||
import { createOrder } from '../support/create-order';
|
||||
|
||||
describe.skip(
|
||||
describe(
|
||||
'account validation',
|
||||
{ tags: '@regression', testIsolation: true },
|
||||
() => {
|
||||
|
||||
@@ -120,9 +120,7 @@ describe('orders list', { tags: '@smoke', testIsolation: true }, () => {
|
||||
cy.getByTestId('All').click();
|
||||
|
||||
cy.getByTestId('tab-orders')
|
||||
.get(
|
||||
`.ag-center-cols-container [col-id='${orderSymbol}'] [data-testid="market-code"]`
|
||||
)
|
||||
.get(`.ag-center-cols-container [col-id='${orderSymbol}']`)
|
||||
.should('have.length.at.least', expectedOrderList.length)
|
||||
.then(($symbols) => {
|
||||
const symbolNames: string[] = [];
|
||||
@@ -222,17 +220,12 @@ describe('subscribe orders', { tags: '@smoke' }, () => {
|
||||
|
||||
it('must see a filled order', () => {
|
||||
// 7002-SORD-046
|
||||
// 7003-MORD-020
|
||||
// NOT COVERED: Must be able to see/link to all trades that were created from this order
|
||||
updateOrder({
|
||||
id: orderId,
|
||||
status: Schema.OrderStatus.STATUS_FILLED,
|
||||
});
|
||||
cy.getByTestId(`order-status-${orderId}`).should('have.text', 'Filled');
|
||||
cy.get('[col-id="market.tradableInstrument.instrument.code"]').contains(
|
||||
'[title="Future"]',
|
||||
'Futr'
|
||||
);
|
||||
});
|
||||
|
||||
it('must see a rejected order', () => {
|
||||
@@ -452,7 +445,8 @@ describe('amend and cancel order', { tags: '@smoke' }, () => {
|
||||
liquidityProvisionId: null,
|
||||
});
|
||||
cy.get(`[row-id=${orderId}]`)
|
||||
.find('[data-testid="icon-edit"]')
|
||||
.find('[data-testid="edit"]')
|
||||
.should('have.text', 'Edit')
|
||||
.then(($btn) => {
|
||||
cy.wrap($btn).click();
|
||||
cy.getByTestId('dialog-title').should('have.text', 'Edit order');
|
||||
@@ -480,7 +474,8 @@ describe('amend and cancel order', { tags: '@smoke' }, () => {
|
||||
liquidityProvisionId: null,
|
||||
});
|
||||
cy.get(`[row-id=${orderId}]`)
|
||||
.find(`[data-testid="icon-cross"]`)
|
||||
.find(`[data-testid="cancel"]`)
|
||||
.should('have.text', 'Cancel')
|
||||
.then(($btn) => {
|
||||
cy.wrap($btn).click({ force: true });
|
||||
const order: OrderCancellation = {
|
||||
@@ -517,7 +512,8 @@ describe('amend and cancel order', { tags: '@smoke' }, () => {
|
||||
liquidityProvisionId: null,
|
||||
});
|
||||
cy.get(`[row-id=${orderId}]`)
|
||||
.find('[data-testid="icon-edit"]')
|
||||
.find('[data-testid="edit"]')
|
||||
.should('have.text', 'Edit')
|
||||
.then(($btn) => {
|
||||
cy.wrap($btn).click({ force: true });
|
||||
cy.getByTestId('dialog-title').should('have.text', 'Edit order');
|
||||
|
||||
@@ -0,0 +1,371 @@
|
||||
import { checkSorting, aliasGQLQuery } from '@vegaprotocol/cypress';
|
||||
import { marketsDataQuery } from '@vegaprotocol/mock';
|
||||
import { positionsQuery } from '@vegaprotocol/mock';
|
||||
|
||||
// #region consts
|
||||
const closePosition = 'close-position';
|
||||
const dialogCloseX = 'dialog-close';
|
||||
const dialogContent = 'dialog-content';
|
||||
const dropDownMenu = 'dropdown-menu';
|
||||
const marketActionsContent = 'position-actions-content';
|
||||
const positions = 'Positions';
|
||||
const tabPositions = 'tab-positions';
|
||||
const toastContent = 'toast-content';
|
||||
const tooltipContent = 'tooltip-content';
|
||||
// #endregion
|
||||
|
||||
describe('positions', { tags: '@smoke', testIsolation: true }, () => {
|
||||
beforeEach(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.setVegaWallet();
|
||||
});
|
||||
it('renders positions on trading page', () => {
|
||||
visitAndClickPositions();
|
||||
// 7004-POSI-001
|
||||
// 7004-POSI-002
|
||||
validatePositionsDisplayed();
|
||||
});
|
||||
|
||||
// TODO: move this to sim, its flakey
|
||||
it.skip('renders positions on portfolio page', () => {
|
||||
cy.mockGQL((req) => {
|
||||
const positions = positionsQuery();
|
||||
if (positions.positions?.edges) {
|
||||
positions.positions.edges.push(
|
||||
...positions.positions.edges.map((edge) => ({
|
||||
...edge,
|
||||
node: {
|
||||
...edge.node,
|
||||
party: {
|
||||
...edge.node.party,
|
||||
id: 'vega-1',
|
||||
},
|
||||
},
|
||||
}))
|
||||
);
|
||||
}
|
||||
aliasGQLQuery(req, 'Positions', positions);
|
||||
});
|
||||
visitAndClickPositions();
|
||||
// 7004-POSI-001
|
||||
// 7004-POSI-002
|
||||
validatePositionsDisplayed(true);
|
||||
});
|
||||
|
||||
it('Close my position', () => {
|
||||
visitAndClickPositions();
|
||||
cy.getByTestId(closePosition).first().click();
|
||||
// 7004-POSI-010
|
||||
cy.getByTestId(toastContent).should(
|
||||
'contain.text',
|
||||
'Awaiting confirmation'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('positions', { tags: '@regression', testIsolation: true }, () => {
|
||||
beforeEach(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.setVegaWallet();
|
||||
});
|
||||
|
||||
it('rows should be displayed despite errors', () => {
|
||||
const errors = [
|
||||
{
|
||||
message:
|
||||
'no market data for market: 9c55fb644c6f7de5422d40d691a62bffd5898384c70135bab29ba1e3e2e5280a',
|
||||
path: ['marketsConnection', 'edges'],
|
||||
extensions: {
|
||||
code: 13,
|
||||
type: 'Internal',
|
||||
},
|
||||
},
|
||||
];
|
||||
const marketData = marketsDataQuery();
|
||||
const edges = marketData.marketsConnection?.edges.map((market) => {
|
||||
const replace =
|
||||
market.node.data?.market.id === 'market-2' ? null : market.node.data;
|
||||
return { ...market, node: { ...market.node, data: replace } };
|
||||
});
|
||||
const overrides = {
|
||||
...marketData,
|
||||
marketsConnection: { ...marketData.marketsConnection, edges },
|
||||
};
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(req, 'MarketsData', overrides, errors);
|
||||
});
|
||||
cy.visit('/#/markets/market-0');
|
||||
const emptyCells = [
|
||||
'notional',
|
||||
'markPrice',
|
||||
'currentLeverage',
|
||||
'averageEntryPrice',
|
||||
];
|
||||
cy.getByTestId(tabPositions)
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.get(
|
||||
'[row-id="02eceaba4df2bef76ea10caf728d8a099a2aa846cced25737cccaa9812342f65-market-2"]'
|
||||
)
|
||||
.eq(0)
|
||||
.within(() => {
|
||||
emptyCells.forEach((cell) => {
|
||||
cy.get(`[col-id="${cell}"]`).should('contain.text', '-');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('error message should be displayed', () => {
|
||||
const errors = [
|
||||
{
|
||||
message:
|
||||
'no market data for asset: 9c55fb644c6f7de5422d40d691a62bffd5898384c70135bab29ba1e3e2e5280a',
|
||||
path: ['assets', 'edges'],
|
||||
extensions: {
|
||||
code: 13,
|
||||
type: 'Internal',
|
||||
},
|
||||
},
|
||||
];
|
||||
const overrides = {
|
||||
marketsConnection: { edges: [] },
|
||||
};
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(req, 'MarketsData', overrides, errors);
|
||||
});
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.getByTestId(tabPositions).contains('no market data');
|
||||
});
|
||||
|
||||
it('sorting by Market', () => {
|
||||
visitAndClickPositions();
|
||||
const marketsSortedDefault = [
|
||||
'AAPL.MF21',
|
||||
'BTCUSD.MF21',
|
||||
'ETHBTC.QM21',
|
||||
'SOLUSD',
|
||||
];
|
||||
const marketsSortedAsc = [
|
||||
'AAPL.MF21',
|
||||
'BTCUSD.MF21',
|
||||
'ETHBTC.QM21',
|
||||
'SOLUSD',
|
||||
];
|
||||
const marketsSortedDesc = [
|
||||
'SOLUSD',
|
||||
'ETHBTC.QM21',
|
||||
'BTCUSD.MF21',
|
||||
'AAPL.MF21',
|
||||
];
|
||||
cy.getByTestId(positions).click();
|
||||
// 7004-POSI-003
|
||||
checkSorting(
|
||||
'marketName',
|
||||
marketsSortedDefault,
|
||||
marketsSortedAsc,
|
||||
marketsSortedDesc
|
||||
);
|
||||
});
|
||||
|
||||
// let elementWidth: number;
|
||||
|
||||
it('Resize column', () => {
|
||||
visitAndClickPositions();
|
||||
cy.get('.ag-overlay-loading-wrapper').should('not.be.visible');
|
||||
cy.get('.ag-header-container').within(() => {
|
||||
cy.get(`[col-id="marketName"]`)
|
||||
.find('.ag-header-cell-resize')
|
||||
.realMouseDown()
|
||||
.realMouseMove(250, 0)
|
||||
.realMouseUp();
|
||||
});
|
||||
|
||||
// 7004-POSI-006
|
||||
cy.get(`[col-id="marketName"]`)
|
||||
.invoke('width')
|
||||
.should('be.greaterThan', 250);
|
||||
});
|
||||
|
||||
// This test depends on the previous one
|
||||
it('Has persisted column widths', () => {
|
||||
const width = 400;
|
||||
|
||||
cy.window().then((win) => {
|
||||
win.localStorage.setItem(
|
||||
'vega_positions_store',
|
||||
JSON.stringify({
|
||||
state: {
|
||||
gridStore: {
|
||||
columnState: [{ colId: 'marketName', width }],
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
visitAndClickPositions();
|
||||
|
||||
// 7004-POSI-012
|
||||
cy.get('.ag-center-cols-container .ag-row')
|
||||
.first()
|
||||
.find('[col-id="marketName"]')
|
||||
.invoke('outerWidth')
|
||||
.should('equal', width);
|
||||
});
|
||||
|
||||
it('Scroll horizontally', () => {
|
||||
visitAndClickPositions();
|
||||
|
||||
cy.get('.ag-header-container').within(() => {
|
||||
cy.get(`[col-id="marketName"]`)
|
||||
.find('.ag-header-cell-resize')
|
||||
.realMouseDown()
|
||||
.realMouseMove(400, 0)
|
||||
.realMouseUp();
|
||||
});
|
||||
cy.get('[col-id="marketName"]').should('be.visible');
|
||||
cy.get('.ag-body-horizontal-scroll-viewport').realMouseWheel({
|
||||
deltaX: 500,
|
||||
});
|
||||
// 7004-POSI-004
|
||||
cy.get('[col-id="unrealisedPNL"]').should('be.visible');
|
||||
});
|
||||
|
||||
it('Drag and drop columns', () => {
|
||||
visitAndClickPositions();
|
||||
cy.get('.ag-overlay-loading-wrapper').should('not.be.visible');
|
||||
cy.get('[col-id="marketName"]')
|
||||
.realMouseDown()
|
||||
.realMouseMove(700, 15)
|
||||
.realMouseUp();
|
||||
|
||||
// 7004-POSI-005
|
||||
cy.get('[col-id="marketName"]').should(($element) => {
|
||||
const attributeValue = $element.attr('aria-colindex');
|
||||
expect(attributeValue).not.to.equal('1');
|
||||
});
|
||||
});
|
||||
|
||||
it('I can see warnings', () => {
|
||||
visitAndClickPositions();
|
||||
|
||||
cy.get('[col-id="openVolume"]')
|
||||
.eq(3)
|
||||
.within(() => {
|
||||
cy.get('[aria-label="warning-sign icon"]')
|
||||
.should('be.visible')
|
||||
.realHover();
|
||||
});
|
||||
// 7004-POSI-011
|
||||
cy.getByTestId(tooltipContent).should('be.visible');
|
||||
});
|
||||
|
||||
it('Positive and Negative color change', () => {
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.getByTestId(positions).click();
|
||||
// 7004-POSI-007
|
||||
cy.get('.ag-center-cols-container').within(() => {
|
||||
assertPNLColor(
|
||||
'[col-id="realisedPNL"]',
|
||||
'text-market-green-600',
|
||||
'text-market-red'
|
||||
);
|
||||
});
|
||||
cy.get('.ag-center-cols-container').within(() => {
|
||||
assertPNLColor(
|
||||
'[col-id="unrealisedPNL"]',
|
||||
'text-market-green-600',
|
||||
'text-market-red'
|
||||
);
|
||||
});
|
||||
cy.get('.ag-center-cols-container').within(() => {
|
||||
assertPNLColor(
|
||||
'[col-id="openVolume"]',
|
||||
'text-market-green-600',
|
||||
'text-market-red'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('View settlement asset', () => {
|
||||
visitAndClickPositions();
|
||||
cy.get('[col-id="asset"]')
|
||||
.eq(3)
|
||||
.within(() => {
|
||||
cy.get('button[type="button"]').click();
|
||||
});
|
||||
// 7004-POSI-008
|
||||
cy.getByTestId(dialogContent).should('be.visible');
|
||||
cy.getByTestId(dialogCloseX).click();
|
||||
cy.getByTestId(dropDownMenu).first().click();
|
||||
cy.getByTestId(marketActionsContent).click();
|
||||
// 7004-POSI-009
|
||||
cy.getByTestId(dialogContent).should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
function validatePositionsDisplayed(multiKey = false) {
|
||||
cy.getByTestId('tab-positions').should('be.visible');
|
||||
cy.getByTestId('tab-positions')
|
||||
.get('.ag-center-cols-container .ag-row')
|
||||
.eq(multiKey ? 3 : 1)
|
||||
.within(() => {
|
||||
cy.get('[col-id="marketName"]')
|
||||
.should('be.visible')
|
||||
.invoke('text')
|
||||
.should('not.be.empty');
|
||||
|
||||
cy.get('[col-id="openVolume"]').should('not.be.empty');
|
||||
|
||||
// includes average entry price, mark price, realised PNL & leverage
|
||||
cy.getByTestId('flash-cell').should('not.be.empty');
|
||||
|
||||
if (!multiKey) {
|
||||
cy.get('[col-id="currentLeverage"]').should('contain.text', '2,767.3');
|
||||
cy.get('[col-id="marginAccountBalance"]') // margin allocated
|
||||
.should('contain.text', '0.01');
|
||||
}
|
||||
|
||||
cy.get('[col-id="unrealisedPNL"]').should('not.be.empty');
|
||||
cy.get('[col-id="notional"]').should('contain.text', '276,761.40348'); // Total tDAI position
|
||||
cy.get('[col-id="realisedPNL"]').should('contain.text', '2.30'); // Total Realised PNL
|
||||
cy.get('[col-id="unrealisedPNL"]').should('contain.text', '8.95'); // Total Unrealised PNL
|
||||
});
|
||||
|
||||
cy.get('.ag-header-row [col-id="notional"]')
|
||||
.should('contain.text', 'Notional')
|
||||
.realHover();
|
||||
cy.get('.ag-popup').should('contain.text', 'Mark price x open volume');
|
||||
|
||||
cy.getByTestId('close-position').should('be.visible').and('have.length', 3);
|
||||
}
|
||||
|
||||
function assertPNLColor(
|
||||
pnlSelector: string,
|
||||
positiveClass: string,
|
||||
negativeClass: string
|
||||
) {
|
||||
cy.get(pnlSelector).each(($el) => {
|
||||
const value = parseFloat($el.text());
|
||||
|
||||
if (value > 0) {
|
||||
cy.wrap($el).invoke('attr', 'class').should('contain', positiveClass);
|
||||
} else if (value < 0) {
|
||||
cy.wrap($el).invoke('attr', 'class').should('contain', negativeClass);
|
||||
} else if (value == 0) {
|
||||
cy.wrap($el)
|
||||
.invoke('attr', 'class')
|
||||
.should('not.contain', negativeClass, positiveClass);
|
||||
} else {
|
||||
throw new Error('Unexpected value');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function visitAndClickPositions() {
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.getByTestId(positions).click();
|
||||
}
|
||||
+2
-4
@@ -12,13 +12,11 @@ NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/main/announcements.json
|
||||
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
||||
|
||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet
|
||||
|
||||
# Cosmic elevator flags
|
||||
NX_SUCCESSOR_MARKETS=true
|
||||
NX_STOP_ORDERS=true
|
||||
# NX_ICEBERG_ORDERS
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
|
||||
NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.rocks
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket
|
||||
|
||||
@@ -12,8 +12,6 @@ NX_VEGA_WALLET_URL=http://localhost:1789
|
||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
|
||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet
|
||||
|
||||
NX_ETH_LOCAL_PROVIDER_URL=http://localhost:8545/
|
||||
NX_ETH_WALLET_MNEMONIC="ozone access unlock valid olympic save include omit supply green clown session"
|
||||
@@ -22,7 +20,4 @@ NX_ETH_WALLET_MNEMONIC="ozone access unlock valid olympic save include omit supp
|
||||
NX_SUCCESSOR_MARKETS=false
|
||||
NX_STOP_ORDERS=false
|
||||
# NX_ICEBERG_ORDERS
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
|
||||
NX_TENDERMINT_URL=http://localhost:26617
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
@@ -13,14 +13,9 @@ NX_VEGA_DOCS_URL=#
|
||||
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega-dev-releases/releases
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
|
||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet
|
||||
|
||||
# Cosmic elevator flags
|
||||
NX_SUCCESSOR_MARKETS=true
|
||||
NX_STOP_ORDERS=true
|
||||
# NX_ICEBERG_ORDERS
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
|
||||
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
@@ -13,8 +13,6 @@ NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
|
||||
NX_VEGA_CONSOLE_URL=https://console.vega.xyz
|
||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-mainnet/codfcglpplgmmlokgilfkpcjnmkbfiel
|
||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet-mainnet
|
||||
# TAG name of the current app version - TODO: bump to the latest upon release
|
||||
NX_APP_VERSION=v0.20.21-core-0.71.6
|
||||
|
||||
@@ -23,6 +21,3 @@ NX_SUCCESSOR_MARKETS=false
|
||||
NX_STOP_ORDERS=false
|
||||
# NX_ICEBERG_ORDERS
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
|
||||
NX_TENDERMINT_URL=https://be.vega.community
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
|
||||
|
||||
@@ -13,8 +13,6 @@ NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
|
||||
NX_VEGA_CONSOLE_URL=https://console.mainnet-mirror.vega.rocks
|
||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-mainnet/codfcglpplgmmlokgilfkpcjnmkbfiel
|
||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet-mainnet
|
||||
# TAG name of the current app version - TODO: bump to the latest upon release
|
||||
NX_APP_VERSION=v0.20.19-core-0.71.6
|
||||
|
||||
@@ -22,7 +20,4 @@ NX_APP_VERSION=v0.20.19-core-0.71.6
|
||||
NX_SUCCESSOR_MARKETS=false
|
||||
NX_STOP_ORDERS=false
|
||||
# NX_ICEBERG_ORDERS
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
|
||||
NX_TENDERMINT_URL=https://be.mainnet-mirror.vega.rocks
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
@@ -13,11 +13,9 @@ NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
|
||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet
|
||||
|
||||
# Cosmic elevator flags
|
||||
NX_SUCCESSOR_MARKETS=true
|
||||
NX_STOP_ORDERS=true
|
||||
# NX_ICEBERG_ORDERS
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
@@ -14,14 +14,9 @@ NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
|
||||
NX_VEGA_CONSOLE_URL=https://console.fairground.wtf
|
||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet
|
||||
|
||||
# Cosmic elevator flags
|
||||
NX_SUCCESSOR_MARKETS=true
|
||||
NX_STOP_ORDERS=true
|
||||
NX_ICEBERG_ORDERS=true
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
|
||||
NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
@@ -15,14 +15,8 @@ NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/annou
|
||||
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
|
||||
NX_VEGA_CONSOLE_URL=https://trading.validators-testnet.vega.rocks
|
||||
|
||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet
|
||||
|
||||
# Cosmic elevator flags
|
||||
NX_SUCCESSOR_MARKETS=false
|
||||
NX_STOP_ORDERS=false
|
||||
# NX_ICEBERG_ORDERS
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
|
||||
NX_TENDERMINT_URL=https://tm.be.validators-testnet.vega.rocks
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.xyz/websocket
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
@@ -94,11 +94,7 @@ const MainGrid = memo(
|
||||
>
|
||||
<TradeGridChild>
|
||||
<Tabs storageKey="console-trade-grid-bottom">
|
||||
<Tab
|
||||
id="positions"
|
||||
name={t('Positions')}
|
||||
menu={<TradingViews.positions.menu />}
|
||||
>
|
||||
<Tab id="positions" name={t('Positions')}>
|
||||
<TradingViews.positions.component />
|
||||
</Tab>
|
||||
<Tab
|
||||
|
||||
@@ -17,7 +17,6 @@ import type { OrderContainerProps } from '../../components/orders-container';
|
||||
import { OrdersContainer } from '../../components/orders-container';
|
||||
import { StopOrdersContainer } from '../../components/stop-orders-container';
|
||||
import { AccountsMenu } from '../../components/accounts-menu';
|
||||
import { PositionsMenu } from '../../components/positions-menu';
|
||||
|
||||
type MarketDependantView =
|
||||
| typeof CandlesChartContainer
|
||||
@@ -58,11 +57,7 @@ export const TradingViews = {
|
||||
label: 'Trades',
|
||||
component: requiresMarket(TradesContainer),
|
||||
},
|
||||
positions: {
|
||||
label: 'Positions',
|
||||
component: PositionsContainer,
|
||||
menu: PositionsMenu,
|
||||
},
|
||||
positions: { label: 'Positions', component: PositionsContainer },
|
||||
activeOrders: {
|
||||
label: 'Active',
|
||||
component: (props: OrderContainerProps) => (
|
||||
|
||||
@@ -214,6 +214,7 @@ describe('Closed', () => {
|
||||
</MemoryRouter>
|
||||
);
|
||||
});
|
||||
// screen.debug(document, Infinity);
|
||||
|
||||
const headers = screen.getAllByRole('columnheader');
|
||||
const expectedHeaders = [
|
||||
@@ -433,7 +434,7 @@ describe('Closed', () => {
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
screen.getByRole('button', { name: /^SuccessorCode/ })
|
||||
screen.getByRole('button', { name: 'SuccessorCode' })
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
expect(
|
||||
@@ -442,16 +443,6 @@ describe('Closed', () => {
|
||||
element.getAttribute('col-id') === 'successorMarket',
|
||||
})
|
||||
).toBeInTheDocument();
|
||||
screen
|
||||
.getAllByRole('gridcell', {
|
||||
name: (_name, element) =>
|
||||
element.getAttribute('col-id') === 'successorMarket',
|
||||
})
|
||||
.forEach((element) => {
|
||||
expect(element.querySelector('[title="Future"]')?.textContent).toEqual(
|
||||
'Futr'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('feature flag should hide successors', async () => {
|
||||
|
||||
@@ -4,11 +4,7 @@ import type {
|
||||
VegaICellRendererParams,
|
||||
VegaValueFormatterParams,
|
||||
} from '@vegaprotocol/datagrid';
|
||||
import {
|
||||
AgGridLazy as AgGrid,
|
||||
COL_DEFS,
|
||||
MarketNameCell,
|
||||
} from '@vegaprotocol/datagrid';
|
||||
import { AgGridLazy as AgGrid, COL_DEFS } from '@vegaprotocol/datagrid';
|
||||
import { useMemo } from 'react';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { MarketState, MarketStateMapping } from '@vegaprotocol/types';
|
||||
@@ -51,7 +47,6 @@ interface Row {
|
||||
setlementDataSourceFilter: DataSourceFilterFragment | undefined;
|
||||
tradingTerminationOracleId: string;
|
||||
settlementAsset: SettlementAsset;
|
||||
productType: string;
|
||||
}
|
||||
|
||||
export const Closed = () => {
|
||||
@@ -95,7 +90,6 @@ export const Closed = () => {
|
||||
tradingTerminationOracleId:
|
||||
instrument.product.dataSourceSpecForTradingTermination.id,
|
||||
settlementAsset: instrument.product.settlementAsset,
|
||||
productType: instrument.product.__typename || '',
|
||||
};
|
||||
|
||||
return row;
|
||||
@@ -121,7 +115,16 @@ const ClosedMarketsDataGrid = ({
|
||||
{
|
||||
headerName: t('Market'),
|
||||
field: 'code',
|
||||
cellRenderer: 'MarketNameCell',
|
||||
cellRenderer: ({
|
||||
value,
|
||||
data,
|
||||
}: VegaICellRendererParams<Row, 'code'>) => {
|
||||
return (
|
||||
<span data-testid="market-code" data-market-id={data?.id}>
|
||||
{value}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
headerName: t('Description'),
|
||||
@@ -276,7 +279,7 @@ const ClosedMarketsDataGrid = ({
|
||||
rowData={rowData}
|
||||
columnDefs={colDefs}
|
||||
getRowId={({ data }) => data.id}
|
||||
components={{ SuccessorMarketRenderer, MarketNameCell }}
|
||||
components={{ SuccessorMarketRenderer }}
|
||||
overlayNoRowsTemplate={error ? error.message : t('No markets')}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,190 +0,0 @@
|
||||
import { render, screen, act, waitFor } from '@testing-library/react';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import type { Market } from '@vegaprotocol/markets';
|
||||
import { SuccessorMarketRenderer } from './successor-market-cell';
|
||||
import {
|
||||
MarketsDocument,
|
||||
SuccessorMarketIdsDocument,
|
||||
} from '@vegaprotocol/markets';
|
||||
import { createMarketFragment } from '@vegaprotocol/mock';
|
||||
|
||||
const mockSuccessorsQuery = [
|
||||
{
|
||||
id: 'market1',
|
||||
parentMarketID: 'parentMarket1',
|
||||
successorMarketID: 'successorMarket1',
|
||||
},
|
||||
{ id: 'market2', parentMarketID: 'parentMarket2' },
|
||||
{ id: 'market3', successorMarketID: 'successorMarket3' },
|
||||
];
|
||||
const parentMarket1 = {
|
||||
id: 'parentMarket1',
|
||||
tradableInstrument: {
|
||||
instrument: { code: 'code parent 1', id: '1' },
|
||||
},
|
||||
} as unknown as Market;
|
||||
const successorMarket1 = {
|
||||
id: 'successorMarket1',
|
||||
tradableInstrument: {
|
||||
instrument: { code: 'code successor 1', id: '2' },
|
||||
},
|
||||
} as unknown as Market;
|
||||
const parentMarket2 = {
|
||||
id: 'parentMarket2',
|
||||
tradableInstrument: {
|
||||
instrument: { code: 'code parent 2', id: '3' },
|
||||
},
|
||||
} as unknown as Market;
|
||||
const successorMarket3 = {
|
||||
id: 'successorMarket3',
|
||||
tradableInstrument: {
|
||||
instrument: { code: 'code successor 3', id: '4' },
|
||||
},
|
||||
} as unknown as Market;
|
||||
|
||||
const mockMarkets = [
|
||||
parentMarket1,
|
||||
successorMarket1,
|
||||
parentMarket2,
|
||||
successorMarket3,
|
||||
];
|
||||
|
||||
const mockClickHandler = jest.fn();
|
||||
jest.mock('../../lib/hooks/use-market-click-handler', () => ({
|
||||
useMarketClickHandler: jest.fn().mockImplementation(() => mockClickHandler),
|
||||
}));
|
||||
|
||||
const marketMock = {
|
||||
request: {
|
||||
query: MarketsDocument,
|
||||
variables: undefined,
|
||||
},
|
||||
result: {
|
||||
data: {
|
||||
marketsConnection: {
|
||||
edges: mockMarkets.map((item) => ({
|
||||
node: {
|
||||
...createMarketFragment(item),
|
||||
},
|
||||
})),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const successorMock = {
|
||||
request: {
|
||||
query: SuccessorMarketIdsDocument,
|
||||
},
|
||||
result: {
|
||||
data: {
|
||||
marketsConnection: {
|
||||
edges: mockSuccessorsQuery.map((item) => ({
|
||||
node: {
|
||||
...item,
|
||||
},
|
||||
})),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const mocks = [marketMock, successorMock];
|
||||
|
||||
describe('SuccessorMarketRenderer', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
it('should properly rendered successor market', async () => {
|
||||
const successorValue = 'market1';
|
||||
render(
|
||||
<MockedProvider mocks={[...mocks]}>
|
||||
<SuccessorMarketRenderer value={successorValue} />
|
||||
</MockedProvider>
|
||||
);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('market-code')).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.getByText('code successor 1')).toBeInTheDocument();
|
||||
expect(screen.getByText('Futr')).toBeInTheDocument();
|
||||
|
||||
await userEvent.click(screen.getByRole('button'));
|
||||
await waitFor(() => {
|
||||
expect(mockClickHandler).toHaveBeenCalledWith('successorMarket1', false);
|
||||
});
|
||||
});
|
||||
it('should properly rendered parent market', async () => {
|
||||
const successorValue = 'market1';
|
||||
render(
|
||||
<MockedProvider mocks={[...mocks]}>
|
||||
<SuccessorMarketRenderer value={successorValue} parent />
|
||||
</MockedProvider>
|
||||
);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('market-code')).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.getByText('code parent 1')).toBeInTheDocument();
|
||||
expect(screen.getByText('Futr')).toBeInTheDocument();
|
||||
|
||||
await userEvent.click(screen.getByRole('button'));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockClickHandler).toHaveBeenCalledWith('parentMarket1', false);
|
||||
});
|
||||
});
|
||||
it('should properly rendered only parent market', async () => {
|
||||
const successorValue = 'market2';
|
||||
const { rerender } = render(
|
||||
<MockedProvider mocks={[...mocks]}>
|
||||
<SuccessorMarketRenderer value={successorValue} parent />
|
||||
</MockedProvider>
|
||||
);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('market-code')).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.getByText('code parent 2')).toBeInTheDocument();
|
||||
expect(screen.getByText('Futr')).toBeInTheDocument();
|
||||
await userEvent.click(screen.getByRole('button'));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockClickHandler).toHaveBeenCalledWith('parentMarket2', false);
|
||||
});
|
||||
|
||||
rerender(
|
||||
<MockedProvider mocks={[...mocks]}>
|
||||
<SuccessorMarketRenderer value={successorValue} />
|
||||
</MockedProvider>
|
||||
);
|
||||
|
||||
expect(screen.getByText('-')).toBeInTheDocument();
|
||||
});
|
||||
it('should properly rendered only successor market', async () => {
|
||||
const successorValue = 'market3';
|
||||
const { rerender } = render(
|
||||
<MockedProvider mocks={[...mocks]}>
|
||||
<SuccessorMarketRenderer value={successorValue} />
|
||||
</MockedProvider>
|
||||
);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('market-code')).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.getByText('code successor 3')).toBeInTheDocument();
|
||||
expect(screen.getByText('Futr')).toBeInTheDocument();
|
||||
|
||||
await userEvent.click(screen.getByRole('button'));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockClickHandler).toHaveBeenCalledWith('successorMarket3', false);
|
||||
});
|
||||
|
||||
await act(() => {
|
||||
rerender(
|
||||
<MockedProvider mocks={[...mocks]}>
|
||||
<SuccessorMarketRenderer value={successorValue} parent />
|
||||
</MockedProvider>
|
||||
);
|
||||
});
|
||||
expect(screen.getByText('-')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -1,8 +1,8 @@
|
||||
import React from 'react';
|
||||
import { MarketNameCell } from '@vegaprotocol/datagrid';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import { marketProvider, useSuccessorMarketIds } from '@vegaprotocol/markets';
|
||||
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
||||
import React from 'react';
|
||||
|
||||
export const SuccessorMarketRenderer = ({
|
||||
value,
|
||||
@@ -33,7 +33,6 @@ export const SuccessorMarketRenderer = ({
|
||||
value={data.tradableInstrument.instrument.code}
|
||||
data={data}
|
||||
onMarketClick={onMarketClick}
|
||||
productType={data.tradableInstrument.instrument?.product.__typename}
|
||||
/>
|
||||
) : (
|
||||
'-'
|
||||
|
||||
@@ -1,2 +1,10 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
|
||||
export const THROTTLE_UPDATE_TIME = 500;
|
||||
export const ONBOARDING_VIEWED_KEY = 'vega_onboarding_viewed';
|
||||
export const MAINNET_WELCOME_HEADER = t(
|
||||
'Trade cash settled futures on the fully decentralised Vega network.'
|
||||
);
|
||||
export const TESTNET_WELCOME_HEADER = t(
|
||||
'Try out trading cash settled futures on the fully decentralised Vega network (Testnet).'
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Fragment, useState } from 'react';
|
||||
import { useState } from 'react';
|
||||
import type {
|
||||
SuccessorProposalListFieldsFragment,
|
||||
NewMarketSuccessorFieldsFragment,
|
||||
@@ -52,7 +52,7 @@ export const MarketSuccessorProposalBanner = ({
|
||||
TOKEN_PROPOSAL.replace(':id', item.id || '')
|
||||
);
|
||||
return (
|
||||
<Fragment key={i}>
|
||||
<>
|
||||
<ExternalLink href={externalLink} key={i}>
|
||||
{
|
||||
(item.terms?.change as NewMarketSuccessorFieldsFragment)
|
||||
@@ -60,7 +60,7 @@ export const MarketSuccessorProposalBanner = ({
|
||||
}
|
||||
</ExternalLink>
|
||||
{i < successors.length - 1 && ', '}
|
||||
</Fragment>
|
||||
</>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Header, HeaderTitle } from '../header';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { MarketSelector } from '../../components/market-selector/market-selector';
|
||||
import { MarketHeaderStats } from '../../client-pages/market/market-header-stats';
|
||||
import { useMarket, useMarketList } from '@vegaprotocol/markets';
|
||||
import { useMarket } from '@vegaprotocol/markets';
|
||||
import { useState } from 'react';
|
||||
|
||||
export const MarketHeader = () => {
|
||||
@@ -11,10 +11,6 @@ export const MarketHeader = () => {
|
||||
const { data } = useMarket(marketId);
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
// Ensure that markets are kept cached so opening the list
|
||||
// shows all markets instantly
|
||||
useMarketList();
|
||||
|
||||
if (!data) return null;
|
||||
|
||||
return (
|
||||
|
||||
@@ -99,7 +99,6 @@ describe('MarketSelectorItem', () => {
|
||||
currentMarketId={market.id}
|
||||
style={{}}
|
||||
onSelect={jest.fn()}
|
||||
allProducts
|
||||
/>
|
||||
</MockedProvider>
|
||||
</MemoryRouter>
|
||||
@@ -182,7 +181,5 @@ describe('MarketSelectorItem', () => {
|
||||
addDecimalsFormatNumber(marketData.markPrice, market.decimalPlaces)
|
||||
);
|
||||
});
|
||||
|
||||
expect(screen.getByText('Futr')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -12,20 +12,17 @@ import {
|
||||
MarketTradingModeMapping,
|
||||
} from '@vegaprotocol/types';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { MarketProductPill } from '@vegaprotocol/datagrid';
|
||||
|
||||
export const MarketSelectorItem = ({
|
||||
market,
|
||||
style,
|
||||
currentMarketId,
|
||||
onSelect,
|
||||
allProducts,
|
||||
}: {
|
||||
market: MarketMaybeWithDataAndCandles;
|
||||
style: CSSProperties;
|
||||
currentMarketId?: string;
|
||||
onSelect: (marketId: string) => void;
|
||||
allProducts: boolean;
|
||||
}) => {
|
||||
return (
|
||||
<div style={style} role="row">
|
||||
@@ -39,19 +36,13 @@ export const MarketSelectorItem = ({
|
||||
})}
|
||||
onClick={() => onSelect(market.id)}
|
||||
>
|
||||
<MarketData market={market} allProducts={allProducts} />
|
||||
<MarketData market={market} />
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const MarketData = ({
|
||||
market,
|
||||
allProducts,
|
||||
}: {
|
||||
market: MarketMaybeWithDataAndCandles;
|
||||
allProducts: boolean;
|
||||
}) => {
|
||||
const MarketData = ({ market }: { market: MarketMaybeWithDataAndCandles }) => {
|
||||
const { data } = useMarketDataUpdateSubscription({
|
||||
variables: {
|
||||
marketId: market.id,
|
||||
@@ -89,16 +80,11 @@ const MarketData = ({
|
||||
? addDecimalsFormatNumber(vol, market.positionDecimalPlaces)
|
||||
: '0.00';
|
||||
|
||||
const productType = market.tradableInstrument.instrument.product.__typename;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="w-2/5" role="gridcell">
|
||||
<h3 className="text-ellipsis text-sm lg:text-base whitespace-nowrap overflow-hidden">
|
||||
{market.tradableInstrument.instrument.code}{' '}
|
||||
{allProducts && productType && (
|
||||
<MarketProductPill productType={productType} />
|
||||
)}
|
||||
{market.tradableInstrument.instrument.code}
|
||||
</h3>
|
||||
{mode && (
|
||||
<p className="text-xs text-vega-orange-500 dark:text-vega-orange-550 whitespace-nowrap">
|
||||
|
||||
@@ -132,7 +132,6 @@ describe('MarketSelector', () => {
|
||||
data: markets,
|
||||
loading: false,
|
||||
error: undefined,
|
||||
reload: jest.fn(),
|
||||
});
|
||||
|
||||
it('Button "All" should be selected by default', () => {
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import uniqBy from 'lodash/uniqBy';
|
||||
import { type MarketMaybeWithDataAndCandles } from '@vegaprotocol/markets';
|
||||
import type { MarketMaybeWithDataAndCandles } from '@vegaprotocol/markets';
|
||||
import {
|
||||
TradingInput,
|
||||
Input,
|
||||
TinyScroll,
|
||||
VegaIcon,
|
||||
VegaIconNames,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import type { CSSProperties } from 'react';
|
||||
import { useCallback, useState, useMemo, useRef, useEffect } from 'react';
|
||||
import { useCallback, useState, useMemo, useRef } from 'react';
|
||||
import { FixedSizeList } from 'react-window';
|
||||
import { useMarketSelectorList } from './use-market-selector-list';
|
||||
import type { ProductType } from './product-selector';
|
||||
@@ -43,13 +43,8 @@ export const MarketSelector = ({
|
||||
sort: Sort.None,
|
||||
assets: [],
|
||||
});
|
||||
const allProducts = filter.product === Product.All;
|
||||
const { markets, data, loading, error, reload } =
|
||||
useMarketSelectorList(filter);
|
||||
|
||||
useEffect(() => {
|
||||
reload();
|
||||
}, [reload]);
|
||||
const { markets, data, loading, error } = useMarketSelectorList(filter);
|
||||
|
||||
return (
|
||||
<div data-testid="market-selector">
|
||||
@@ -62,7 +57,7 @@ export const MarketSelector = ({
|
||||
/>
|
||||
<div className="text-sm grid grid-cols-[2fr_1fr_1fr] gap-1 ">
|
||||
<div className="flex-1">
|
||||
<TradingInput
|
||||
<Input
|
||||
onChange={(e) =>
|
||||
setFilter((curr) => ({ ...curr, searchTerm: e.target.value }))
|
||||
}
|
||||
@@ -133,7 +128,6 @@ export const MarketSelector = ({
|
||||
? t('Spot markets coming soon.')
|
||||
: t('No markets')
|
||||
}
|
||||
allProducts={allProducts}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -147,7 +141,6 @@ const MarketList = ({
|
||||
currentMarketId,
|
||||
onSelect,
|
||||
noItems,
|
||||
allProducts,
|
||||
}: {
|
||||
data: MarketMaybeWithDataAndCandles[];
|
||||
error: Error | undefined;
|
||||
@@ -156,7 +149,6 @@ const MarketList = ({
|
||||
currentMarketId?: string;
|
||||
onSelect: (marketId: string) => void;
|
||||
noItems: string;
|
||||
allProducts: boolean;
|
||||
}) => {
|
||||
const itemSize = 45;
|
||||
const listRef = useRef<HTMLDivElement | null>(null);
|
||||
@@ -200,7 +192,6 @@ const MarketList = ({
|
||||
currentMarketId={currentMarketId}
|
||||
onSelect={onSelect}
|
||||
noItems={noItems}
|
||||
allProducts={allProducts}
|
||||
/>
|
||||
</div>
|
||||
</TinyScroll>
|
||||
@@ -211,7 +202,6 @@ interface ListItemData {
|
||||
data: MarketMaybeWithDataAndCandles[];
|
||||
onSelect: (marketId: string) => void;
|
||||
currentMarketId?: string;
|
||||
allProducts: boolean;
|
||||
}
|
||||
|
||||
const ListItem = ({
|
||||
@@ -228,7 +218,6 @@ const ListItem = ({
|
||||
currentMarketId={data.currentMarketId}
|
||||
style={style}
|
||||
onSelect={data.onSelect}
|
||||
allProducts={data.allProducts}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -240,21 +229,19 @@ const List = ({
|
||||
onSelect,
|
||||
noItems,
|
||||
currentMarketId,
|
||||
allProducts,
|
||||
}: ListItemData & {
|
||||
loading: boolean;
|
||||
height: number;
|
||||
itemSize: number;
|
||||
noItems: string;
|
||||
allProducts: boolean;
|
||||
}) => {
|
||||
const itemKey = useCallback(
|
||||
(index: number, data: ListItemData) => data.data[index].id,
|
||||
[]
|
||||
);
|
||||
const itemData = useMemo(
|
||||
() => ({ data, onSelect, currentMarketId, allProducts }),
|
||||
[data, onSelect, currentMarketId, allProducts]
|
||||
() => ({ data, onSelect, currentMarketId }),
|
||||
[data, onSelect, currentMarketId]
|
||||
);
|
||||
if (!data || loading) {
|
||||
return (
|
||||
|
||||
@@ -15,7 +15,6 @@ export const Sort = {
|
||||
Gained: 'Gained',
|
||||
Lost: 'Lost',
|
||||
New: 'New',
|
||||
TopTraded: 'TopTraded',
|
||||
} as const;
|
||||
|
||||
export type SortType = keyof typeof Sort;
|
||||
@@ -27,7 +26,6 @@ export const SortTypeMapping: {
|
||||
[Sort.Gained]: 'Top gaining',
|
||||
[Sort.Lost]: 'Top losing',
|
||||
[Sort.New]: 'New markets',
|
||||
[Sort.TopTraded]: 'Top traded',
|
||||
};
|
||||
|
||||
const SortIconMapping: {
|
||||
@@ -37,7 +35,6 @@ const SortIconMapping: {
|
||||
[Sort.Gained]: VegaIconNames.TREND_UP,
|
||||
[Sort.Lost]: VegaIconNames.TREND_DOWN,
|
||||
[Sort.New]: VegaIconNames.STAR,
|
||||
[Sort.TopTraded]: VegaIconNames.ARROW_UP,
|
||||
};
|
||||
|
||||
export const SortDropdown = ({
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import { useMemo } from 'react';
|
||||
import orderBy from 'lodash/orderBy';
|
||||
import { MarketState } from '@vegaprotocol/types';
|
||||
import {
|
||||
calcCandleVolume,
|
||||
calcTradedFactor,
|
||||
useMarketList,
|
||||
} from '@vegaprotocol/markets';
|
||||
import { calcCandleVolume, useMarketList } from '@vegaprotocol/markets';
|
||||
import { priceChangePercentage } from '@vegaprotocol/utils';
|
||||
import type { Filter } from '../../components/market-selector/market-selector';
|
||||
import { Sort } from './sort-dropdown';
|
||||
@@ -24,7 +20,7 @@ export const useMarketSelectorList = ({
|
||||
sort,
|
||||
searchTerm,
|
||||
}: Filter) => {
|
||||
const { data, loading, error, reload } = useMarketList();
|
||||
const { data, loading, error } = useMarketList();
|
||||
|
||||
const markets = useMemo(() => {
|
||||
if (!data?.length) return [];
|
||||
@@ -98,14 +94,10 @@ export const useMarketSelectorList = ({
|
||||
);
|
||||
}
|
||||
|
||||
if (sort === Sort.TopTraded) {
|
||||
return orderBy(markets, [(m) => calcTradedFactor(m)], ['desc']);
|
||||
}
|
||||
|
||||
return markets;
|
||||
}, [data, product, searchTerm, assets, sort]);
|
||||
|
||||
return { markets, data, loading, error, reload };
|
||||
return { markets, data, loading, error };
|
||||
};
|
||||
|
||||
export const isMarketActive = (state: MarketState) => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { VegaIcon, VegaIconNames } from '@vegaprotocol/ui-toolkit';
|
||||
import { MarketSelector } from '../market-selector';
|
||||
import { useMarket, useMarketList } from '@vegaprotocol/markets';
|
||||
import { useMarket } from '@vegaprotocol/markets';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import * as PopoverPrimitive from '@radix-ui/react-popover';
|
||||
@@ -14,10 +14,6 @@ export const NavHeader = () => {
|
||||
const { data } = useMarket(marketId);
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
// Ensure that markets are kept cached so opening the list
|
||||
// shows all markets instantly
|
||||
useMarketList();
|
||||
|
||||
if (!marketId) return null;
|
||||
|
||||
return (
|
||||
|
||||
@@ -5,7 +5,6 @@ import { Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import type { DataGridSlice } from '../../stores/datagrid-store-slice';
|
||||
import { createDataGridSlice } from '../../stores/datagrid-store-slice';
|
||||
import type { StateCreator } from 'zustand';
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
||||
@@ -14,7 +13,6 @@ export const PositionsContainer = ({ allKeys }: { allKeys?: boolean }) => {
|
||||
const onMarketClick = useMarketClickHandler(true);
|
||||
const { pubKey, pubKeys, isReadOnly } = useVegaWallet();
|
||||
|
||||
const showClosed = usePositionsStore((store) => store.showClosedMarkets);
|
||||
const gridStore = usePositionsStore((store) => store.gridStore);
|
||||
const updateGridStore = usePositionsStore((store) => store.updateGridStore);
|
||||
const gridStoreCallbacks = useDataGridEvents(gridStore, updateGridStore);
|
||||
@@ -42,35 +40,12 @@ export const PositionsContainer = ({ allKeys }: { allKeys?: boolean }) => {
|
||||
onMarketClick={onMarketClick}
|
||||
isReadOnly={isReadOnly}
|
||||
gridProps={gridStoreCallbacks}
|
||||
showClosed={showClosed}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
type PositionsStoreSlice = {
|
||||
showClosedMarkets: boolean;
|
||||
toggleClosedMarkets: () => void;
|
||||
};
|
||||
|
||||
const createPositionStoreSlice: StateCreator<PositionsStoreSlice> = (set) => ({
|
||||
showClosedMarkets: false,
|
||||
toggleClosedMarkets: () => {
|
||||
set((curr) => {
|
||||
return {
|
||||
showClosedMarkets: !curr.showClosedMarkets,
|
||||
};
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export const usePositionsStore = create<PositionsStoreSlice & DataGridSlice>()(
|
||||
persist(
|
||||
(...args) => ({
|
||||
...createPositionStoreSlice(...args),
|
||||
...createDataGridSlice(...args),
|
||||
}),
|
||||
{
|
||||
name: 'vega_positions_store',
|
||||
}
|
||||
)
|
||||
const usePositionsStore = create<DataGridSlice>()(
|
||||
persist(createDataGridSlice, {
|
||||
name: 'vega_positions_store',
|
||||
})
|
||||
);
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export * from './positions-menu';
|
||||
@@ -1,18 +0,0 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { Intent, TradingButton } from '@vegaprotocol/ui-toolkit';
|
||||
import { usePositionsStore } from '../positions-container';
|
||||
|
||||
export const PositionsMenu = () => {
|
||||
const showClosed = usePositionsStore((store) => store.showClosedMarkets);
|
||||
const toggle = usePositionsStore((store) => store.toggleClosedMarkets);
|
||||
return (
|
||||
<TradingButton
|
||||
intent={Intent.Primary}
|
||||
size="extra-small"
|
||||
data-testid="open-transfer"
|
||||
onClick={toggle}
|
||||
>
|
||||
{showClosed ? t('Hide closed markets') : t('Show closed markets')}
|
||||
</TradingButton>
|
||||
);
|
||||
};
|
||||
@@ -14,9 +14,12 @@ import { Settings } from '../settings';
|
||||
import { Tooltip } from '../../components/tooltip';
|
||||
import { WithdrawContainer } from '../withdraw-container';
|
||||
import { Routes as AppRoutes } from '../../pages/client-router';
|
||||
import { persist } from 'zustand/middleware';
|
||||
import { GetStarted } from '../welcome-dialog';
|
||||
import { useVegaWallet, useViewAsDialog } from '@vegaprotocol/wallet';
|
||||
|
||||
const STORAGE_KEY = 'vega_sidebar_store';
|
||||
|
||||
export enum ViewType {
|
||||
Order = 'Order',
|
||||
Info = 'Info',
|
||||
@@ -299,14 +302,22 @@ export const useSidebar = create<{
|
||||
init: boolean;
|
||||
view: SidebarView | null;
|
||||
setView: (view: SidebarView | null) => void;
|
||||
}>()((set) => ({
|
||||
init: true,
|
||||
view: null,
|
||||
setView: (x) =>
|
||||
set(() => {
|
||||
if (x == null) {
|
||||
return { view: null, init: false };
|
||||
}
|
||||
return { view: x, init: false };
|
||||
}>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
init: true,
|
||||
view: null,
|
||||
setView: (x) =>
|
||||
set(() => {
|
||||
if (x == null) {
|
||||
return { view: null, init: false };
|
||||
}
|
||||
|
||||
return { view: x, init: false };
|
||||
}),
|
||||
}),
|
||||
}));
|
||||
{
|
||||
name: STORAGE_KEY,
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
@@ -36,6 +36,6 @@ export const StopOrdersContainer = () => {
|
||||
|
||||
const useStopOrdersStore = create<DataGridSlice>()(
|
||||
persist(createDataGridSlice, {
|
||||
name: 'vega_stop_orders_store',
|
||||
name: 'vega_fills_store',
|
||||
})
|
||||
);
|
||||
|
||||
@@ -1,36 +1,16 @@
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
|
||||
import { VegaWalletContext } from '@vegaprotocol/wallet';
|
||||
import { GetStarted } from './get-started';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
|
||||
let mockStep = 1;
|
||||
jest.mock('./use-get-onboarding-step', () => ({
|
||||
...jest.requireActual('./use-get-onboarding-step'),
|
||||
useGetOnboardingStep: jest.fn(() => mockStep),
|
||||
}));
|
||||
|
||||
describe('GetStarted', () => {
|
||||
const renderComponent = (context: Partial<VegaWalletContextShape> = {}) => {
|
||||
return render(
|
||||
<MemoryRouter>
|
||||
<VegaWalletContext.Provider value={context as VegaWalletContextShape}>
|
||||
<GetStarted />
|
||||
</VegaWalletContext.Provider>
|
||||
</MemoryRouter>
|
||||
<VegaWalletContext.Provider value={context as VegaWalletContextShape}>
|
||||
<GetStarted />
|
||||
</VegaWalletContext.Provider>
|
||||
);
|
||||
};
|
||||
const checkTicks = (elements: Element[]) => {
|
||||
elements.forEach((item, i) => {
|
||||
if (i + 1 < mockStep) {
|
||||
expect(item.querySelector('[data-testid="icon-tick"]')).toBeTruthy();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('renders full get started content if not connected and no browser wallet detected', () => {
|
||||
renderComponent();
|
||||
@@ -40,71 +20,12 @@ describe('GetStarted', () => {
|
||||
it('renders connect prompt if no pubKey but wallet installed', () => {
|
||||
globalThis.window.vega = {} as Vega;
|
||||
renderComponent();
|
||||
expect(screen.getByTestId('get-started-banner')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('order-connect-wallet')).toBeInTheDocument();
|
||||
globalThis.window.vega = undefined as unknown as Vega;
|
||||
});
|
||||
|
||||
it('renders nothing if connected', () => {
|
||||
mockStep = 0;
|
||||
const { container } = renderComponent({ pubKey: 'my-pubkey' });
|
||||
expect(container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it('steps should be ticked', () => {
|
||||
const navigatorGetter: jest.SpyInstance = jest.spyOn(
|
||||
window.navigator,
|
||||
'userAgent',
|
||||
'get'
|
||||
);
|
||||
navigatorGetter.mockReturnValue('Chrome');
|
||||
mockStep = 1;
|
||||
const { rerender, container } = renderComponent();
|
||||
expect(screen.queryByTestId('icon-tick')).not.toBeInTheDocument();
|
||||
expect(screen.getByTestId('get-wallet-button')).toBeInTheDocument();
|
||||
|
||||
mockStep = 2;
|
||||
rerender(
|
||||
<MemoryRouter>
|
||||
<VegaWalletContext.Provider value={{} as VegaWalletContextShape}>
|
||||
<GetStarted />
|
||||
</VegaWalletContext.Provider>
|
||||
</MemoryRouter>
|
||||
);
|
||||
checkTicks(screen.getAllByRole('listitem'));
|
||||
expect(screen.getByRole('button', { name: 'Connect' })).toBeInTheDocument();
|
||||
|
||||
mockStep = 3;
|
||||
rerender(
|
||||
<MemoryRouter>
|
||||
<VegaWalletContext.Provider value={{} as VegaWalletContextShape}>
|
||||
<GetStarted />
|
||||
</VegaWalletContext.Provider>
|
||||
</MemoryRouter>
|
||||
);
|
||||
checkTicks(screen.getAllByRole('listitem'));
|
||||
expect(screen.getByRole('button', { name: 'Deposit' })).toBeInTheDocument();
|
||||
|
||||
mockStep = 4;
|
||||
rerender(
|
||||
<MemoryRouter>
|
||||
<VegaWalletContext.Provider value={{} as VegaWalletContextShape}>
|
||||
<GetStarted />
|
||||
</VegaWalletContext.Provider>
|
||||
</MemoryRouter>
|
||||
);
|
||||
checkTicks(screen.getAllByRole('listitem'));
|
||||
expect(screen.getByRole('button', { name: 'Dismiss' })).toBeInTheDocument();
|
||||
|
||||
mockStep = 5;
|
||||
rerender(
|
||||
<MemoryRouter>
|
||||
<VegaWalletContext.Provider
|
||||
value={{ pubKey: 'my-pubkey' } as VegaWalletContextShape}
|
||||
>
|
||||
<GetStarted />
|
||||
</VegaWalletContext.Provider>
|
||||
</MemoryRouter>
|
||||
);
|
||||
expect(container).toBeEmptyDOMElement();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,96 +1,36 @@
|
||||
import classNames from 'classnames';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { ExternalLink, Intent, TradingButton } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
ExternalLink,
|
||||
Intent,
|
||||
TradingButton,
|
||||
VegaIcon,
|
||||
VegaIconNames,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
GetWalletButton,
|
||||
useVegaWallet,
|
||||
useVegaWalletDialogStore,
|
||||
isBrowserWalletInstalled,
|
||||
} from '@vegaprotocol/wallet';
|
||||
import { Networks, useEnvironment } from '@vegaprotocol/environment';
|
||||
import { useLocalStorage } from '@vegaprotocol/react-helpers';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import {
|
||||
OnboardingStep,
|
||||
useGetOnboardingStep,
|
||||
} from './use-get-onboarding-step';
|
||||
import { Links, Routes } from '../../pages/client-router';
|
||||
import { useGlobalStore } from '../../stores';
|
||||
import { useSidebar, ViewType } from '../sidebar';
|
||||
import * as constants from '../constants';
|
||||
|
||||
interface Props {
|
||||
lead?: string;
|
||||
}
|
||||
|
||||
const GetStartedButton = ({ step }: { step: OnboardingStep }) => {
|
||||
const navigate = useNavigate();
|
||||
const [, setOnboardingViewed] = useLocalStorage(
|
||||
constants.ONBOARDING_VIEWED_KEY
|
||||
);
|
||||
|
||||
const update = useGlobalStore((store) => store.update);
|
||||
const marketId = useGlobalStore((store) => store.marketId);
|
||||
const link = marketId ? Links[Routes.MARKET](marketId) : Links[Routes.HOME]();
|
||||
const openVegaWalletDialog = useVegaWalletDialogStore(
|
||||
(store) => store.openVegaWalletDialog
|
||||
);
|
||||
const setView = useSidebar((store) => store.setView);
|
||||
let buttonText = t('Get started');
|
||||
let onClickHandle = () => {
|
||||
openVegaWalletDialog();
|
||||
};
|
||||
if (step === OnboardingStep.ONBOARDING_WALLET_STEP) {
|
||||
return <GetWalletButton className="justify-between" />;
|
||||
} else if (step === OnboardingStep.ONBOARDING_CONNECT_STEP) {
|
||||
buttonText = t('Connect');
|
||||
} else if (step === OnboardingStep.ONBOARDING_DEPOSIT_STEP) {
|
||||
buttonText = t('Deposit');
|
||||
onClickHandle = () => {
|
||||
navigate(link);
|
||||
setView({ type: ViewType.Deposit });
|
||||
update({ onBoardingDismissed: true });
|
||||
};
|
||||
} else if (step === OnboardingStep.ONBOARDING_ORDER_STEP) {
|
||||
buttonText = t('Dismiss');
|
||||
onClickHandle = () => {
|
||||
navigate(link);
|
||||
setView({ type: ViewType.Order });
|
||||
setOnboardingViewed('true');
|
||||
};
|
||||
}
|
||||
|
||||
return (
|
||||
<TradingButton
|
||||
onClick={onClickHandle}
|
||||
size="small"
|
||||
data-testid="get-started-button"
|
||||
intent={Intent.Info}
|
||||
>
|
||||
{buttonText}
|
||||
</TradingButton>
|
||||
);
|
||||
};
|
||||
|
||||
export const GetStarted = ({ lead }: Props) => {
|
||||
const { pubKey } = useVegaWallet();
|
||||
const { VEGA_ENV, VEGA_NETWORKS } = useEnvironment();
|
||||
const CANONICAL_URL = VEGA_NETWORKS[VEGA_ENV] || 'https://console.vega.xyz';
|
||||
const [onBoardingViewed] = useLocalStorage(constants.ONBOARDING_VIEWED_KEY);
|
||||
const currentStep = useGetOnboardingStep();
|
||||
|
||||
const [, setOnboardingViewed] = useLocalStorage(
|
||||
constants.ONBOARDING_VIEWED_KEY
|
||||
);
|
||||
|
||||
const openVegaWalletDialog = useVegaWalletDialogStore(
|
||||
(store) => store.openVegaWalletDialog
|
||||
);
|
||||
|
||||
const getStartedNeeded =
|
||||
onBoardingViewed !== 'true' &&
|
||||
currentStep &&
|
||||
currentStep < OnboardingStep.ONBOARDING_COMPLETE_STEP;
|
||||
const onButtonClick = () => {
|
||||
openVegaWalletDialog();
|
||||
setOnboardingViewed('true');
|
||||
};
|
||||
|
||||
const wrapperClasses = classNames(
|
||||
'flex flex-col py-4 px-6 gap-4 rounded',
|
||||
@@ -99,39 +39,27 @@ export const GetStarted = ({ lead }: Props) => {
|
||||
{ 'mt-8': !lead }
|
||||
);
|
||||
|
||||
if (getStartedNeeded) {
|
||||
if (!pubKey && !isBrowserWalletInstalled()) {
|
||||
return (
|
||||
<div className={wrapperClasses} data-testid="get-started-banner">
|
||||
{lead && <h2>{lead}</h2>}
|
||||
<h3 className="text-lg">{t('Get started')}</h3>
|
||||
<div>
|
||||
<ul className="list-none">
|
||||
<Step
|
||||
step={1}
|
||||
text={t('Get a Vega wallet')}
|
||||
complete={currentStep > OnboardingStep.ONBOARDING_WALLET_STEP}
|
||||
/>
|
||||
<Step
|
||||
step={2}
|
||||
text={t('Connect')}
|
||||
complete={Boolean(
|
||||
currentStep > OnboardingStep.ONBOARDING_CONNECT_STEP || pubKey
|
||||
)}
|
||||
/>
|
||||
<Step
|
||||
step={3}
|
||||
text={t('Deposit funds')}
|
||||
complete={currentStep > OnboardingStep.ONBOARDING_DEPOSIT_STEP}
|
||||
/>
|
||||
<Step
|
||||
step={4}
|
||||
text={t('Open a position')}
|
||||
complete={currentStep > OnboardingStep.ONBOARDING_ORDER_STEP}
|
||||
/>
|
||||
<ul className="list-decimal list-inside">
|
||||
<li>{t('Get a Vega wallet')}</li>
|
||||
<li>{t('Connect')}</li>
|
||||
<li>{t('Deposit funds')}</li>
|
||||
<li>{t('Open a position')}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<GetStartedButton step={currentStep} />
|
||||
<TradingButton
|
||||
intent={Intent.Info}
|
||||
onClick={onButtonClick}
|
||||
data-testid="get-started-button"
|
||||
>
|
||||
{t('Get started')}
|
||||
</TradingButton>
|
||||
</div>
|
||||
{VEGA_ENV === Networks.MAINNET && (
|
||||
<p className="text-sm">
|
||||
@@ -156,7 +84,7 @@ export const GetStarted = ({ lead }: Props) => {
|
||||
if (!pubKey) {
|
||||
return (
|
||||
<div className={wrapperClasses}>
|
||||
<p className="mb-1 text-sm">
|
||||
<p className="text-sm mb-1">
|
||||
You need a{' '}
|
||||
<ExternalLink href="https://vega.xyz/wallet">
|
||||
Vega wallet
|
||||
@@ -177,34 +105,3 @@ export const GetStarted = ({ lead }: Props) => {
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const Step = ({
|
||||
step,
|
||||
text,
|
||||
complete,
|
||||
}: {
|
||||
step: number;
|
||||
text: string;
|
||||
complete: boolean;
|
||||
}) => {
|
||||
return (
|
||||
<li
|
||||
className={classNames('flex', {
|
||||
'text-vega-clight-200 dark:text-vega-cdark-200': complete,
|
||||
})}
|
||||
>
|
||||
<div className="flex justify-center w-5">
|
||||
{complete ? <Tick /> : <span>{step}.</span>}
|
||||
</div>
|
||||
<div className="ml-1">{text}</div>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
||||
const Tick = () => {
|
||||
return (
|
||||
<span className="relative right-[2px]">
|
||||
<VegaIcon name={VegaIconNames.TICK} size={18} />
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { TradingCheckbox } from '@vegaprotocol/ui-toolkit';
|
||||
import { Checkbox } from '@vegaprotocol/ui-toolkit';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useTelemetryApproval } from '../../lib/hooks/use-telemetry-approval';
|
||||
|
||||
@@ -7,7 +7,7 @@ export const TelemetryApproval = ({ helpText }: { helpText: string }) => {
|
||||
return (
|
||||
<div className="flex flex-col py-3">
|
||||
<div className="mr-4" role="form">
|
||||
<TradingCheckbox
|
||||
<Checkbox
|
||||
label={<span className="text-lg pl-1">{t('Share usage data')}</span>}
|
||||
checked={isApproved}
|
||||
name="telemetry-approval"
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
import type { ReactNode } from 'react';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import {
|
||||
useGetOnboardingStep,
|
||||
OnboardingStep,
|
||||
} from './use-get-onboarding-step';
|
||||
import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
|
||||
import { VegaWalletContext } from '@vegaprotocol/wallet';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import { depositsProvider } from '@vegaprotocol/deposits';
|
||||
import { aggregatedAccountsDataProvider } from '@vegaprotocol/accounts';
|
||||
import { ordersWithMarketProvider } from '@vegaprotocol/orders';
|
||||
import { positionsDataProvider } from '@vegaprotocol/positions';
|
||||
|
||||
let mockData: object[] | null = [{ id: 'item-id' }];
|
||||
jest.mock('@vegaprotocol/data-provider', () => ({
|
||||
...jest.requireActual('@vegaprotocol/data-provider'),
|
||||
useDataProvider: jest.fn(() => ({ data: mockData })),
|
||||
}));
|
||||
|
||||
let mockContext: Partial<VegaWalletContextShape> = { pubKey: 'test-pubkey' };
|
||||
|
||||
describe('useGetOnboardingStep', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
mockData = [{ id: 'item-id' }];
|
||||
mockContext = { pubKey: 'test-pubkey' };
|
||||
globalThis.window.vega = {} as Vega;
|
||||
});
|
||||
|
||||
const wrapper = ({ children }: { children: ReactNode }) => (
|
||||
<VegaWalletContext.Provider
|
||||
value={mockContext as unknown as VegaWalletContextShape}
|
||||
>
|
||||
{children}
|
||||
</VegaWalletContext.Provider>
|
||||
);
|
||||
|
||||
it('should return properly ONBOARDING_UNKNOWN_STEP', () => {
|
||||
mockData = null;
|
||||
const { result } = renderHook(() => useGetOnboardingStep(), { wrapper });
|
||||
expect(result.current).toEqual(OnboardingStep.ONBOARDING_UNKNOWN_STEP);
|
||||
});
|
||||
|
||||
it('should return properly ONBOARDING_WALLET_STEP', () => {
|
||||
// @ts-ignore test only purpose
|
||||
globalThis.window.vega = undefined;
|
||||
const { result } = renderHook(() => useGetOnboardingStep(), { wrapper });
|
||||
expect(result.current).toEqual(OnboardingStep.ONBOARDING_WALLET_STEP);
|
||||
});
|
||||
|
||||
it('should return properly ONBOARDING_CONNECT_STEP', () => {
|
||||
mockContext = { pubKey: null };
|
||||
const { result } = renderHook(() => useGetOnboardingStep(), { wrapper });
|
||||
expect(result.current).toEqual(OnboardingStep.ONBOARDING_CONNECT_STEP);
|
||||
});
|
||||
|
||||
it('should return properly ONBOARDING_DEPOSIT_STEP', async () => {
|
||||
(useDataProvider as jest.Mock).mockImplementation((args) => {
|
||||
if (
|
||||
args.dataProvider === depositsProvider ||
|
||||
args.dataProvider === aggregatedAccountsDataProvider
|
||||
) {
|
||||
return { data: [] };
|
||||
}
|
||||
return { data: mockData };
|
||||
});
|
||||
const { result } = renderHook(() => useGetOnboardingStep(), { wrapper });
|
||||
await expect(result.current).toEqual(
|
||||
OnboardingStep.ONBOARDING_DEPOSIT_STEP
|
||||
);
|
||||
});
|
||||
|
||||
it('should return properly ONBOARDING_ORDER_STEP', async () => {
|
||||
(useDataProvider as jest.Mock).mockImplementation((args) => {
|
||||
if (
|
||||
args.dataProvider === ordersWithMarketProvider ||
|
||||
args.dataProvider === positionsDataProvider
|
||||
) {
|
||||
return { data: [] };
|
||||
}
|
||||
return { data: mockData };
|
||||
});
|
||||
const { result } = renderHook(() => useGetOnboardingStep(), { wrapper });
|
||||
await expect(result.current).toEqual(OnboardingStep.ONBOARDING_ORDER_STEP);
|
||||
});
|
||||
|
||||
it('should return properly ONBOARDING_COMPLETE_STEP', async () => {
|
||||
(useDataProvider as jest.Mock).mockImplementation(() => {
|
||||
return { data: mockData };
|
||||
});
|
||||
const { result } = renderHook(() => useGetOnboardingStep(), { wrapper });
|
||||
await expect(result.current).toEqual(
|
||||
OnboardingStep.ONBOARDING_COMPLETE_STEP
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,82 +0,0 @@
|
||||
import { isBrowserWalletInstalled, useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { depositsProvider } from '@vegaprotocol/deposits';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import { ordersWithMarketProvider } from '@vegaprotocol/orders';
|
||||
import * as Types from '@vegaprotocol/types';
|
||||
import { aggregatedAccountsDataProvider } from '@vegaprotocol/accounts';
|
||||
import { positionsDataProvider } from '@vegaprotocol/positions';
|
||||
import { useGlobalStore } from '../../stores';
|
||||
|
||||
export enum OnboardingStep {
|
||||
ONBOARDING_UNKNOWN_STEP,
|
||||
ONBOARDING_WALLET_STEP,
|
||||
ONBOARDING_CONNECT_STEP,
|
||||
ONBOARDING_DEPOSIT_STEP,
|
||||
ONBOARDING_ORDER_STEP,
|
||||
ONBOARDING_COMPLETE_STEP,
|
||||
}
|
||||
|
||||
export const useGetOnboardingStep = () => {
|
||||
const connecting = useGlobalStore((store) => store.eagerConnecting);
|
||||
const { pubKey = '', pubKeys } = useVegaWallet();
|
||||
const { data: depositsData } = useDataProvider({
|
||||
dataProvider: depositsProvider,
|
||||
variables: { partyId: pubKey || '' },
|
||||
skip: !pubKey,
|
||||
});
|
||||
const { data: collateralData } = useDataProvider({
|
||||
dataProvider: aggregatedAccountsDataProvider,
|
||||
variables: { partyId: pubKey || '' },
|
||||
skip: !pubKey,
|
||||
});
|
||||
const collaterals = Boolean(collateralData?.length);
|
||||
const deposits =
|
||||
depositsData?.some(
|
||||
(item) => item.status === Types.DepositStatus.STATUS_FINALIZED
|
||||
) || false;
|
||||
const { data: ordersData } = useDataProvider({
|
||||
dataProvider: ordersWithMarketProvider,
|
||||
variables: {
|
||||
partyId: pubKey || '',
|
||||
pagination: {
|
||||
first: 1,
|
||||
},
|
||||
},
|
||||
skip: !pubKey,
|
||||
});
|
||||
const orders = Boolean(ordersData?.length);
|
||||
|
||||
const partyIds = pubKeys?.map((item) => item.publicKey) || [];
|
||||
const { data: positionsData } = useDataProvider({
|
||||
dataProvider: positionsDataProvider,
|
||||
variables: {
|
||||
partyIds,
|
||||
},
|
||||
skip: !partyIds?.length,
|
||||
});
|
||||
const positions = Boolean(positionsData?.length);
|
||||
|
||||
const isLoading = Boolean(
|
||||
(connecting || pubKey) &&
|
||||
(depositsData === null ||
|
||||
ordersData === null ||
|
||||
collateralData === null ||
|
||||
positionsData === null)
|
||||
);
|
||||
if (isLoading) {
|
||||
return OnboardingStep.ONBOARDING_UNKNOWN_STEP;
|
||||
}
|
||||
if (!isBrowserWalletInstalled()) {
|
||||
return OnboardingStep.ONBOARDING_WALLET_STEP;
|
||||
}
|
||||
if (!pubKey) {
|
||||
return OnboardingStep.ONBOARDING_CONNECT_STEP;
|
||||
}
|
||||
if (!deposits && !collaterals) {
|
||||
return OnboardingStep.ONBOARDING_DEPOSIT_STEP;
|
||||
}
|
||||
if (!orders && !positions) {
|
||||
return OnboardingStep.ONBOARDING_ORDER_STEP;
|
||||
}
|
||||
return OnboardingStep.ONBOARDING_COMPLETE_STEP;
|
||||
};
|
||||
@@ -3,19 +3,21 @@ import { GetStarted } from './get-started';
|
||||
import { TradingButton } from '@vegaprotocol/ui-toolkit';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Links, Routes } from '../../pages/client-router';
|
||||
import { useLocalStorage } from '@vegaprotocol/react-helpers';
|
||||
import * as constants from '../constants';
|
||||
import { Networks, useEnvironment } from '@vegaprotocol/environment';
|
||||
import type { ReactNode } from 'react';
|
||||
import { useGlobalStore } from '../../stores';
|
||||
|
||||
export const WelcomeDialogContent = () => {
|
||||
const { VEGA_ENV } = useEnvironment();
|
||||
|
||||
const update = useGlobalStore((store) => store.update);
|
||||
const [, setOnboardingViewed] = useLocalStorage(
|
||||
constants.ONBOARDING_VIEWED_KEY
|
||||
);
|
||||
const navigate = useNavigate();
|
||||
const browseMarkets = () => {
|
||||
const link = Links[Routes.MARKETS]();
|
||||
navigate(link);
|
||||
update({ onBoardingDismissed: true });
|
||||
setOnboardingViewed('true');
|
||||
};
|
||||
const lead =
|
||||
VEGA_ENV === Networks.MAINNET
|
||||
@@ -55,7 +57,7 @@ export const WelcomeDialogContent = () => {
|
||||
{t('Browse the markets')}
|
||||
</TradingButton>
|
||||
</div>
|
||||
<div className="sm:w-1/2 flex grow">
|
||||
<div className="sm:w-1/2">
|
||||
<GetStarted lead={lead} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user