diff --git a/apps/explorer/src/app/routes/parties/id/Party-assets.graphql b/apps/explorer/src/app/routes/parties/id/Party-assets.graphql index 72ae0fa38..1021cfc78 100644 --- a/apps/explorer/src/app/routes/parties/id/Party-assets.graphql +++ b/apps/explorer/src/app/routes/parties/id/Party-assets.graphql @@ -48,9 +48,11 @@ query ExplorerPartyAssets($partyId: ID!) { } stakingSummary { currentStakeAvailable - linkings(pagination: { first: 100 }) { + linkings(pagination: { last: 100 }) { edges { node { + type + status amount } } diff --git a/apps/explorer/src/app/routes/parties/id/__generated__/Party-assets.ts b/apps/explorer/src/app/routes/parties/id/__generated__/Party-assets.ts index 77e334201..dfe632305 100644 --- a/apps/explorer/src/app/routes/parties/id/__generated__/Party-assets.ts +++ b/apps/explorer/src/app/routes/parties/id/__generated__/Party-assets.ts @@ -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', 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', 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 const ExplorerPartyAssetsAccountsFragmentDoc = gql` fragment ExplorerPartyAssetsAccounts on AccountBalance { @@ -64,9 +64,11 @@ export const ExplorerPartyAssetsDocument = gql` } stakingSummary { currentStakeAvailable - linkings(pagination: {first: 100}) { + linkings(pagination: {last: 100}) { edges { node { + type + status amount } } diff --git a/apps/explorer/src/app/routes/parties/id/components/party-block-stake.tsx b/apps/explorer/src/app/routes/parties/id/components/party-block-stake.tsx index 831c15ccc..6b45e73a5 100644 --- a/apps/explorer/src/app/routes/parties/id/components/party-block-stake.tsx +++ b/apps/explorer/src/app/routes/parties/id/components/party-block-stake.tsx @@ -42,9 +42,15 @@ export const PartyBlockStake = ({ linkedLength && linkedLength > 0 ? p?.stakingSummary?.linkings?.edges ?.reduce((total, e) => { - return new BigNumber(total).plus( - new BigNumber(e?.node.amount || 0) - ); + 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; + } }, new BigNumber(0)) .toString() : '0'; diff --git a/apps/governance-e2e/src/integration/flow/proposal-details.cy.ts b/apps/governance-e2e/src/integration/flow/proposal-details.cy.ts index cef462d61..13b7e19bb 100644 --- a/apps/governance-e2e/src/integration/flow/proposal-details.cy.ts +++ b/apps/governance-e2e/src/integration/flow/proposal-details.cy.ts @@ -361,6 +361,34 @@ 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('@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(); diff --git a/apps/governance-e2e/src/integration/view/home.cy.ts b/apps/governance-e2e/src/integration/view/home.cy.ts index a84b15846..dc080b0ad 100644 --- a/apps/governance-e2e/src/integration/view/home.cy.ts +++ b/apps/governance-e2e/src/integration/view/home.cy.ts @@ -119,6 +119,7 @@ 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') @@ -130,6 +131,37 @@ 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') @@ -138,6 +170,7 @@ 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') diff --git a/apps/governance-e2e/src/support/staking.functions.ts b/apps/governance-e2e/src/support/staking.functions.ts index 4f99e0964..cd198783d 100644 --- a/apps/governance-e2e/src/support/staking.functions.ts +++ b/apps/governance-e2e/src/support/staking.functions.ts @@ -183,9 +183,8 @@ export function clickOnValidatorFromList( cy.get(`[row-id="${validatorNumber}"]`) .should('be.visible') .first() - .within(() => { - cy.get(stakeValidatorListName).click(); - }); + .as('validatorOnList'); + cy.get('@validatorOnList').click(); } } diff --git a/apps/governance/src/routes/proposals/components/proposal/proposal.tsx b/apps/governance/src/routes/proposals/components/proposal/proposal.tsx index 076ac0fd5..64790df1f 100644 --- a/apps/governance/src/routes/proposals/components/proposal/proposal.tsx +++ b/apps/governance/src/routes/proposals/components/proposal/proposal.tsx @@ -55,7 +55,7 @@ export const Proposal = ({ mostRecentlyEnactedAssociatedMarketProposal, }: ProposalProps) => { const { t } = useTranslation(); - const { submit, Dialog, finalizedVote } = useVoteSubmit(); + const { submit, Dialog, finalizedVote, transaction } = useVoteSubmit(); const { voteState, voteDatetime } = useUserVote(proposal?.id, finalizedVote); if (!proposal) { @@ -215,6 +215,7 @@ export const Proposal = ({ } submit={submit} dialog={Dialog} + transaction={transaction} voteState={voteState} voteDatetime={voteDatetime} /> diff --git a/apps/governance/src/routes/proposals/components/vote-details/vega-transaction-dialog.spec.tsx b/apps/governance/src/routes/proposals/components/vote-details/vega-transaction-dialog.spec.tsx new file mode 100644 index 000000000..6ef513333 --- /dev/null +++ b/apps/governance/src/routes/proposals/components/vote-details/vega-transaction-dialog.spec.tsx @@ -0,0 +1,110 @@ +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 }) => ( +
+
{title}
+
{content?.Complete}
+
+ )); + + it('renders without crashing', () => { + render( + + ); + + expect(screen.getByTestId('vote-transaction-dialog')).toBeInTheDocument(); + }); + + it('renders with txRequested title when voteState is Requested', () => { + render( + + ); + + expect(screen.getByText('txRequested')).toBeInTheDocument(); + }); + + it('renders with votePending title when voteState is Pending', () => { + render( + + ); + + expect(screen.getByText('votePending')).toBeInTheDocument(); + }); + + it('renders with no title when voteState is neither Requested nor Pending', () => { + render( + + ); + + 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( + + ); + + 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( + + ); + + expect(screen.getByText('voteError')).toBeInTheDocument(); + }); + + it('renders default ui (i.e. not error) when not in a failed state', () => { + render( + + ); + + expect(screen.queryByText('voteError')).not.toBeInTheDocument(); + }); +}); diff --git a/apps/governance/src/routes/proposals/components/vote-details/vote-buttons.spec.tsx b/apps/governance/src/routes/proposals/components/vote-details/vote-buttons.spec.tsx index 7f1ae36b6..9eab79c44 100644 --- a/apps/governance/src/routes/proposals/components/vote-details/vote-buttons.spec.tsx +++ b/apps/governance/src/routes/proposals/components/vote-details/vote-buttons.spec.tsx @@ -1,4 +1,4 @@ -import { render, screen, fireEvent } from '@testing-library/react'; +import { fireEvent, render, screen } from '@testing-library/react'; import BigNumber from 'bignumber.js'; import { VoteButtons } from './vote-buttons'; import { VoteState } from './use-user-vote'; @@ -24,6 +24,7 @@ describe('Vote buttons', () => { currentStakeAvailable={new BigNumber(1)} dialog={() =>
Blah
} submit={() => Promise.resolve()} + transaction={null} /> @@ -47,6 +48,7 @@ describe('Vote buttons', () => { currentStakeAvailable={new BigNumber(1)} dialog={() =>
Blah
} submit={() => Promise.resolve()} + transaction={null} /> @@ -81,6 +83,7 @@ describe('Vote buttons', () => { currentStakeAvailable={new BigNumber(1)} dialog={() =>
Blah
} submit={() => Promise.resolve()} + transaction={null} /> @@ -105,6 +108,7 @@ describe('Vote buttons', () => { currentStakeAvailable={new BigNumber(0)} dialog={() =>
Blah
} submit={() => Promise.resolve()} + transaction={null} /> @@ -132,6 +136,7 @@ describe('Vote buttons', () => { currentStakeAvailable={new BigNumber(1)} dialog={() =>
Blah
} submit={() => Promise.resolve()} + transaction={null} /> @@ -159,6 +164,7 @@ describe('Vote buttons', () => { currentStakeAvailable={new BigNumber(10)} dialog={() =>
Blah
} submit={() => Promise.resolve()} + transaction={null} /> @@ -183,6 +189,7 @@ describe('Vote buttons', () => { currentStakeAvailable={new BigNumber(10)} dialog={() =>
Blah
} submit={() => Promise.resolve()} + transaction={null} /> diff --git a/apps/governance/src/routes/proposals/components/vote-details/vote-buttons.tsx b/apps/governance/src/routes/proposals/components/vote-details/vote-buttons.tsx index 919c6b423..7199c9365 100644 --- a/apps/governance/src/routes/proposals/components/vote-details/vote-buttons.tsx +++ b/apps/governance/src/routes/proposals/components/vote-details/vote-buttons.tsx @@ -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 } from '@vegaprotocol/wallet'; +import type { DialogProps, VegaTxState } from '@vegaprotocol/wallet'; interface VoteButtonsContainerProps { voteState: VoteState | null; @@ -27,6 +27,7 @@ interface VoteButtonsContainerProps { minVoterBalance: string | null | undefined; spamProtectionMinTokens: string | null | undefined; submit: (voteValue: VoteValue, proposalId: string | null) => Promise; + transaction: VegaTxState | null; dialog: (props: DialogProps) => JSX.Element; className?: string; } @@ -67,6 +68,7 @@ export const VoteButtons = ({ minVoterBalance, spamProtectionMinTokens, submit, + transaction, dialog: Dialog, }: VoteButtonsProps) => { const { t } = useTranslation(); @@ -208,7 +210,11 @@ export const VoteButtons = ({

) )} - + ); }; diff --git a/apps/governance/src/routes/proposals/components/vote-details/vote-details.tsx b/apps/governance/src/routes/proposals/components/vote-details/vote-details.tsx index db36adfce..b8fbb7c0a 100644 --- a/apps/governance/src/routes/proposals/components/vote-details/vote-details.tsx +++ b/apps/governance/src/routes/proposals/components/vote-details/vote-details.tsx @@ -12,7 +12,7 @@ import { VoteButtonsContainer } from './vote-buttons'; import { SubHeading } from '../../../../components/heading'; import { ProposalType } from '../proposal/proposal'; import type { VoteValue } from '@vegaprotocol/types'; -import type { DialogProps } from '@vegaprotocol/wallet'; +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'; @@ -22,6 +22,7 @@ interface VoteDetailsProps { minVoterBalance: string | null | undefined; spamProtectionMinTokens: string | null | undefined; proposalType: ProposalType | null; + transaction: VegaTxState | null; submit: (voteValue: VoteValue, proposalId: string | null) => Promise; dialog: (props: DialogProps) => JSX.Element; voteState: VoteState | null; @@ -34,6 +35,7 @@ export const VoteDetails = ({ spamProtectionMinTokens, proposalType, submit, + transaction, dialog, voteState, voteDatetime, @@ -228,6 +230,7 @@ export const VoteDetails = ({ spamProtectionMinTokens={spamProtectionMinTokens} className="flex" submit={submit} + transaction={transaction} dialog={dialog} /> ) diff --git a/apps/governance/src/routes/proposals/components/vote-details/vote-transaction-dialog.tsx b/apps/governance/src/routes/proposals/components/vote-details/vote-transaction-dialog.tsx index 59f04d705..c0d9b3da9 100644 --- a/apps/governance/src/routes/proposals/components/vote-details/vote-transaction-dialog.tsx +++ b/apps/governance/src/routes/proposals/components/vote-details/vote-transaction-dialog.tsx @@ -1,9 +1,10 @@ import { t } from '@vegaprotocol/i18n'; import { VoteState } from './use-user-vote'; -import type { DialogProps } from '@vegaprotocol/wallet'; +import type { DialogProps, VegaTxState } from '@vegaprotocol/wallet'; interface VoteTransactionDialogProps { voteState: VoteState; + transaction: VegaTxState | null; TransactionDialog: (props: DialogProps) => JSX.Element; } @@ -20,12 +21,15 @@ 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 ?

{t('voteError')}

: undefined; + voteState === VoteState.Failed ? ( +

{transaction?.error?.message || t('voteError')}

+ ) : undefined; return (
diff --git a/apps/trading-e2e/src/integration/closed-markets.cy.ts b/apps/trading-e2e/src/integration/closed-markets.cy.ts index d689963d8..f0861de49 100644 --- a/apps/trading-e2e/src/integration/closed-markets.cy.ts +++ b/apps/trading-e2e/src/integration/closed-markets.cy.ts @@ -259,6 +259,12 @@ describe('Closed markets', { tags: '@smoke' }, () => { .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() diff --git a/apps/trading-e2e/src/integration/market-all.cy.ts b/apps/trading-e2e/src/integration/market-all.cy.ts index 83183f3bc..f6c2c5f91 100644 --- a/apps/trading-e2e/src/integration/market-all.cy.ts +++ b/apps/trading-e2e/src/integration/market-all.cy.ts @@ -69,6 +69,12 @@ 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() diff --git a/apps/trading-e2e/src/integration/markets-proposed.cy.ts b/apps/trading-e2e/src/integration/markets-proposed.cy.ts index 5c8057477..7b8acd537 100644 --- a/apps/trading-e2e/src/integration/markets-proposed.cy.ts +++ b/apps/trading-e2e/src/integration/markets-proposed.cy.ts @@ -45,6 +45,12 @@ describe('markets proposed table', { tags: '@smoke' }, () => { .find('[col-id="description"]') .should('have.text', 'ETHUSD'); + // 6001-MARK-074 + cy.get(rowSelector) + .first() + .find('[title="Future"]') + .should('have.text', 'Futr'); + // 6001-MARK-051 cy.get(rowSelector) .first() diff --git a/apps/trading-e2e/src/integration/settings.cy.ts b/apps/trading-e2e/src/integration/settings.cy.ts deleted file mode 100644 index a09223e5e..000000000 --- a/apps/trading-e2e/src/integration/settings.cy.ts +++ /dev/null @@ -1,30 +0,0 @@ -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'); - }); -}); diff --git a/apps/trading-e2e/src/integration/trading-chart.cy.ts b/apps/trading-e2e/src/integration/trading-chart.cy.ts deleted file mode 100644 index 152ba334d..000000000 --- a/apps/trading-e2e/src/integration/trading-chart.cy.ts +++ /dev/null @@ -1,186 +0,0 @@ -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); - }); - }); - } -); diff --git a/apps/trading-e2e/src/integration/trading-deal-ticket-basics.cy.ts b/apps/trading-e2e/src/integration/trading-deal-ticket-basics.cy.ts index 57254632d..0b2d1036a 100644 --- a/apps/trading-e2e/src/integration/trading-deal-ticket-basics.cy.ts +++ b/apps/trading-e2e/src/integration/trading-deal-ticket-basics.cy.ts @@ -54,6 +54,15 @@ 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( diff --git a/apps/trading-e2e/src/integration/trading-orders.cy.ts b/apps/trading-e2e/src/integration/trading-orders.cy.ts index 31ceb2818..c595f5aab 100644 --- a/apps/trading-e2e/src/integration/trading-orders.cy.ts +++ b/apps/trading-e2e/src/integration/trading-orders.cy.ts @@ -222,12 +222,17 @@ 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', () => { diff --git a/apps/trading/client-pages/market/trade-grid.tsx b/apps/trading/client-pages/market/trade-grid.tsx index b316a3f54..ab64f77b1 100644 --- a/apps/trading/client-pages/market/trade-grid.tsx +++ b/apps/trading/client-pages/market/trade-grid.tsx @@ -94,7 +94,11 @@ const MainGrid = memo( > - + } + > ( diff --git a/apps/trading/components/market-selector/market-selector.tsx b/apps/trading/components/market-selector/market-selector.tsx index d182a814f..59ec08fc5 100644 --- a/apps/trading/components/market-selector/market-selector.tsx +++ b/apps/trading/components/market-selector/market-selector.tsx @@ -2,7 +2,7 @@ import { t } from '@vegaprotocol/i18n'; import uniqBy from 'lodash/uniqBy'; import type { MarketMaybeWithDataAndCandles } from '@vegaprotocol/markets'; import { - Input, + TradingInput, TinyScroll, VegaIcon, VegaIconNames, @@ -57,7 +57,7 @@ export const MarketSelector = ({ />
- setFilter((curr) => ({ ...curr, searchTerm: e.target.value })) } diff --git a/apps/trading/components/positions-container/positions-container.tsx b/apps/trading/components/positions-container/positions-container.tsx index 518f7c2d6..f830d4666 100644 --- a/apps/trading/components/positions-container/positions-container.tsx +++ b/apps/trading/components/positions-container/positions-container.tsx @@ -5,6 +5,7 @@ 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'; @@ -13,6 +14,7 @@ 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); @@ -40,12 +42,35 @@ export const PositionsContainer = ({ allKeys }: { allKeys?: boolean }) => { onMarketClick={onMarketClick} isReadOnly={isReadOnly} gridProps={gridStoreCallbacks} + showClosed={showClosed} /> ); }; -const usePositionsStore = create()( - persist(createDataGridSlice, { - name: 'vega_positions_store', - }) +type PositionsStoreSlice = { + showClosedMarkets: boolean; + toggleClosedMarkets: () => void; +}; + +const createPositionStoreSlice: StateCreator = (set) => ({ + showClosedMarkets: false, + toggleClosedMarkets: () => { + set((curr) => { + return { + showClosedMarkets: !curr.showClosedMarkets, + }; + }); + }, +}); + +export const usePositionsStore = create()( + persist( + (...args) => ({ + ...createPositionStoreSlice(...args), + ...createDataGridSlice(...args), + }), + { + name: 'vega_positions_store', + } + ) ); diff --git a/apps/trading/components/positions-menu/index.ts b/apps/trading/components/positions-menu/index.ts new file mode 100644 index 000000000..12fc9ea53 --- /dev/null +++ b/apps/trading/components/positions-menu/index.ts @@ -0,0 +1 @@ +export * from './positions-menu'; diff --git a/apps/trading/components/positions-menu/positions-menu.tsx b/apps/trading/components/positions-menu/positions-menu.tsx new file mode 100644 index 000000000..58dddee7b --- /dev/null +++ b/apps/trading/components/positions-menu/positions-menu.tsx @@ -0,0 +1,18 @@ +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 ( + + {showClosed ? t('Hide closed markets') : t('Show closed markets')} + + ); +}; diff --git a/apps/trading/components/sidebar/sidebar.tsx b/apps/trading/components/sidebar/sidebar.tsx index 2dcf8d4a8..d32d0d8d0 100644 --- a/apps/trading/components/sidebar/sidebar.tsx +++ b/apps/trading/components/sidebar/sidebar.tsx @@ -14,12 +14,9 @@ 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', @@ -302,22 +299,14 @@ export const useSidebar = create<{ init: boolean; view: SidebarView | null; setView: (view: SidebarView | null) => void; -}>()( - persist( - (set) => ({ - init: true, - view: null, - setView: (x) => - set(() => { - if (x == null) { - return { view: null, init: false }; - } - - return { view: x, init: false }; - }), +}>()((set) => ({ + init: true, + view: null, + setView: (x) => + set(() => { + if (x == null) { + return { view: null, init: false }; + } + return { view: x, init: false }; }), - { - name: STORAGE_KEY, - } - ) -); +})); diff --git a/apps/trading/components/welcome-dialog/telemetry-approval.tsx b/apps/trading/components/welcome-dialog/telemetry-approval.tsx index c27506dfa..0fd49c983 100644 --- a/apps/trading/components/welcome-dialog/telemetry-approval.tsx +++ b/apps/trading/components/welcome-dialog/telemetry-approval.tsx @@ -1,4 +1,4 @@ -import { Checkbox } from '@vegaprotocol/ui-toolkit'; +import { TradingCheckbox } 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 (
- {t('Share usage data')}} checked={isApproved} name="telemetry-approval" diff --git a/apps/trading/pages/_document.page.tsx b/apps/trading/pages/_document.page.tsx index 9a2552e07..53c42fb1a 100644 --- a/apps/trading/pages/_document.page.tsx +++ b/apps/trading/pages/_document.page.tsx @@ -1,40 +1,10 @@ -import { Html, Head, Main, NextScript } from 'next/document'; +import { Head, Html, Main, NextScript } from 'next/document'; export default function Document() { return ( - + <> - - - - - - - - - - - - - - - - - - - - - {/* eslint-disable-next-line @next/next/no-css-tags */} -